Compare commits
5 commits
e764133868
...
0f7c6fd508
Author | SHA1 | Date | |
---|---|---|---|
0f7c6fd508 | |||
c917083554 | |||
d67fb1138a | |||
|
64f891308e | ||
833cf7b6d1 |
14 changed files with 298 additions and 52 deletions
18
flake.nix
18
flake.nix
|
@ -17,7 +17,7 @@
|
||||||
};
|
};
|
||||||
in
|
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 {
|
packages.am-kernels = crossPkgs.stdenv.mkDerivation rec {
|
||||||
pname = "am-kernels";
|
pname = "am-kernels";
|
||||||
|
@ -44,12 +44,13 @@
|
||||||
'';
|
'';
|
||||||
|
|
||||||
buildPhase = ''
|
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 = ''
|
installPhase = ''
|
||||||
mkdir -p $out/bin
|
mkdir -p $out/share/images $out/share/dump
|
||||||
cp build/riscv32-nemu/*.bin $out/bin
|
cp build/riscv32-nemu/*.bin $out/share/images
|
||||||
|
cp build/riscv32-nemu/*.txt $out/share/dump
|
||||||
'';
|
'';
|
||||||
|
|
||||||
dontFixup = true;
|
dontFixup = true;
|
||||||
|
@ -60,6 +61,15 @@
|
||||||
gdb
|
gdb
|
||||||
] ++ builtins.attrValues self.packages.${system};
|
] ++ builtins.attrValues self.packages.${system};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
devShells.nemu = pkgs.mkShell {
|
||||||
|
packages = with pkgs; [
|
||||||
|
clang-tools
|
||||||
|
];
|
||||||
|
inputsFrom = [
|
||||||
|
self.packages.${system}.nemu
|
||||||
|
];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
22
nemu/Kconfig
22
nemu/Kconfig
|
@ -151,6 +151,28 @@ config ITRACE_COND
|
||||||
string "Only trace instructions when the condition is true"
|
string "Only trace instructions when the condition is true"
|
||||||
default "true"
|
default "true"
|
||||||
|
|
||||||
|
config ITRACE_BUFFER
|
||||||
|
depends on ITRACE
|
||||||
|
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
|
config DIFFTEST
|
||||||
depends on TARGET_NATIVE_ELF
|
depends on TARGET_NATIVE_ELF
|
||||||
|
|
|
@ -23,7 +23,6 @@ typedef struct Decode {
|
||||||
vaddr_t snpc; // static next pc
|
vaddr_t snpc; // static next pc
|
||||||
vaddr_t dnpc; // dynamic next pc
|
vaddr_t dnpc; // dynamic next pc
|
||||||
ISADecodeInfo isa;
|
ISADecodeInfo isa;
|
||||||
IFDEF(CONFIG_ITRACE, char logbuf[128]);
|
|
||||||
} Decode;
|
} Decode;
|
||||||
|
|
||||||
// --- pattern matching mechanism ---
|
// --- pattern matching mechanism ---
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <utils.h>
|
#include <utils.h>
|
||||||
|
|
||||||
|
#define Trace(format, ...) \
|
||||||
|
_Log("[TRACE] " format "\n", ## __VA_ARGS__)
|
||||||
|
|
||||||
#define Log(format, ...) \
|
#define Log(format, ...) \
|
||||||
_Log(ANSI_FMT("[INFO] %s:%d %s() ", ANSI_FG_BLUE) format "\n", \
|
_Log(ANSI_FMT("[INFO] %s:%d %s() ", ANSI_FG_BLUE) format "\n", \
|
||||||
__FILE__, __LINE__, __func__, ## __VA_ARGS__)
|
__FILE__, __LINE__, __func__, ## __VA_ARGS__)
|
||||||
|
@ -38,6 +41,7 @@
|
||||||
MUXDEF(CONFIG_TARGET_AM, printf(ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__), \
|
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__))); \
|
(fflush(stdout), fprintf(stderr, ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__))); \
|
||||||
IFNDEF(CONFIG_TARGET_AM, extern FILE* log_fp; fflush(log_fp)); \
|
IFNDEF(CONFIG_TARGET_AM, extern FILE* log_fp; fflush(log_fp)); \
|
||||||
|
IFDEF(CONFIG_ITRACE, log_itrace_print()); \
|
||||||
extern void assert_fail_msg(); \
|
extern void assert_fail_msg(); \
|
||||||
assert_fail_msg(); \
|
assert_fail_msg(); \
|
||||||
assert(cond); \
|
assert(cond); \
|
||||||
|
|
|
@ -74,4 +74,7 @@ uint64_t get_time();
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
IFDEF(CONFIG_ITRACE, void log_itrace_print());
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
#include <cpu/cpu.h>
|
#include <cpu/cpu.h>
|
||||||
#include <cpu/decode.h>
|
#include <cpu/decode.h>
|
||||||
#include <cpu/difftest.h>
|
#include <cpu/difftest.h>
|
||||||
|
@ -29,15 +30,17 @@ CPU_state cpu = {};
|
||||||
uint64_t g_nr_guest_inst = 0;
|
uint64_t g_nr_guest_inst = 0;
|
||||||
static uint64_t g_timer = 0; // unit: us
|
static uint64_t g_timer = 0; // unit: us
|
||||||
static bool g_print_step = false;
|
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();
|
void device_update();
|
||||||
bool wp_eval_all();
|
bool wp_eval_all();
|
||||||
|
|
||||||
static void trace_and_difftest(Decode *_this, vaddr_t dnpc) {
|
static void trace_and_difftest(Decode *_this, vaddr_t dnpc) {
|
||||||
#ifdef CONFIG_ITRACE_COND
|
#ifdef CONFIG_ITRACE_COND
|
||||||
if (ITRACE_COND) { log_write("%s\n", _this->logbuf); }
|
if (ITRACE_COND) { log_write("%s\n", logbuf[logbuf_rear]); }
|
||||||
#endif
|
#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));
|
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);
|
isa_exec_once(s);
|
||||||
cpu.pc = s->dnpc;
|
cpu.pc = s->dnpc;
|
||||||
#ifdef CONFIG_ITRACE
|
#ifdef CONFIG_ITRACE
|
||||||
char *p = s->logbuf;
|
logbuf_rear = (logbuf_rear + 1) % CONFIG_ITRACE_BUFFER;
|
||||||
p += snprintf(p, sizeof(s->logbuf), FMT_WORD ":", s->pc);
|
char *p = logbuf[logbuf_rear];
|
||||||
|
p += snprintf(p, sizeof(logbuf), FMT_WORD ":", s->pc);
|
||||||
int ilen = s->snpc - s->pc;
|
int ilen = s->snpc - s->pc;
|
||||||
int i;
|
int i;
|
||||||
uint8_t *inst = (uint8_t *)&s->isa.inst.val;
|
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
|
#ifndef CONFIG_ISA_loongarch32r
|
||||||
void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte);
|
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);
|
MUXDEF(CONFIG_ISA_x86, s->snpc, s->pc), (uint8_t *)&s->isa.inst.val, ilen);
|
||||||
#else
|
#else
|
||||||
p[0] = '\0'; // the upstream llvm does not support loongarch32r
|
p[0] = '\0'; // the upstream llvm does not support loongarch32r
|
||||||
|
@ -79,7 +83,7 @@ static void execute(uint64_t n) {
|
||||||
g_nr_guest_inst ++;
|
g_nr_guest_inst ++;
|
||||||
trace_and_difftest(&s, cpu.pc);
|
trace_and_difftest(&s, cpu.pc);
|
||||||
if (wp_eval_all()) {
|
if (wp_eval_all()) {
|
||||||
puts(s.logbuf);
|
puts(logbuf[logbuf_rear]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (nemu_state.state != NEMU_RUNNING) break;
|
if (nemu_state.state != NEMU_RUNNING) break;
|
||||||
|
@ -121,13 +125,16 @@ void cpu_exec(uint64_t n) {
|
||||||
switch (nemu_state.state) {
|
switch (nemu_state.state) {
|
||||||
case NEMU_RUNNING: nemu_state.state = NEMU_STOP; break;
|
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,
|
Log("nemu: %s at pc = " FMT_WORD,
|
||||||
(nemu_state.state == NEMU_ABORT ? ANSI_FMT("ABORT", ANSI_FG_RED) :
|
(nemu_state.state == NEMU_ABORT ? ANSI_FMT("ABORT", ANSI_FG_RED) :
|
||||||
(nemu_state.halt_ret == 0 ? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN) :
|
(nemu_state.halt_ret == 0 ? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN) :
|
||||||
ANSI_FMT("HIT BAD TRAP", ANSI_FG_RED))),
|
ANSI_FMT("HIT BAD TRAP", ANSI_FG_RED))),
|
||||||
nemu_state.halt_pc);
|
nemu_state.halt_pc);
|
||||||
// fall through
|
if(nemu_state.halt_ret != 0) {
|
||||||
|
log_itrace_print();
|
||||||
|
}
|
||||||
|
} // fall through
|
||||||
case NEMU_QUIT: statistic();
|
case NEMU_QUIT: statistic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||||
*
|
*
|
||||||
* NEMU is licensed under Mulan PSL v2.
|
* NEMU is licensed under Mulan PSL v2.
|
||||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
* You can use this software according to the terms and conditions of the Mulan
|
||||||
* You may obtain a copy of Mulan PSL v2 at:
|
*PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
||||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
*KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
*NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
*
|
*
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "local-include/reg.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 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)
|
#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;
|
uint32_t i = s->isa.inst.val;
|
||||||
int rs1 = BITS(i, 19, 15);
|
int rs1 = BITS(i, 19, 15);
|
||||||
int rs2 = BITS(i, 24, 20);
|
int rs2 = BITS(i, 24, 20);
|
||||||
|
@ -53,7 +54,7 @@ static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2, word_
|
||||||
|
|
||||||
static void do_branch(Decode *s, bool condition, word_t offset) {
|
static void do_branch(Decode *s, bool condition, word_t offset) {
|
||||||
if (condition) {
|
if (condition) {
|
||||||
puts(s->logbuf);
|
// puts(s->logbuf[s->logbuf_rear]);
|
||||||
s->dnpc = s->pc + offset;
|
s->dnpc = s->pc + offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,8 +101,6 @@ static int decode_exec(Decode *s) {
|
||||||
INSTPAT("0000000 ????? ????? 001 ????? 00100 11", slli , I, R(rd) = src1 << imm);
|
INSTPAT("0000000 ????? ????? 001 ????? 00100 11", slli , I, R(rd) = src1 << imm);
|
||||||
INSTPAT("0000000 ????? ????? 101 ????? 00100 11", srli , 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("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("0000000 ????? ????? 000 ????? 01100 11", add , R, R(rd) = src1 + src2);
|
||||||
INSTPAT("0100000 ????? ????? 000 ????? 01100 11", sub , 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);
|
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 ????? ????? 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
|
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("??????? ????? ????? ??? ????? ????? ??", inv , N, INV(s->pc));
|
||||||
INSTPAT_END();
|
INSTPAT_END();
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "debug.h"
|
||||||
#include <memory/host.h>
|
#include <memory/host.h>
|
||||||
#include <memory/paddr.h>
|
#include <memory/paddr.h>
|
||||||
#include <device/mmio.h>
|
#include <device/mmio.h>
|
||||||
|
@ -23,6 +25,11 @@ static uint8_t *pmem = NULL;
|
||||||
#else // CONFIG_PMEM_GARRAY
|
#else // CONFIG_PMEM_GARRAY
|
||||||
static uint8_t pmem[CONFIG_MSIZE] PG_ALIGN = {};
|
static uint8_t pmem[CONFIG_MSIZE] PG_ALIGN = {};
|
||||||
#endif
|
#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; }
|
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; }
|
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);
|
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() {
|
void init_mem() {
|
||||||
#if defined(CONFIG_PMEM_MALLOC)
|
#if defined(CONFIG_PMEM_MALLOC)
|
||||||
pmem = malloc(CONFIG_MSIZE);
|
pmem = malloc(CONFIG_MSIZE);
|
||||||
assert(pmem);
|
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
|
#endif
|
||||||
IFDEF(CONFIG_MEM_RANDOM, memset(pmem, rand(), CONFIG_MSIZE));
|
IFDEF(CONFIG_MEM_RANDOM, memset(pmem, rand(), CONFIG_MSIZE));
|
||||||
Log("physical memory area [" FMT_PADDR ", " FMT_PADDR "]", PMEM_LEFT, PMEM_RIGHT);
|
Log("physical memory area [" FMT_PADDR ", " FMT_PADDR "]", PMEM_LEFT, PMEM_RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
word_t paddr_read(paddr_t addr, int len) {
|
word_t paddr_read(paddr_t addr, int len) {
|
||||||
if (likely(in_pmem(addr))) return pmem_read(addr, len);
|
word_t result = 0;
|
||||||
IFDEF(CONFIG_DEVICE, return mmio_read(addr, len));
|
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);
|
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) {
|
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; }
|
if (likely(in_pmem(addr))) { pmem_write(addr, len, data); return; }
|
||||||
IFDEF(CONFIG_DEVICE, mmio_write(addr, len, data); return);
|
IFDEF(CONFIG_DEVICE, mmio_write(addr, len, data); return);
|
||||||
out_of_bound(addr);
|
out_of_bound(addr);
|
||||||
|
|
|
@ -35,3 +35,18 @@ bool log_enable() {
|
||||||
(g_nr_guest_inst <= CONFIG_TRACE_END), false);
|
(g_nr_guest_inst <= CONFIG_TRACE_END), false);
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
||||||
|
|
|
@ -6,10 +6,11 @@ val chiselVersion = "5.1.0"
|
||||||
|
|
||||||
lazy val root = (project in file("."))
|
lazy val root = (project in file("."))
|
||||||
.settings(
|
.settings(
|
||||||
name := "ChiselLearning",
|
name := "flow",
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
"org.chipsalliance" %% "chisel" % chiselVersion,
|
"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(
|
scalacOptions ++= Seq(
|
||||||
"-language:reflectiveCalls",
|
"-language:reflectiveCalls",
|
||||||
|
|
|
@ -2,8 +2,10 @@ package npc
|
||||||
|
|
||||||
import chisel3._
|
import chisel3._
|
||||||
import chisel3.util.{MuxLookup, Fill, Decoupled, Counter, Queue, Reverse}
|
import chisel3.util.{MuxLookup, Fill, Decoupled, Counter, Queue, Reverse}
|
||||||
|
import chisel3.util.{SRAM}
|
||||||
import chisel3.stage.ChiselOption
|
import chisel3.stage.ChiselOption
|
||||||
import npc.util.KeyboardSegController
|
import npc.util.{ KeyboardSegController, RegisterFile }
|
||||||
|
import flowpc.components.ProgramCounter
|
||||||
|
|
||||||
class Switch extends Module {
|
class Switch extends Module {
|
||||||
val io = IO(new Bundle {
|
val io = IO(new Bundle {
|
||||||
|
@ -31,3 +33,12 @@ class Keyboard extends Module {
|
||||||
io.segs := seg_handler.io.segs
|
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
|
||||||
|
|
11
npc/core/src/main/scala/ProgramCounter.scala
Normal file
11
npc/core/src/main/scala/ProgramCounter.scala
Normal file
|
@ -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)
|
||||||
|
}
|
|
@ -1,25 +1,73 @@
|
||||||
package npc.util
|
package flowpc.components
|
||||||
|
|
||||||
import chisel3._
|
import chisel3._
|
||||||
|
import chisel3.util.log2Ceil
|
||||||
|
import chisel3.util.UIntToOH
|
||||||
|
import chisel3.util.MuxLookup
|
||||||
|
|
||||||
class RegisterFile(readPorts: Int) extends Module {
|
class RegControl extends Bundle {
|
||||||
require(readPorts >= 0)
|
val writeEnable = Input(Bool())
|
||||||
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)))
|
|
||||||
})
|
|
||||||
|
|
||||||
val regFile = RegInit(VecInit(Seq.fill(32)(0.U(32.W))))
|
object WriteSelect extends ChiselEnum {
|
||||||
for (i <- 1 until 32) {
|
val rAluOut, rMemOut = Value
|
||||||
regFile(i) := regFile(i)
|
}
|
||||||
|
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
|
regFile(0) := 0.U
|
||||||
|
|
||||||
for (i <- 0 until readPorts) {
|
for (readPort <- readPorts) {
|
||||||
io.readData(i) := regFile(io.readAddr(i))
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
63
npc/core/src/test/scala/RegisterFile.scala
Normal file
63
npc/core/src/test/scala/RegisterFile.scala
Normal file
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue