pa2.1: support RV32I instructions
This commit is contained in:
parent
3c7c5f060e
commit
e764133868
4 changed files with 100 additions and 13 deletions
|
@ -64,12 +64,34 @@ include $(NEMU_HOME)/scripts/native.mk
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(NEMU_HOME)/tests/Makefile
|
include $(NEMU_HOME)/tests/Makefile
|
||||||
all-tests: TEST_OBJS = $(filter-out $(OBJ_DIR)/src/nemu-main.o, $(OBJS))
|
unit-tests: TEST_OBJS = $(filter-out $(OBJ_DIR)/src/nemu-main.o, $(OBJS))
|
||||||
all-tests: CFLAGS += $(shell pkg-config --cflags check)
|
unit-tests: CFLAGS += $(shell pkg-config --cflags check)
|
||||||
all-tests: LDFLAGS += $(shell pkg-config --libs check)
|
unit-tests: LDFLAGS += $(shell pkg-config --libs check)
|
||||||
all-tests: $(TEST_SRCS:%.c=$(OBJ_DIR)/%)
|
unit-tests: $(TEST_SRCS:%.c=$(OBJ_DIR)/%)
|
||||||
|
|
||||||
test: all-tests
|
IMAGES = $(patsubst %.bin, %, $(shell find $(IMAGES_PATH) -type f -name '*.bin'))
|
||||||
@$(OBJ_DIR)/tests/expr_test
|
|
||||||
|
|
||||||
.PHONY: test
|
COLOR_RED = \033[1;31m
|
||||||
|
COLOR_GREEN = \033[1;32m
|
||||||
|
COLOR_BLUE = \033[1;34m
|
||||||
|
COLOR_NONE = \033[0m
|
||||||
|
|
||||||
|
RESULT = .result.tmp
|
||||||
|
$(shell > $(RESULT)) # Clear result file
|
||||||
|
|
||||||
|
$(IMAGES): %: %.bin $(BINARY)
|
||||||
|
@echo + TEST $(notdir $<)
|
||||||
|
@$(BINARY) -b $< >/dev/null 2>&1 || printf "\t%14s\n" $(notdir $<) >> $(RESULT)
|
||||||
|
|
||||||
|
integration-tests: $(IMAGES)
|
||||||
|
@printf "$(COLOR_BLUE)INTEGRATION TEST:$(COLOR_NONE)\n\tALL: %s\n\tFAILED: %s\n" $(words $(IMAGES)) $(shell wc -l $(RESULT) | cut -f1 -d' ')
|
||||||
|
@test ! -s $(RESULT) || printf "$(COLOR_RED)FAILED:$(COLOR_NONE)\n"
|
||||||
|
@cat $(RESULT)
|
||||||
|
@test ! -s $(RESULT); \
|
||||||
|
r=$$?; \
|
||||||
|
$(RM) $(RESULT); \
|
||||||
|
test $$r -eq 0
|
||||||
|
|
||||||
|
test: unit-tests integration-tests
|
||||||
|
|
||||||
|
.PHONY: test unit-tests integration-tests
|
|
@ -1,6 +1,7 @@
|
||||||
{ pkgs,
|
{ pkgs,
|
||||||
lib,
|
lib,
|
||||||
stdenv
|
stdenv,
|
||||||
|
am-kernels
|
||||||
}:
|
}:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
|
@ -9,21 +10,25 @@ stdenv.mkDerivation rec {
|
||||||
|
|
||||||
src = ./.;
|
src = ./.;
|
||||||
|
|
||||||
NEMU_HOME = "/build/nemu";
|
|
||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = with pkgs; [
|
||||||
gnumake
|
gnumake
|
||||||
|
pkg-config
|
||||||
flex
|
flex
|
||||||
bison
|
bison
|
||||||
];
|
];
|
||||||
|
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
check
|
|
||||||
readline
|
readline
|
||||||
libllvm
|
libllvm
|
||||||
];
|
];
|
||||||
|
|
||||||
|
checkInputs = [
|
||||||
|
pkgs.check
|
||||||
|
am-kernels
|
||||||
|
];
|
||||||
|
|
||||||
configurePhase = ''
|
configurePhase = ''
|
||||||
echo pwd=$(pwd)
|
export NEMU_HOME=$(pwd)
|
||||||
make alldefconfig
|
make alldefconfig
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
@ -31,7 +36,9 @@ stdenv.mkDerivation rec {
|
||||||
make
|
make
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
doCheck = true;
|
||||||
checkPhase = ''
|
checkPhase = ''
|
||||||
|
export IMAGES_PATH=${am-kernels}/share/images
|
||||||
make test
|
make test
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
@ -40,6 +47,11 @@ stdenv.mkDerivation rec {
|
||||||
make PREFIX=$out install
|
make PREFIX=$out install
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
export NEMU_HOME=$(pwd)
|
||||||
|
export IMAGES_PATH=${am-kernels}/share/images
|
||||||
|
'';
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
description = "NJU EMUlator, a full system x86/mips32/riscv32/riscv64 emulator for teaching";
|
description = "NJU EMUlator, a full system x86/mips32/riscv32/riscv64 emulator for teaching";
|
||||||
homepage = "https://github.com/NJU-ProjectN/nemu.git";
|
homepage = "https://github.com/NJU-ProjectN/nemu.git";
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
#include "local-include/reg.h"
|
#include "local-include/reg.h"
|
||||||
#include <cpu/cpu.h>
|
#include <cpu/cpu.h>
|
||||||
#include <cpu/ifetch.h>
|
#include <cpu/ifetch.h>
|
||||||
|
@ -23,7 +24,7 @@
|
||||||
#define Mw vaddr_write
|
#define Mw vaddr_write
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TYPE_I, TYPE_U, TYPE_S,
|
TYPE_R, TYPE_I, TYPE_I_SHIFT, TYPE_U, TYPE_S, TYPE_B, TYPE_J,
|
||||||
TYPE_N, // none
|
TYPE_N, // none
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,7 +32,9 @@ enum {
|
||||||
#define src2R() do { *src2 = R(rs2); } while (0)
|
#define src2R() do { *src2 = R(rs2); } while (0)
|
||||||
#define immI() do { *imm = SEXT(BITS(i, 31, 20), 12); } while(0)
|
#define immI() do { *imm = SEXT(BITS(i, 31, 20), 12); } while(0)
|
||||||
#define immU() do { *imm = SEXT(BITS(i, 31, 12), 20) << 12; } while(0)
|
#define immU() do { *imm = SEXT(BITS(i, 31, 12), 20) << 12; } while(0)
|
||||||
#define immS() do { *imm = (SEXT(BITS(i, 31, 25), 7) << 5) | BITS(i, 11, 7); } while(0)
|
#define immS() do { *imm = SEXT(BITS(i, 31, 25), 7) << 5 | BITS(i, 11, 7); } 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)
|
||||||
|
|
||||||
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;
|
||||||
|
@ -39,9 +42,19 @@ static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2, word_
|
||||||
int rs2 = BITS(i, 24, 20);
|
int rs2 = BITS(i, 24, 20);
|
||||||
*rd = BITS(i, 11, 7);
|
*rd = BITS(i, 11, 7);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case TYPE_R: src1R(); src2R(); break;
|
||||||
case TYPE_I: src1R(); immI(); break;
|
case TYPE_I: src1R(); immI(); break;
|
||||||
case TYPE_U: immU(); break;
|
case TYPE_U: immU(); break;
|
||||||
|
case TYPE_J: immJ(); break;
|
||||||
case TYPE_S: src1R(); src2R(); immS(); break;
|
case TYPE_S: src1R(); src2R(); immS(); break;
|
||||||
|
case TYPE_B: src1R(); src2R(); immB(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_branch(Decode *s, bool condition, word_t offset) {
|
||||||
|
if (condition) {
|
||||||
|
puts(s->logbuf);
|
||||||
|
s->dnpc = s->pc + offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,9 +70,48 @@ static int decode_exec(Decode *s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTPAT_START();
|
INSTPAT_START();
|
||||||
|
INSTPAT("??????? ????? ????? ??? ????? 01101 11", lui , U, R(rd) = imm);
|
||||||
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc , U, R(rd) = s->pc + imm);
|
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc , U, R(rd) = s->pc + imm);
|
||||||
|
|
||||||
|
INSTPAT("??????? ????? ????? ??? ????? 11011 11", jal , J, do {s->dnpc = s->pc + imm; R(rd) = s->pc + 4; } while(0));
|
||||||
|
INSTPAT("??????? ????? ????? ??? ????? 11001 11", jalr , I, do {s->dnpc = src1 + imm; R(rd) = s->pc + 4; } while(0));
|
||||||
|
INSTPAT("??????? ????? ????? 000 ????? 11000 11", beq , B, do_branch(s, src1 == src2, imm));
|
||||||
|
INSTPAT("??????? ????? ????? 001 ????? 11000 11", bne , B, do_branch(s, src1 != src2, imm));
|
||||||
|
INSTPAT("??????? ????? ????? 100 ????? 11000 11", blt , B, do_branch(s, (sword_t)src1 < (sword_t)src2, imm));
|
||||||
|
INSTPAT("??????? ????? ????? 101 ????? 11000 11", bge , B, do_branch(s, (sword_t)src1 >= (sword_t)src2, imm));
|
||||||
|
INSTPAT("??????? ????? ????? 110 ????? 11000 11", bltu , B, do_branch(s, src1 < src2, imm));
|
||||||
|
INSTPAT("??????? ????? ????? 111 ????? 11000 11", bgeu , B, do_branch(s, src1 >= src2, imm));
|
||||||
|
|
||||||
|
INSTPAT("??????? ????? ????? 000 ????? 00000 11", lb , I, R(rd) = SEXT(Mr(src1 + imm, 1), 8));
|
||||||
|
INSTPAT("??????? ????? ????? 001 ????? 00000 11", lh , I, R(rd) = SEXT(Mr(src1 + imm, 2), 16));
|
||||||
|
INSTPAT("??????? ????? ????? 010 ????? 00000 11", lw , I, R(rd) = SEXT(Mr(src1 + imm, 4), 32));
|
||||||
INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu , I, R(rd) = Mr(src1 + imm, 1));
|
INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu , I, R(rd) = Mr(src1 + imm, 1));
|
||||||
|
INSTPAT("??????? ????? ????? 101 ????? 00000 11", lhu , I, R(rd) = Mr(src1 + imm, 2));
|
||||||
INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb , S, Mw(src1 + imm, 1, src2));
|
INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb , S, Mw(src1 + imm, 1, src2));
|
||||||
|
INSTPAT("??????? ????? ????? 001 ????? 01000 11", sh , S, Mw(src1 + imm, 2, src2));
|
||||||
|
INSTPAT("??????? ????? ????? 010 ????? 01000 11", sw , S, Mw(src1 + imm, 4, src2));
|
||||||
|
|
||||||
|
INSTPAT("??????? ????? ????? 000 ????? 00100 11", addi , I, R(rd) = src1 + imm);
|
||||||
|
INSTPAT("??????? ????? ????? 010 ????? 00100 11", slti , I, R(rd) = (sword_t)src1 < (sword_t)imm ? 1 : 0);
|
||||||
|
INSTPAT("??????? ????? ????? 011 ????? 00100 11", sltiu , I, R(rd) = src1 < imm ? 1 : 0);
|
||||||
|
INSTPAT("??????? ????? ????? 100 ????? 00100 11", xori , I, R(rd) = src1 ^ imm);
|
||||||
|
INSTPAT("??????? ????? ????? 110 ????? 00100 11", ori , I, R(rd) = src1 | imm);
|
||||||
|
INSTPAT("??????? ????? ????? 111 ????? 00100 11", andi , 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("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);
|
||||||
|
INSTPAT("0000000 ????? ????? 010 ????? 01100 11", slt , R, R(rd) = (sword_t)src1 < (sword_t)src2 ? 1 : 0);
|
||||||
|
INSTPAT("0000000 ????? ????? 011 ????? 01100 11", sltu , R, R(rd) = src1 < src2 ? 1 : 0);
|
||||||
|
INSTPAT("0000000 ????? ????? 100 ????? 01100 11", xor , R, R(rd) = src1 ^ src2);
|
||||||
|
INSTPAT("0000000 ????? ????? 101 ????? 01100 11", srl , R, R(rd) = src1 >> src2);
|
||||||
|
INSTPAT("0100000 ????? ????? 101 ????? 01100 11", sra , R, R(rd) = (sword_t)src1 >> (src2 & 0x01F));
|
||||||
|
INSTPAT("0000000 ????? ????? 110 ????? 01100 11", or , 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
|
||||||
INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv , N, INV(s->pc));
|
INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv , N, INV(s->pc));
|
||||||
|
|
|
@ -7,3 +7,4 @@ $(OBJ_DIR)/%: %.c $(TEST_OBJS) app
|
||||||
@$(CC) $(CFLAGS) -o $@.o -c $<
|
@$(CC) $(CFLAGS) -o $@.o -c $<
|
||||||
@echo + LD $@
|
@echo + LD $@
|
||||||
@$(LD) $(LIBS) $(LDFLAGS) -o $@ $(TEST_OBJS) $@.o
|
@$(LD) $(LIBS) $(LDFLAGS) -o $@ $(TEST_OBJS) $@.o
|
||||||
|
@$@
|
||||||
|
|
Loading…
Reference in a new issue