From 833cf7b6d142e0bb3def7cb3bf3dcd6a3726a440 Mon Sep 17 00:00:00 2001 From: xinyangli Date: Thu, 7 Mar 2024 13:19:12 +0800 Subject: [PATCH 1/5] pa2.1: add M extension support, finish pa2.1 --- flake.nix | 18 ++++++++++++---- nemu/src/isa/riscv32/inst.c | 42 +++++++++++++++++++++++-------------- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/flake.nix b/flake.nix index 35d3b94..6656094 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ }; in { - packages.nemu = pkgs.callPackage ./nemu {}; + packages.nemu = pkgs.callPackage ./nemu { am-kernels = self.packages.${system}.am-kernels; }; packages.am-kernels = crossPkgs.stdenv.mkDerivation rec { pname = "am-kernels"; @@ -44,12 +44,13 @@ ''; buildPhase = '' - AS=$CC make -C tests/cpu-tests BUILD_DIR=$(pwd)/build ARCH=$ARCH --trace + AS=$CC make -C tests/cpu-tests BUILD_DIR=$(pwd)/build ARCH=$ARCH ''; installPhase = '' - mkdir -p $out/bin - cp build/riscv32-nemu/*.bin $out/bin + mkdir -p $out/share/images $out/share/dump + cp build/riscv32-nemu/*.bin $out/share/images + cp build/riscv32-nemu/*.txt $out/share/dump ''; dontFixup = true; @@ -60,6 +61,15 @@ gdb ] ++ builtins.attrValues self.packages.${system}; }; + + devShells.nemu = pkgs.mkShell { + packages = with pkgs; [ + clang-tools + ]; + inputsFrom = [ + self.packages.${system}.nemu + ]; + }; } ); } diff --git a/nemu/src/isa/riscv32/inst.c b/nemu/src/isa/riscv32/inst.c index 2a53ba5..9c86937 100644 --- a/nemu/src/isa/riscv32/inst.c +++ b/nemu/src/isa/riscv32/inst.c @@ -1,17 +1,17 @@ /*************************************************************************************** -* Copyright (c) 2014-2022 Zihao Yu, Nanjing University -* -* NEMU is licensed under Mulan PSL v2. -* You can use this software according to the terms and conditions of the Mulan PSL v2. -* You may obtain a copy of Mulan PSL v2 at: -* http://license.coscl.org.cn/MulanPSL2 -* -* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -* -* See the Mulan PSL v2 for more details. -***************************************************************************************/ + * Copyright (c) 2014-2022 Zihao Yu, Nanjing University + * + * NEMU is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan + *PSL v2. You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY + *KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + *NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * + * See the Mulan PSL v2 for more details. + ***************************************************************************************/ #include "common.h" #include "local-include/reg.h" @@ -36,7 +36,8 @@ enum { #define immB() do { *imm = SEXT(BITS(i, 31, 31), 1) << 12 | BITS(i, 30, 25) << 5 | BITS(i, 11, 8) << 1 | BITS(i, 7, 7) << 11; } while(0) #define immJ() do { *imm = SEXT(BITS(i, 31, 31), 1) << 20 | BITS(i, 30, 21) << 1 | BITS(i, 20, 20) << 11 | BITS(i, 19, 12) << 12; } while(0) -static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2, word_t *imm, int type) { +static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2, + word_t *imm, int type) { uint32_t i = s->isa.inst.val; int rs1 = BITS(i, 19, 15); int rs2 = BITS(i, 24, 20); @@ -100,8 +101,6 @@ static int decode_exec(Decode *s) { INSTPAT("0000000 ????? ????? 001 ????? 00100 11", slli , I, R(rd) = src1 << imm); INSTPAT("0000000 ????? ????? 101 ????? 00100 11", srli , I, R(rd) = src1 >> imm); INSTPAT("0100000 ????? ????? 101 ????? 00100 11", srai , I, R(rd) = (sword_t)src1 >> (imm & 0x01F)); - - INSTPAT("0000000 ????? ????? 000 ????? 01100 11", add , R, R(rd) = src1 + src2); INSTPAT("0100000 ????? ????? 000 ????? 01100 11", sub , R, R(rd) = src1 - src2); INSTPAT("0000000 ????? ????? 001 ????? 01100 11", sll , R, R(rd) = src1 << src2); @@ -114,6 +113,17 @@ static int decode_exec(Decode *s) { INSTPAT("0000000 ????? ????? 111 ????? 01100 11", and , R, R(rd) = src1 & src2); INSTPAT("0000000 00001 00000 000 00000 11100 11", ebreak , N, NEMUTRAP(s->pc, R(10))); // R(10) is $a0 + + // "M" + INSTPAT("0000001 ????? ????? 000 ????? 01100 11", mul , R, R(rd) = src1 * src2); + INSTPAT("0000001 ????? ????? 001 ????? 01100 11", mulh , R, R(rd) = (int64_t)(sword_t)src1 * (sword_t)src2 >> 32); + INSTPAT("0000001 ????? ????? 010 ????? 01100 11", mulhsu , R, R(rd) = (int64_t)(sword_t)src1 * (uint64_t)src2 >> 32); + INSTPAT("0000001 ????? ????? 011 ????? 01100 11", mulhu , R, R(rd) = (uint64_t)src1 * (uint64_t)src2 >> 32); + INSTPAT("0000001 ????? ????? 100 ????? 01100 11", div , R, R(rd) = (sword_t)src1 / (sword_t)src2); + INSTPAT("0000001 ????? ????? 101 ????? 01100 11", divu , R, R(rd) = src1 / src2); + INSTPAT("0000001 ????? ????? 110 ????? 01100 11", rem , R, R(rd) = (sword_t)src1 % (sword_t)src2); + INSTPAT("0000001 ????? ????? 111 ????? 01100 11", remu , R, R(rd) = src1 % src2); + INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv , N, INV(s->pc)); INSTPAT_END(); From 64f891308eca0372362d6ea1e197cc554a2a9aec Mon Sep 17 00:00:00 2001 From: tracer-ysyx Date: Thu, 7 Mar 2024 18:16:48 +0800 Subject: [PATCH 2/5] =?UTF-8?q?>=20configure(npc)=20=20ysyx=5F22040000=20?= =?UTF-8?q?=E6=9D=8E=E5=BF=83=E6=9D=A8=20=20Linux=20calcite=206.6.19=20#1-?= =?UTF-8?q?NixOS=20SMP=20PREEMPT=5FDYNAMIC=20Fri=20Mar=20=201=2012:35:11?= =?UTF-8?q?=20UTC=202024=20x86=5F64=20GNU/Linux=20=20=2018:16:48=20=20up?= =?UTF-8?q?=20=20=203:36,=20=202=20users,=20=20load=20average:=200.28,=200?= =?UTF-8?q?.25,=200.34?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- npc/core/src/main/scala/Main.scala | 13 ++++++++++++- npc/core/src/main/scala/ProgramCounter.scala | 11 +++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 npc/core/src/main/scala/ProgramCounter.scala diff --git a/npc/core/src/main/scala/Main.scala b/npc/core/src/main/scala/Main.scala index c06bc8e..95b9e61 100644 --- a/npc/core/src/main/scala/Main.scala +++ b/npc/core/src/main/scala/Main.scala @@ -2,8 +2,10 @@ package npc import chisel3._ import chisel3.util.{MuxLookup, Fill, Decoupled, Counter, Queue, Reverse} +import chisel3.util.{SRAM} import chisel3.stage.ChiselOption -import npc.util.KeyboardSegController +import npc.util.{ KeyboardSegController, RegisterFile } +import flowpc.components.ProgramCounter class Switch extends Module { val io = IO(new Bundle { @@ -31,3 +33,12 @@ class Keyboard extends Module { io.segs := seg_handler.io.segs } +<<<<<<< Updated upstream +======= +class Flowpc extends Module { + val io = IO(new Bundle { }) + val register_file = new RegisterFile(readPorts = 2); + val pc = new ProgramCounter(32); + val adder = new SRAM() +} +>>>>>>> Stashed changes diff --git a/npc/core/src/main/scala/ProgramCounter.scala b/npc/core/src/main/scala/ProgramCounter.scala new file mode 100644 index 0000000..0687f9a --- /dev/null +++ b/npc/core/src/main/scala/ProgramCounter.scala @@ -0,0 +1,11 @@ +package flowpc.components +import chisel3._ +import chisel3.util.{Valid} + +class ProgramCounter (width: Int) extends Module { + val io = new Bundle { + val next_pc = Input(Flipped(Valid(UInt(width.W)))) + val pc = Output(UInt(width.W)) + } + io.pc := Mux(io.next_pc.valid, io.next_pc.bits, io.pc) +} From d67fb1138a03905020b5651ba7d7fb5c11524ef7 Mon Sep 17 00:00:00 2001 From: xinyangli Date: Mon, 11 Mar 2024 21:41:45 +0800 Subject: [PATCH 3/5] npc: Register File --- npc/core/build.sbt | 5 +- npc/core/src/main/scala/RegisterFile.scala | 80 +++++++++++++++++----- npc/core/src/test/scala/RegisterFile.scala | 63 +++++++++++++++++ 3 files changed, 130 insertions(+), 18 deletions(-) create mode 100644 npc/core/src/test/scala/RegisterFile.scala diff --git a/npc/core/build.sbt b/npc/core/build.sbt index 792a764..16f31f3 100644 --- a/npc/core/build.sbt +++ b/npc/core/build.sbt @@ -6,10 +6,11 @@ val chiselVersion = "5.1.0" lazy val root = (project in file(".")) .settings( - name := "ChiselLearning", + name := "flow", libraryDependencies ++= Seq( "org.chipsalliance" %% "chisel" % chiselVersion, - "edu.berkeley.cs" %% "chiseltest" % "5.0.2" % "test" + "edu.berkeley.cs" %% "chiseltest" % "5.0.2" % "test", + "com.chuusai" %% "shapeless" % "2.3.3" ), scalacOptions ++= Seq( "-language:reflectiveCalls", diff --git a/npc/core/src/main/scala/RegisterFile.scala b/npc/core/src/main/scala/RegisterFile.scala index fbf8a94..a6c5a62 100644 --- a/npc/core/src/main/scala/RegisterFile.scala +++ b/npc/core/src/main/scala/RegisterFile.scala @@ -1,25 +1,73 @@ -package npc.util +package flowpc.components import chisel3._ +import chisel3.util.log2Ceil +import chisel3.util.UIntToOH +import chisel3.util.MuxLookup -class RegisterFile(readPorts: Int) extends Module { - require(readPorts >= 0) - val io = IO(new Bundle { - val writeEnable = Input(Bool()) - val writeAddr = Input(UInt(5.W)) - val writeData = Input(UInt(32.W)) - val readAddr = Input(Vec(readPorts, UInt(5.W))) - val readData = Output(Vec(readPorts, UInt(32.W))) - }) +class RegControl extends Bundle { + val writeEnable = Input(Bool()) - val regFile = RegInit(VecInit(Seq.fill(32)(0.U(32.W)))) - for (i <- 1 until 32) { - regFile(i) := regFile(i) + object WriteSelect extends ChiselEnum { + val rAluOut, rMemOut = Value + } + val writeSelect = Input(WriteSelect()) +} + +class RegFileData[T <: Data](size:Int, tpe: T, numReadPorts: Int, numWritePorts: Int) extends Bundle { + val write = new Bundle { + val addr = Input(UInt(size.W)) + val data = Vec(numWritePorts, Input(tpe)) + } + val read = Vec(numReadPorts, new Bundle { + val rs = Input(UInt(size.W)) + val src = Output(tpe) + }) +} + +class RegFileInterface[T <: Data](size: Int, tpe: T, numReadPorts: Int, numWritePorts: Int) extends Bundle { + val control = new RegControl + val data = new RegFileData(size, tpe, numReadPorts, numWritePorts) +} + +class RegisterFileCore[T <: Data](size: Int, tpe: T, numReadPorts: Int) extends Module { + require(numReadPorts >= 0) + val writePort = IO(new Bundle { + val enable = Input(Bool()) + val addr = Input(UInt(log2Ceil(size).W)) + val data = Input(tpe) + }) + val readPorts = IO(Vec(numReadPorts, new Bundle { + val addr = Input(UInt(log2Ceil(size).W)) + val data = Output(tpe) + })) + + val regFile = RegInit(VecInit(Seq.fill(size)(0.U(tpe.getWidth.W)))) + val writeAddrOH = UIntToOH(writePort.addr) + for ((reg, i) <- regFile.zipWithIndex.tail) { + reg := Mux(writeAddrOH(i) && writePort.enable, writePort.data, reg) } - regFile(io.writeAddr) := Mux(io.writeEnable, io.writeData, regFile(io.writeAddr)) regFile(0) := 0.U - for (i <- 0 until readPorts) { - io.readData(i) := regFile(io.readAddr(i)) + for (readPort <- readPorts) { + readPort.data := regFile(readPort.addr) + } +} + +object RegisterFile { + def apply[T <: Data](size: Int, tpe: T, numReadPorts: Int, numWritePorts: Int): RegFileInterface[T] = { + val core = Module(new RegisterFileCore(size, tpe, numReadPorts)) + val _out = Wire(new RegFileInterface(size, tpe, numReadPorts, numWritePorts)) + val clock = core.clock + for (i <- 0 until numReadPorts) { + core.readPorts(i).addr := _out.data.read(i).rs + _out.data.read(i).src := core.readPorts(i).data + } + core.writePort.addr := _out.data.write.addr + core.writePort.data := MuxLookup(_out.control.writeSelect, 0.U)( + _out.control.WriteSelect.all.map(x => (x -> _out.data.write.data(x.asUInt).asUInt)) + ) + core.writePort.enable := _out.control.writeEnable + _out } } diff --git a/npc/core/src/test/scala/RegisterFile.scala b/npc/core/src/test/scala/RegisterFile.scala new file mode 100644 index 0000000..87be171 --- /dev/null +++ b/npc/core/src/test/scala/RegisterFile.scala @@ -0,0 +1,63 @@ +package flowpc + +import chisel3._ +import chiseltest._ +import org.scalatest.freespec.AnyFreeSpec +import chiseltest.simulator.WriteVcdAnnotation + +import flowpc.components._ +class RegisterFileSpec extends AnyFreeSpec with ChiselScalatestTester { + "RegisterFileCore" - { + "register 0 is always 0" in { + test(new RegisterFileCore(32, UInt(32.W), 2)) { c => + c.readPorts(0).addr.poke(0) + c.readPorts(1).addr.poke(0) + c.writePort.enable.poke(true) + c.writePort.addr.poke(0) + c.writePort.data.poke(0x1234) + + c.readPorts(0).data.expect(0) + c.readPorts(1).data.expect(0) + c.clock.step(2) + c.readPorts(0).data.expect(0) + c.readPorts(1).data.expect(0) + } + } + "register other than 0 can be written" in { + test(new RegisterFileCore(32, UInt(32.W), 2)) { c => + import scala.util.Random + val r = new Random() + for (i <- 1 until 32) { + val v = r.nextLong() & 0xFFFFFFFFL + c.readPorts(0).addr.poke(i) + c.writePort.enable.poke(true) + c.writePort.addr.poke(i) + c.writePort.data.poke(v) + + c.clock.step(1) + c.readPorts(0).data.expect(v) + } + } + } + } + "RegisterInterface" - { + "worked" in { + class Top extends Module { + val io = IO(new RegFileInterface(32, UInt(32.W), 2, 2)) + val rf = RegisterFile(32, UInt(32.W), 2, 2) + io :<>= rf + } + test(new Top).withAnnotations(Seq(WriteVcdAnnotation)) { c => + import c.io.control.WriteSelect._ + val writePort = rAluOut.litValue.toInt + c.io.control.writeEnable.poke(true) + c.io.control.writeSelect.poke(rAluOut) + c.io.data.write.addr.poke(5) + c.io.data.write.data(writePort).poke(0xcdef) + c.io.data.read(0).rs.poke(5) + c.clock.step(1) + c.io.data.read(0).src.expect(0xcdef) + } + } + } +} From c917083554d4aa61c5778658df351537712e3100 Mon Sep 17 00:00:00 2001 From: xinyangli Date: Wed, 13 Mar 2024 16:54:00 +0800 Subject: [PATCH 4/5] pa2.2: add ITRACE buffer --- nemu/Kconfig | 4 ++++ nemu/include/cpu/decode.h | 1 - nemu/include/debug.h | 1 + nemu/include/utils.h | 3 +++ nemu/src/cpu/cpu-exec.c | 23 +++++++++++++++-------- nemu/src/isa/riscv32/inst.c | 2 +- nemu/src/utils/log.c | 15 +++++++++++++++ 7 files changed, 39 insertions(+), 10 deletions(-) diff --git a/nemu/Kconfig b/nemu/Kconfig index a1ed68e..20f7705 100644 --- a/nemu/Kconfig +++ b/nemu/Kconfig @@ -151,6 +151,10 @@ config ITRACE_COND string "Only trace instructions when the condition is true" default "true" +config ITRACE_BUFFER + depends on ITRACE + int "Buffer size for intruction trace (unit: number of instructions)" + default 10 config DIFFTEST depends on TARGET_NATIVE_ELF diff --git a/nemu/include/cpu/decode.h b/nemu/include/cpu/decode.h index 915bcf2..a17c888 100644 --- a/nemu/include/cpu/decode.h +++ b/nemu/include/cpu/decode.h @@ -23,7 +23,6 @@ typedef struct Decode { vaddr_t snpc; // static next pc vaddr_t dnpc; // dynamic next pc ISADecodeInfo isa; - IFDEF(CONFIG_ITRACE, char logbuf[128]); } Decode; // --- pattern matching mechanism --- diff --git a/nemu/include/debug.h b/nemu/include/debug.h index 087da4d..df88556 100644 --- a/nemu/include/debug.h +++ b/nemu/include/debug.h @@ -38,6 +38,7 @@ MUXDEF(CONFIG_TARGET_AM, printf(ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__), \ (fflush(stdout), fprintf(stderr, ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__))); \ IFNDEF(CONFIG_TARGET_AM, extern FILE* log_fp; fflush(log_fp)); \ + IFDEF(CONFIG_ITRACE, log_itrace_print()); \ extern void assert_fail_msg(); \ assert_fail_msg(); \ assert(cond); \ diff --git a/nemu/include/utils.h b/nemu/include/utils.h index 2cd1561..59bc9df 100644 --- a/nemu/include/utils.h +++ b/nemu/include/utils.h @@ -74,4 +74,7 @@ uint64_t get_time(); } while (0) +IFDEF(CONFIG_ITRACE, void log_itrace_print()); + + #endif diff --git a/nemu/src/cpu/cpu-exec.c b/nemu/src/cpu/cpu-exec.c index 1f2940f..72e1265 100644 --- a/nemu/src/cpu/cpu-exec.c +++ b/nemu/src/cpu/cpu-exec.c @@ -13,6 +13,7 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ +#include "utils.h" #include #include #include @@ -29,15 +30,17 @@ CPU_state cpu = {}; uint64_t g_nr_guest_inst = 0; static uint64_t g_timer = 0; // unit: us static bool g_print_step = false; +IFDEF(CONFIG_ITRACE, extern char logbuf[CONFIG_ITRACE_BUFFER][128]); +IFDEF(CONFIG_ITRACE, extern int logbuf_rear); void device_update(); bool wp_eval_all(); static void trace_and_difftest(Decode *_this, vaddr_t dnpc) { #ifdef CONFIG_ITRACE_COND - if (ITRACE_COND) { log_write("%s\n", _this->logbuf); } + if (ITRACE_COND) { log_write("%s\n", logbuf[logbuf_rear]); } #endif - if (g_print_step) { IFDEF(CONFIG_ITRACE, puts(_this->logbuf)); } + if (g_print_step) { IFDEF(CONFIG_ITRACE, puts(logbuf[logbuf_rear])); } IFDEF(CONFIG_DIFFTEST, difftest_step(_this->pc, dnpc)); } @@ -47,8 +50,9 @@ static void exec_once(Decode *s, vaddr_t pc) { isa_exec_once(s); cpu.pc = s->dnpc; #ifdef CONFIG_ITRACE - char *p = s->logbuf; - p += snprintf(p, sizeof(s->logbuf), FMT_WORD ":", s->pc); + logbuf_rear = (logbuf_rear + 1) % CONFIG_ITRACE_BUFFER; + char *p = logbuf[logbuf_rear]; + p += snprintf(p, sizeof(logbuf), FMT_WORD ":", s->pc); int ilen = s->snpc - s->pc; int i; uint8_t *inst = (uint8_t *)&s->isa.inst.val; @@ -64,7 +68,7 @@ static void exec_once(Decode *s, vaddr_t pc) { #ifndef CONFIG_ISA_loongarch32r void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte); - disassemble(p, s->logbuf + sizeof(s->logbuf) - p, + disassemble(p, logbuf[logbuf_rear] + sizeof(logbuf[logbuf_rear]) - p, MUXDEF(CONFIG_ISA_x86, s->snpc, s->pc), (uint8_t *)&s->isa.inst.val, ilen); #else p[0] = '\0'; // the upstream llvm does not support loongarch32r @@ -79,7 +83,7 @@ static void execute(uint64_t n) { g_nr_guest_inst ++; trace_and_difftest(&s, cpu.pc); if (wp_eval_all()) { - puts(s.logbuf); + puts(logbuf[logbuf_rear]); break; } if (nemu_state.state != NEMU_RUNNING) break; @@ -121,13 +125,16 @@ void cpu_exec(uint64_t n) { switch (nemu_state.state) { case NEMU_RUNNING: nemu_state.state = NEMU_STOP; break; - case NEMU_END: case NEMU_ABORT: + case NEMU_END: case NEMU_ABORT: { Log("nemu: %s at pc = " FMT_WORD, (nemu_state.state == NEMU_ABORT ? ANSI_FMT("ABORT", ANSI_FG_RED) : (nemu_state.halt_ret == 0 ? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN) : ANSI_FMT("HIT BAD TRAP", ANSI_FG_RED))), nemu_state.halt_pc); - // fall through + if(nemu_state.halt_ret != 0) { + log_itrace_print(); + } + } // fall through case NEMU_QUIT: statistic(); } } diff --git a/nemu/src/isa/riscv32/inst.c b/nemu/src/isa/riscv32/inst.c index 9c86937..b7aeac5 100644 --- a/nemu/src/isa/riscv32/inst.c +++ b/nemu/src/isa/riscv32/inst.c @@ -54,7 +54,7 @@ static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2, static void do_branch(Decode *s, bool condition, word_t offset) { if (condition) { - puts(s->logbuf); + // puts(s->logbuf[s->logbuf_rear]); s->dnpc = s->pc + offset; } } diff --git a/nemu/src/utils/log.c b/nemu/src/utils/log.c index a9bb9a7..7939d42 100644 --- a/nemu/src/utils/log.c +++ b/nemu/src/utils/log.c @@ -35,3 +35,18 @@ bool log_enable() { (g_nr_guest_inst <= CONFIG_TRACE_END), false); } #endif + +IFDEF(CONFIG_ITRACE, char logbuf[CONFIG_ITRACE_BUFFER][128]); +IFDEF(CONFIG_ITRACE, int logbuf_rear); + +#ifdef CONFIG_ITRACE +void log_itrace_print() { + puts("ITRACE buffer:"); + for (int i = (logbuf_rear + 1) % CONFIG_ITRACE_BUFFER; i != logbuf_rear; i = (i + 1) % CONFIG_ITRACE_BUFFER) { + if (logbuf[i][0] == '\0') continue; + puts(logbuf[i]); + } + puts("Current command:"); + puts(logbuf[logbuf_rear]); +} +#endif From 0f7c6fd508ac81de10b99b276d23371c72903008 Mon Sep 17 00:00:00 2001 From: xinyangli Date: Wed, 13 Mar 2024 18:14:17 +0800 Subject: [PATCH 5/5] pa2.2: add memory tracer --- nemu/Kconfig | 18 ++++++++++++++++ nemu/include/debug.h | 3 +++ nemu/src/memory/paddr.c | 48 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/nemu/Kconfig b/nemu/Kconfig index 20f7705..9243aba 100644 --- a/nemu/Kconfig +++ b/nemu/Kconfig @@ -156,6 +156,24 @@ config ITRACE_BUFFER int "Buffer size for intruction trace (unit: number of instructions)" default 10 +config MTRACE + depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER + bool "Enable memory tracer" + + +config MTRACE_RANGE + depends on MTRACE + string "Memory trace active range" + default "0x0-0xfffffff" + help + Memory tracer will only print memory access in these ranges. + Use comma to seperate between ranges. + +config MTRACE_RANGE_MAX + depends on MTRACE + int "Max range count in MTRACE_RANGE" + default 10 + config DIFFTEST depends on TARGET_NATIVE_ELF bool "Enable differential testing" diff --git a/nemu/include/debug.h b/nemu/include/debug.h index df88556..057f8bf 100644 --- a/nemu/include/debug.h +++ b/nemu/include/debug.h @@ -20,6 +20,9 @@ #include #include +#define Trace(format, ...) \ + _Log("[TRACE] " format "\n", ## __VA_ARGS__) + #define Log(format, ...) \ _Log(ANSI_FMT("[INFO] %s:%d %s() ", ANSI_FG_BLUE) format "\n", \ __FILE__, __LINE__, __func__, ## __VA_ARGS__) diff --git a/nemu/src/memory/paddr.c b/nemu/src/memory/paddr.c index ee30e70..437debd 100644 --- a/nemu/src/memory/paddr.c +++ b/nemu/src/memory/paddr.c @@ -13,6 +13,8 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ +#include "common.h" +#include "debug.h" #include #include #include @@ -23,6 +25,11 @@ static uint8_t *pmem = NULL; #else // CONFIG_PMEM_GARRAY static uint8_t pmem[CONFIG_MSIZE] PG_ALIGN = {}; #endif +#ifdef CONFIG_MTRACE +static word_t mtrace_start[CONFIG_MTRACE_RANGE_MAX] = {0}; +static word_t mtrace_end[CONFIG_MTRACE_RANGE_MAX] = {0}; +static int range_count = 0; +#endif uint8_t* guest_to_host(paddr_t paddr) { return pmem + paddr - CONFIG_MBASE; } paddr_t host_to_guest(uint8_t *haddr) { return haddr - pmem + CONFIG_MBASE; } @@ -41,23 +48,58 @@ static void out_of_bound(paddr_t addr) { addr, PMEM_LEFT, PMEM_RIGHT, cpu.pc); } +#ifdef CONFIG_MTRACE +static void mtrace_print(char type, word_t addr, int len, word_t data) { + for (int i = 0; i < range_count; i++) + if (addr <= mtrace_end[i] && addr >= mtrace_start[i] ) { + Trace("Mem %c " FMT_PADDR "%d D " FMT_PADDR, type, addr, len, data); + break; + } +} +#endif + void init_mem() { #if defined(CONFIG_PMEM_MALLOC) pmem = malloc(CONFIG_MSIZE); assert(pmem); +#endif +#ifdef CONFIG_MTRACE + char range[sizeof(CONFIG_MTRACE_RANGE)] = CONFIG_MTRACE_RANGE; + char *saveptr, *ptr; + ptr = strtok_r(range, ",", &saveptr); + for (range_count = 0; range_count < CONFIG_MTRACE_RANGE_MAX; ) { + word_t start, end; + Assert(sscanf(ptr, FMT_PADDR "-" FMT_PADDR, &start, &end) == 2, "Config option MTRACE_RANGE has wrong format"); + mtrace_start[range_count] = start; + mtrace_end[range_count] = end; + + range_count++; + ptr = strtok_r(NULL, ",", &saveptr); + if (!ptr) break; + } + Trace("MTRACE ranges: "); + for (int i = 0; i < range_count; i++) { + Trace("[0x%x, 0x%x]", mtrace_start[i], mtrace_end[i]); + } #endif IFDEF(CONFIG_MEM_RANDOM, memset(pmem, rand(), CONFIG_MSIZE)); Log("physical memory area [" FMT_PADDR ", " FMT_PADDR "]", PMEM_LEFT, PMEM_RIGHT); } word_t paddr_read(paddr_t addr, int len) { - if (likely(in_pmem(addr))) return pmem_read(addr, len); - IFDEF(CONFIG_DEVICE, return mmio_read(addr, len)); + word_t result = 0; + if (likely(in_pmem(addr))) { result = pmem_read(addr, len); goto mtrace;} + IFDEF(CONFIG_DEVICE, result = mmio_read(addr, len); goto mtrace) out_of_bound(addr); - return 0; + +mtrace: + IFDEF(CONFIG_MTRACE, mtrace_print('R', addr, len, result)); + + return result; } void paddr_write(paddr_t addr, int len, word_t data) { + IFDEF(CONFIG_MTRACE, mtrace_print('W', addr, len, data)); if (likely(in_pmem(addr))) { pmem_write(addr, len, data); return; } IFDEF(CONFIG_DEVICE, mmio_write(addr, len, data); return); out_of_bound(addr);