From 9124788a5fee3b626058460d781516644fc9f5da Mon Sep 17 00:00:00 2001 From: Qiming Chu Date: Fri, 10 May 2024 22:54:44 +0800 Subject: [PATCH] Use a new method to decode instructions --- src/arch/rv64.zig | 30 +++++++++++++++ src/cpu/decode.zig | 93 +++++++++++++++++++++++++++++----------------- src/cpu/exu.zig | 52 +++++++++++--------------- src/main.zig | 2 +- src/util.zig | 13 +++++++ 5 files changed, 124 insertions(+), 66 deletions(-) diff --git a/src/arch/rv64.zig b/src/arch/rv64.zig index b1b3e07..51bfa23 100644 --- a/src/arch/rv64.zig +++ b/src/arch/rv64.zig @@ -9,6 +9,9 @@ // See the Mulan PSL v2 for more details. const std = @import("std"); +const decode = @import("../cpu/decode.zig"); +const cpu = @import("../cpu/cpu.zig"); +const setState = @import("../cpu/exu.zig").setState; pub const word_t = u64; pub const vaddr_t = u64; @@ -20,3 +23,30 @@ pub const riscv64_ISADecodeInfo = packed struct { val: u32, }; }; + +pub const MatchOp = *const fn (inst: decode.Instruction) void; + +pub fn addi(inst: decode.Instruction) void { + const op = inst.addi; + cpu.setGPRs(op.rd, cpu.GPRs(op.rs1) +% op.imm); + return; +} + +pub fn ebreak(inst: decode.Instruction) void { + if (inst.ebreak.halt == 1) { + // std.debug.print("is halt:{}\n", .{inst.ebreak.halt}); + setState(true); + } else { + const out: u8 = @intCast(cpu.cpu.gprs[11] & 0xff); + std.debug.print("{c}", .{out}); + setState(false); + } + return; +} + +pub fn inst2exu(inst: decode.Instruction) MatchOp { + return switch (inst) { + .addi => addi, + .ebreak => ebreak, + }; +} diff --git a/src/cpu/decode.zig b/src/cpu/decode.zig index d8499e3..ff59c92 100644 --- a/src/cpu/decode.zig +++ b/src/cpu/decode.zig @@ -15,6 +15,8 @@ const word_t = isa.word_t; const testing = std.testing; const expect = std.testing.expect; const print = @import("../common.zig").print; +const cpu = @import("./cpu.zig"); +const utils = @import("../util.zig"); const DECODE_TYPE = enum { TYPE_I, @@ -34,40 +36,63 @@ pub const Decode = struct { inst: u32, }; -fn BITSMASK(hi: u5, lo: u5) u32 { - return ((@as(u32, 1) << (hi - lo + 1)) - 1) << lo; -} +pub const TypeB = struct { + imm: u32, + rs1: u32, + rs2: u32, + rd: u32, +}; + +pub const TypeI = struct { + imm: u32, + rs1: u32, + rd: u32, + pub fn decode(inst: u32) TypeI { + const imm: u32 = utils.BITS(inst, 31, 20); + const rs1: u32 = utils.BITS(inst, 19, 15); + const rd: u32 = utils.BITS(inst, 11, 7); + return TypeI{ + .imm = imm, + .rs1 = rs1, + .rd = rd, + }; + } + pub fn Operand(funct3: u32) !Operand { + return switch (funct3) { + 0 => Operand.addi, + else => unreachable, + }; + } +}; -fn BITS(x: u32, hi: u5, lo: u5) u32 { - const mask = BITSMASK(hi, lo); - return (x & mask) >> @intCast(lo); -} +pub const TypeEnv = struct { + ebreak: u32, + ret: u64, + halt: u32, + const inst_ebreak: u32 = 0b00000000000100000000000001110011; + pub fn decode(inst: u32) TypeEnv { + // Halt emu when is ebreak + if (inst == inst_ebreak) { + if (cpu.GPRs(10) == 1) return TypeEnv{ .ebreak = 1, .ret = cpu.GPRs(10), .halt = 1 } else return TypeEnv{ .ebreak = 1, .ret = cpu.GPRs(10), .halt = 0 }; + } + return TypeEnv{ .ebreak = 0, .ret = cpu.GPRs(10), .halt = 0 }; + } +}; + +pub const Instruction = union(enum) { + addi: TypeI, + ebreak: TypeEnv, -pub fn decode_operand(s: *Decode, dest: *word_t, src1: *word_t, src2: *word_t, inst_type: *word_t, imm: *word_t) void { - const i: u32 = s.*.inst; - const rd: u32 = BITS(i, 11, 7); - const rs1: u32 = BITS(i, 19, 15); - const rs2: u32 = BITS(i, 24, 20); - const opcode: u32 = BITS(i, 6, 0); - const imm_i: u32 = BITS(i, 31, 20); - dest.* = rd; - src1.* = rs1; - src2.* = rs2; - inst_type.* = opcode; - imm.* = imm_i; -} + pub fn DecodePattern(op: anytype, val: anytype) Instruction { + return @unionInit(Instruction, @tagName(op), val); // Return the union with the tag name of the operation and the value + } -test "decode_operand" { - var s: Decode = undefined; - s.inst = 0x00000033; - var dest: word_t = undefined; - var src1: word_t = undefined; - var src2: word_t = undefined; - var opcode: word_t = undefined; - decode_operand(&s, &dest, &src1, &src2, &opcode); - print("dest: {}, src1: {}, src2: {}, opcode: {}\n", .{ dest, src1, src2, opcode }); - try testing.expect(dest == 0); - try testing.expect(src1 == 0); - try testing.expect(src2 == 0); - try testing.expect(opcode == 51); -} + pub fn decode32(inst: u32) anyerror!Instruction { + const opcode: u32 = utils.BITS(inst, 6, 0); + return switch (opcode) { + 0b0010011 => DecodePattern(.addi, TypeI.decode(inst)), + 0b1110011 => DecodePattern(.ebreak, TypeEnv.decode(inst)), + else => unreachable, + }; + } +}; diff --git a/src/cpu/exu.zig b/src/cpu/exu.zig index b3c1462..d0dd484 100644 --- a/src/cpu/exu.zig +++ b/src/cpu/exu.zig @@ -12,45 +12,35 @@ const std = @import("std"); const M = @import("../mem.zig").MEM; const c = @import("cpu.zig"); -const Decode = @import("decode.zig").Decode; -const decode = @import("decode.zig").decode_operand; +const decode = @import("decode.zig"); const word_t = @import("../arch/rv64.zig").word_t; -const print = @import("../common.zig").print; +const print = @import("../util.zig").print; const ifu = @import("ifu.zig"); +const isa = @import("../arch/rv64.zig"); var halt = false; pub fn exu_cycle() void { const inst: u32 = ifu.inst_fetch(c.cpu.pc, &M.memory); - var s: Decode = undefined; - s.inst = inst; - var dest: word_t = undefined; - var src1: word_t = undefined; - var src2: word_t = undefined; - var opcode: word_t = undefined; - var imm_i: word_t = undefined; - decode(&s, &dest, &src1, &src2, &opcode, &imm_i); - const nrZero: bool = if (dest != 0) true else false; - const addi: bool = if ((inst & 0x7f) == 0x13 and ((inst >> 12 & 0x7)) == 0) true else false; - const ebreak: bool = if ((inst & 0x00100073) != 0) true else false; - if (addi) { - if (nrZero) { - c.setGPRs(@intCast(dest), c.cpu.gprs[src1] + imm_i); - } - } else if (ebreak) { - if (c.cpu.gprs[10] == 0) { - const out: u8 = @intCast(c.cpu.gprs[11] & 0xff); - print("{c}", .{out}); - } else if (c.cpu.gprs[10] == 1) { - halt = true; - } else { - print("Unsupported ebreak command\n", .{}); - } - } else { - print("Unsupported instruction\n", .{}); - } + var failed: anyerror = undefined; + const inst_test: ?decode.Instruction = decode.Instruction.decode32(inst) catch |err| { + failed = err; + return; + }; + const exu = isa.inst2exu(inst_test.?); + const ret = exu(inst_test.?); + _ = ret; } -pub fn isHalt() bool { +pub fn ishalt() bool { return halt; } + +pub fn setState(x: bool) void { + if (x) { + halt = true; + } else { + halt = false; + } + return; +} diff --git a/src/main.zig b/src/main.zig index 92ebb8f..6fb6661 100644 --- a/src/main.zig +++ b/src/main.zig @@ -10,7 +10,7 @@ const std = @import("std"); const c = @import("cpu/cpu.zig"); -const halt = @import("cpu/exu.zig").isHalt; +const halt = @import("cpu/exu.zig").ishalt; const initMemory = @import("mem.zig").initMem; pub const reg_display = @import("cpu/reg.zig").reg_display; diff --git a/src/util.zig b/src/util.zig index 2340564..f15591a 100644 --- a/src/util.zig +++ b/src/util.zig @@ -15,3 +15,16 @@ pub const print = std.debug.print; pub fn putchar(c: u8) void { std.os.write(std.os.Stdout, &c, 1); } + +pub inline fn CONCACT(a: u32, b: u32) u64 { + return @intCast(a << 32 | b); +} + +pub fn BITSMASK(hi: u5, lo: u5) u32 { + return ((@as(u32, 1) << (hi - lo + 1)) - 1) << lo; +} + +pub fn BITS(x: u32, hi: u5, lo: u5) u32 { + const mask = BITSMASK(hi, lo); + return (x & mask) >> @intCast(lo); +}