aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorAditya Naik2021-05-08 12:51:18 -0400
committerAditya Naik2021-05-08 12:51:18 -0400
commit1acccc74b1036d9d3847fdcc60c392125a03be85 (patch)
tree609c192f1b3e1b4ab89e1992741d988f4120138c /core
Initial
Added work on RV64 I core to date, including tb
Diffstat (limited to 'core')
-rw-r--r--core/alu.v29
-rw-r--r--core/aluctrl.v114
-rw-r--r--core/ctrl.v201
-rw-r--r--core/obj_dir/Vtb.cpp99
-rw-r--r--core/obj_dir/Vtb.d3
-rw-r--r--core/obj_dir/Vtb.h88
-rw-r--r--core/obj_dir/Vtb.mk66
-rw-r--r--core/obj_dir/Vtb__ALL.cpp5
-rw-r--r--core/obj_dir/Vtb__ALL.d5
-rw-r--r--core/obj_dir/Vtb__Slow.cpp117
-rw-r--r--core/obj_dir/Vtb__Syms.cpp21
-rw-r--r--core/obj_dir/Vtb__Syms.h35
-rw-r--r--core/obj_dir/Vtb__ver.d1
-rw-r--r--core/obj_dir/Vtb__verFiles.dat14
-rw-r--r--core/obj_dir/Vtb_classes.mk49
-rw-r--r--core/obj_dir/verilated.d8
-rw-r--r--core/regs.v42
-rw-r--r--core/tb.v54
18 files changed, 951 insertions, 0 deletions
diff --git a/core/alu.v b/core/alu.v
new file mode 100644
index 0000000..439df08
--- /dev/null
+++ b/core/alu.v
@@ -0,0 +1,29 @@
+module alu(
+ input wire [3:0] op,
+ input wire [63:0] in_x,
+ input wire [63:0] in_y,
+ output reg [63:0] out
+ );
+
+ always @* begin
+ case (op)
+ 4'b0000: out = in_x & in_y; // and
+ 4'b0001: out = in_x | in_y; // or
+ 4'b0010: out = in_x + in_y; // add
+ 4'b0011: out = in_x - in_y; // sub
+ 4'b0100: out = $signed(in_x) >>> $signed(in_y); // sra signed
+ 4'b0101: out = in_x < in_y; // stlu
+ 4'b0110: out = in_x ^ in_y; // xor
+ 4'b0111: out = in_x >> in_y; // srl
+ 4'b1000: out = $signed(in_x) < $signed(in_y); // slt signed
+ 4'b1001: out = in_x << in_y; // sll
+ 4'b1010: out = ~(in_x | in_y); // nor
+ 4'b1011: out = $signed(in_x) >= $signed(in_y); // sge
+ 4'b1100: out = in_x >= in_y; // sgeu
+ 4'b1101: out = in_x == in_y; // seq
+ 4'b1110: out = in_x != in_y; // sne
+ 4'b1111: out = 0; // invalid
+ endcase
+ end // always @ *
+
+endmodule // alu
diff --git a/core/aluctrl.v b/core/aluctrl.v
new file mode 100644
index 0000000..f078870
--- /dev/null
+++ b/core/aluctrl.v
@@ -0,0 +1,114 @@
+/**
+ This file contains ALU control logic.
+
+ * The ALU control unit
+ *
+ * Input: aluop 00 for ld/st, 10 for R-type, 01 for branch
+ * Input: funct7 The most significant bits of the instruction
+ * Input: funct3 The middle three bits of the instruction (12-14)
+ * Output: operation What we want the ALU to do.
+ **/
+
+module aluctrl(
+ input wire [1:0] aluop,
+ input wire itype,
+ input wire [6:0] funct7,
+ input wire [2:0] funct3,
+ output reg [3:0] operation
+ );
+
+ always @* begin
+ case (aluop)
+ 2'b00:
+ operation = 4'b0010;
+ 2'b10: begin
+ case (funct3)
+ 3'b000: begin
+ if (itype == 1'b1 || funct7 == 7'b0000000)
+ operation = 4'b0010; // add
+ else
+ operation = 4'b0011; //sub
+ end
+ 3'b001: operation = 4'b1001; // sll
+ 3'b010: operation = 4'b1000; // slt
+ 3'b011: operation = 4'b0101; // sltu
+ 3'b100: operation = 4'b0110; // xor
+ 3'b101: begin
+ if (funct7 == 7'b0000000)
+ assign operation = 4'b0111; // srl
+ else
+ assign operation = 4'b0100; // sra
+ end
+ 4'b110: operation = 4'b0001; // or
+ 4'b111: operation = 4'b0000;
+ endcase // case (funct3)
+ end // case: 2'b10
+ 2'b01: begin
+ case (funct3)
+ 3'b000: operation = 4'b1101; // beq
+ 3'b001: operation = 4'b1110; // bne
+ 3'b100: operation = 4'b1000; // blt
+ 3'b101: operation = 4'b1011; // bge
+ 3'b110: operation = 4'b0101; // bltu
+ 3'b111: operation = 4'b1100; // bgeu
+ default: operation = 4'b1111; // invalid
+ endcase // case (funct3)
+ end // case: 2'b01
+ default: operation = 4'b1111; // invalid
+ endcase // case (aluop)
+ end // always @ *
+
+ // Direct translation from dino
+ // if (aluop == 2'b00) begin // ld/st
+ // assign operation = 4'b0010;
+ // end
+ // else if (aluop == 2'b10) begin
+ // if (funct3 == 3'b000) begin // R-type
+ // if (itype == 1'b1 || funct7 == 7'b0000000)
+ // assign operation = 4'b0010; // add
+ // else
+ // assign operation = 4'b0011; //sub
+ // end
+ // else if (funct3 == 3'b001)
+ // assign operation = 4'b1001; // sll
+ // else if (funct3 == 3'b010)
+ // assign operation = 4'b1000; // slt
+ // else if (funct3 == 3'b011)
+ // assign operation = 4'b0101; // sltu
+ // else if (funct3 == 3'b100)
+ // assign operation = 4'b0110; // xor
+
+ // else if (funct3 == 3'b101) begin
+ // if (func7 == 7'b0000000)
+ // assign operation = 4'b0111; // srl
+ // else
+ // assign operation = 4'b0100; // sra
+ // end
+ // else if (funct3 == 4'b110)
+ // assign operation = 4'b0001; // or
+ // else
+ // assign operation = 4'b000;
+ // end
+ // else if (aluop == 2'b01) begin // branches
+ // if (funct3 == 3'b000)
+ // assign operation = 4'b1101; // beq
+ // else if (funct3 == 3'b001)
+ // assign operation = 4'b1110; // bne
+ // else if (funct3 == 3'b100)
+ // assign operation = 4'b1000; // blt
+ // else if (funct3 == 3'b101)
+ // assign operation = 4'b1011; // bge
+ // else if (funct3 == 3'b110)
+ // assign operation = 4'b0101; // bltu
+ // else if (funct3 == 3'b111)
+ // assign operation = 4'b1100; // bgeu
+ // else
+ // assign operation = 4'b1111; // invalid
+ // end
+ // else
+ // assign operation = 4'b1111; // invalid
+ // end // always @ *
+
+endmodule // aluctrl
+
+
diff --git a/core/ctrl.v b/core/ctrl.v
new file mode 100644
index 0000000..3fbee1f
--- /dev/null
+++ b/core/ctrl.v
@@ -0,0 +1,201 @@
+
+/**
+ * Main control logic for our simple processor.
+ *
+ * Input: opcode: Opcode from instruction
+ *
+ * Output: validinst True if the instruction we're decoding is valid
+ * Output: _branch true if branch or (jal. update PC with immediate
+ * Output: _jump True if we want update the PC with pc+imm regardless of the ALU result
+ * Output: _imm True if we're working on an itype instruction
+ * Output: pc_from_alu Use the pc from the ALU, not pc+4 or pc+imm
+ * Output: mem_read true if we should read from memory
+ * Output: mem_write true if writing to the data memory
+ * Output: reg_write true if writing to the register file
+ * Output: to_reg 0 for result from execute, 1 for data from memory
+ * Output: result_select 00 for result from alu, 01 for immediate, 10 for pc+4
+ * Output: alu_src source for the second ALU input (0 is readdata2 and 1 is immediate)
+ * Output: pc_add Use PC as the input to the ALU
+ * Output: alu_op 00 for ld/st, 10 for R-type, 01 for branch
+ **/
+
+module op(
+ input wire [6:0] opcode,
+
+ output reg valid_instr,
+ output reg _branch,
+ output reg _jump,
+ output reg _imm,
+ output reg pc_from_alu,
+ output reg mem_read,
+ output reg mem_write,
+ output reg reg_write,
+ output reg to_reg,
+ output reg [1:0] result_select,
+ output reg alu_src,
+ output reg pc_add,
+ output reg [1:0] alu_op
+ );
+
+ // opcodes for all types and formats
+ assign rtype = 7'b0110011;
+ assign itype = 7'b0010011;
+ assign btype = 7'b1100011;
+
+ assign load = 7'b0000011;
+ assign store = 7'b0100011;
+ assign lui = 7'b0110111;
+ assign auipc = 7'b0010111;
+ assign jal = 7'b1101111;
+ assign jalr = 7'b1100111;
+
+ always @* begin
+ case (opcode)
+ rtype: begin
+ assign valid_instr = 1;
+ assign reg_write = 1;
+ assign alu_op = 2;
+
+ assign _branch = 0;
+ assign _jump = 0;
+ assign _imm = 0;
+ assign pc_from_alu = 0;
+ assign mem_read = 0;
+ assign mem_write = 0;
+ assign to_reg = 0;
+ assign result_select = 0;
+ assign alu_src = 0;
+ assign pc_add = 0;
+ end
+ itype: begin
+ assign valid_instr = 1;
+ assign reg_write = 1;
+ assign alu_op = 2;
+ assign alu_src = 1;
+ assign _imm = 1;
+
+ assign _branch = 0;
+ assign _jump = 0;
+ assign pc_from_alu = 0;
+ assign mem_read = 0;
+ assign mem_write = 0;
+ assign to_reg = 0;
+ assign result_select = 0;
+ assign pc_add = 0;
+ end
+ load: begin
+ assign valid_instr = 1;
+ assign mem_read = 1;
+ assign reg_write = 1;
+ assign to_reg = 1;
+ assign alu_src = 1;
+
+ assign _branch = 0;
+ assign _jump = 0;
+ assign _imm = 0;
+ assign pc_from_alu = 0;
+ assign mem_write = 0;
+ assign to_reg = 0;
+ assign result_select = 0;
+ assign pc_add = 0;
+ assign alu_op = 0;
+ end
+ store: begin
+ assign valid_instr = 1;
+ assign mem_write = 1;
+ assign alu_src = 1;
+
+ assign _branch = 0;
+ assign _jump = 0;
+ assign _imm = 0;
+ assign pc_from_alu = 0;
+ assign mem_read = 0;
+ assign to_reg = 0;
+ assign result_select = 0;
+ assign pc_add = 0;
+ assign alu_op = 0;
+ end
+ btype: begin
+ assign valid_instr = 1;
+ assign _branch = 1;
+ assign alu_op = 1;
+
+ assign _jump = 0;
+ assign _imm = 0;
+ assign pc_from_alu = 0;
+ assign mem_read = 0;
+ assign mem_write = 0;
+ assign reg_write = 0;
+ assign to_reg = 0;
+ assign result_select = 0;
+ assign alu_src = 0;
+ assign pc_add = 0;
+ end
+ lui: begin
+ assign valid_instr = 1;
+ assign reg_write = 1;
+ assign result_select = 1;
+
+ assign _branch = 0;
+ assign _jump = 0;
+ assign _imm = 0;
+ assign pc_from_alu = 0;
+ assign mem_read = 0;
+ assign mem_write = 0;
+ assign to_reg = 0;
+ assign alu_src = 0;
+ assign pc_add = 0;
+ assign alu_op = 0;
+ end
+ auipc: begin
+ assign valid_instr = 1;
+ assign reg_write = 1;
+ assign alu_src = 1;
+ assign pc_add = 1;
+
+ assign _branch = 0;
+ assign _jump = 0;
+ assign _imm = 0;
+ assign pc_from_alu = 0;
+ assign mem_read = 0;
+ assign mem_write = 0;
+ assign to_reg = 0;
+ assign result_select = 0;
+ assign alu_op = 0;
+ end
+ jal: begin
+ assign valid_instr = 1;
+ assign _jump = 1;
+ assign reg_write = 1;
+ assign result_select = 2;
+
+ assign _branch = 0;
+ assign _imm = 0;
+ assign pc_from_alu = 0;
+ assign mem_read = 0;
+ assign mem_write = 0;
+ assign to_reg = 0;
+ assign alu_src = 0;
+ assign pc_add = 0;
+ assign alu_op = 0;
+ end
+ jalr: begin
+ assign valid_instr = 1;
+ assign pc_from_alu = 1;
+ assign _jump = 1;
+ assign reg_write = 1;
+ assign result_select = 2;
+ assign alu_src = 1;
+
+ assign _branch = 0;
+ assign _imm = 0;
+ assign mem_read = 0;
+ assign mem_write = 0;
+ assign to_reg = 0;
+ assign pc_add = 0;
+ assign alu_op = 0;
+ end
+ endcase
+ end // always
+
+endmodule // op
diff --git a/core/obj_dir/Vtb.cpp b/core/obj_dir/Vtb.cpp
new file mode 100644
index 0000000..f84c787
--- /dev/null
+++ b/core/obj_dir/Vtb.cpp
@@ -0,0 +1,99 @@
+// Verilated -*- C++ -*-
+// DESCRIPTION: Verilator output: Design implementation internals
+// See Vtb.h for the primary calling header
+
+#include "Vtb.h"
+#include "Vtb__Syms.h"
+
+//==========
+
+void Vtb::eval_step() {
+ VL_DEBUG_IF(VL_DBG_MSGF("+++++TOP Evaluate Vtb::eval\n"); );
+ Vtb__Syms* __restrict vlSymsp = this->__VlSymsp; // Setup global symbol table
+ Vtb* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
+#ifdef VL_DEBUG
+ // Debug assertions
+ _eval_debug_assertions();
+#endif // VL_DEBUG
+ // Initialize
+ if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) _eval_initial_loop(vlSymsp);
+ // Evaluate till stable
+ int __VclockLoop = 0;
+ QData __Vchange = 1;
+ do {
+ VL_DEBUG_IF(VL_DBG_MSGF("+ Clock loop\n"););
+ _eval(vlSymsp);
+ if (VL_UNLIKELY(++__VclockLoop > 100)) {
+ // About to fail, so enable debug to see what's not settling.
+ // Note you must run make with OPT=-DVL_DEBUG for debug prints.
+ int __Vsaved_debug = Verilated::debug();
+ Verilated::debug(1);
+ __Vchange = _change_request(vlSymsp);
+ Verilated::debug(__Vsaved_debug);
+ VL_FATAL_MT("tb.v", 6, "",
+ "Verilated model didn't converge\n"
+ "- See DIDNOTCONVERGE in the Verilator manual");
+ } else {
+ __Vchange = _change_request(vlSymsp);
+ }
+ } while (VL_UNLIKELY(__Vchange));
+}
+
+void Vtb::_eval_initial_loop(Vtb__Syms* __restrict vlSymsp) {
+ vlSymsp->__Vm_didInit = true;
+ _eval_initial(vlSymsp);
+ // Evaluate till stable
+ int __VclockLoop = 0;
+ QData __Vchange = 1;
+ do {
+ _eval_settle(vlSymsp);
+ _eval(vlSymsp);
+ if (VL_UNLIKELY(++__VclockLoop > 100)) {
+ // About to fail, so enable debug to see what's not settling.
+ // Note you must run make with OPT=-DVL_DEBUG for debug prints.
+ int __Vsaved_debug = Verilated::debug();
+ Verilated::debug(1);
+ __Vchange = _change_request(vlSymsp);
+ Verilated::debug(__Vsaved_debug);
+ VL_FATAL_MT("tb.v", 6, "",
+ "Verilated model didn't DC converge\n"
+ "- See DIDNOTCONVERGE in the Verilator manual");
+ } else {
+ __Vchange = _change_request(vlSymsp);
+ }
+ } while (VL_UNLIKELY(__Vchange));
+}
+
+void Vtb::_eval(Vtb__Syms* __restrict vlSymsp) {
+ VL_DEBUG_IF(VL_DBG_MSGF("+ Vtb::_eval\n"); );
+ Vtb* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
+}
+
+VL_INLINE_OPT QData Vtb::_change_request(Vtb__Syms* __restrict vlSymsp) {
+ VL_DEBUG_IF(VL_DBG_MSGF("+ Vtb::_change_request\n"); );
+ Vtb* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
+ // Body
+ return (vlTOPp->_change_request_1(vlSymsp));
+}
+
+VL_INLINE_OPT QData Vtb::_change_request_1(Vtb__Syms* __restrict vlSymsp) {
+ VL_DEBUG_IF(VL_DBG_MSGF("+ Vtb::_change_request_1\n"); );
+ Vtb* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
+ // Body
+ // Change detection
+ QData __req = false; // Logically a bool
+ __req |= ((vlTOPp->tb__DOT__val1 ^ vlTOPp->__Vchglast__TOP__tb__DOT__val1)
+ | (vlTOPp->tb__DOT__val2 ^ vlTOPp->__Vchglast__TOP__tb__DOT__val2));
+ VL_DEBUG_IF( if(__req && ((vlTOPp->tb__DOT__val1 ^ vlTOPp->__Vchglast__TOP__tb__DOT__val1))) VL_DBG_MSGF(" CHANGE: tb.v:10: tb.val1\n"); );
+ VL_DEBUG_IF( if(__req && ((vlTOPp->tb__DOT__val2 ^ vlTOPp->__Vchglast__TOP__tb__DOT__val2))) VL_DBG_MSGF(" CHANGE: tb.v:11: tb.val2\n"); );
+ // Final
+ vlTOPp->__Vchglast__TOP__tb__DOT__val1 = vlTOPp->tb__DOT__val1;
+ vlTOPp->__Vchglast__TOP__tb__DOT__val2 = vlTOPp->tb__DOT__val2;
+ return __req;
+}
+
+#ifdef VL_DEBUG
+void Vtb::_eval_debug_assertions() {
+ VL_DEBUG_IF(VL_DBG_MSGF("+ Vtb::_eval_debug_assertions\n"); );
+}
+#endif // VL_DEBUG
diff --git a/core/obj_dir/Vtb.d b/core/obj_dir/Vtb.d
new file mode 100644
index 0000000..65e0d9a
--- /dev/null
+++ b/core/obj_dir/Vtb.d
@@ -0,0 +1,3 @@
+Vtb.o: Vtb.cpp Vtb.h /usr/share/verilator/include/verilated_heavy.h \
+ /usr/share/verilator/include/verilated.h \
+ /usr/share/verilator/include/verilatedos.h Vtb__Syms.h
diff --git a/core/obj_dir/Vtb.h b/core/obj_dir/Vtb.h
new file mode 100644
index 0000000..e1386e3
--- /dev/null
+++ b/core/obj_dir/Vtb.h
@@ -0,0 +1,88 @@
+// Verilated -*- C++ -*-
+// DESCRIPTION: Verilator output: Primary design header
+//
+// This header should be included by all source files instantiating the design.
+// The class here is then constructed to instantiate the design.
+// See the Verilator manual for examples.
+
+#ifndef _VTB_H_
+#define _VTB_H_ // guard
+
+#include "verilated_heavy.h"
+
+//==========
+
+class Vtb__Syms;
+
+//----------
+
+VL_MODULE(Vtb) {
+ public:
+
+ // LOCAL SIGNALS
+ // Internals; generally not touched by application code
+ CData/*4:0*/ tb__DOT__read1;
+ CData/*4:0*/ tb__DOT__read2;
+ CData/*4:0*/ tb__DOT__write;
+ QData/*63:0*/ tb__DOT__val1;
+ QData/*63:0*/ tb__DOT__val2;
+ QData/*63:0*/ tb__DOT__write_data;
+ QData/*63:0*/ tb__DOT__r__DOT__reg_array[32];
+
+ // LOCAL VARIABLES
+ // Internals; generally not touched by application code
+ CData/*4:0*/ __Vtask_tb__DOT__r__DOT__write_reg__0__regid;
+ QData/*63:0*/ __Vtask_tb__DOT__r__DOT__write_reg__0__data;
+ QData/*63:0*/ __Vchglast__TOP__tb__DOT__val1;
+ QData/*63:0*/ __Vchglast__TOP__tb__DOT__val2;
+
+ // INTERNAL VARIABLES
+ // Internals; generally not touched by application code
+ Vtb__Syms* __VlSymsp; // Symbol table
+
+ // CONSTRUCTORS
+ private:
+ VL_UNCOPYABLE(Vtb); ///< Copying not allowed
+ public:
+ /// Construct the model; called by application code
+ /// The special name may be used to make a wrapper with a
+ /// single model invisible with respect to DPI scope names.
+ Vtb(const char* name = "TOP");
+ /// Destroy the model; called (often implicitly) by application code
+ ~Vtb();
+
+ // API METHODS
+ /// Evaluate the model. Application must call when inputs change.
+ void eval() { eval_step(); }
+ /// Evaluate when calling multiple units/models per time step.
+ void eval_step();
+ /// Evaluate at end of a timestep for tracing, when using eval_step().
+ /// Application must call after all eval() and before time changes.
+ void eval_end_step() {}
+ /// Simulation complete, run final blocks. Application must call on completion.
+ void final();
+
+ // INTERNAL METHODS
+ static void _eval_initial_loop(Vtb__Syms* __restrict vlSymsp);
+ void __Vconfigure(Vtb__Syms* symsp, bool first);
+ private:
+ static QData _change_request(Vtb__Syms* __restrict vlSymsp);
+ static QData _change_request_1(Vtb__Syms* __restrict vlSymsp);
+ void _ctor_var_reset() VL_ATTR_COLD;
+ public:
+ static void _eval(Vtb__Syms* __restrict vlSymsp);
+ private:
+#ifdef VL_DEBUG
+ void _eval_debug_assertions();
+#endif // VL_DEBUG
+ public:
+ static void _eval_initial(Vtb__Syms* __restrict vlSymsp) VL_ATTR_COLD;
+ static void _eval_settle(Vtb__Syms* __restrict vlSymsp) VL_ATTR_COLD;
+ static void _initial__TOP__1(Vtb__Syms* __restrict vlSymsp) VL_ATTR_COLD;
+ static void _settle__TOP__2(Vtb__Syms* __restrict vlSymsp) VL_ATTR_COLD;
+} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);
+
+//----------
+
+
+#endif // guard
diff --git a/core/obj_dir/Vtb.mk b/core/obj_dir/Vtb.mk
new file mode 100644
index 0000000..39f8e31
--- /dev/null
+++ b/core/obj_dir/Vtb.mk
@@ -0,0 +1,66 @@
+# Verilated -*- Makefile -*-
+# DESCRIPTION: Verilator output: Makefile for building Verilated archive or executable
+#
+# Execute this makefile from the object directory:
+# make -f Vtb.mk
+
+default: Vtb
+
+### Constants...
+# Perl executable (from $PERL)
+PERL = perl
+# Path to Verilator kit (from $VERILATOR_ROOT)
+VERILATOR_ROOT = /usr/share/verilator
+# SystemC include directory with systemc.h (from $SYSTEMC_INCLUDE)
+SYSTEMC_INCLUDE ?=
+# SystemC library directory with libsystemc.a (from $SYSTEMC_LIBDIR)
+SYSTEMC_LIBDIR ?=
+
+### Switches...
+# SystemC output mode? 0/1 (from --sc)
+VM_SC = 0
+# Legacy or SystemC output mode? 0/1 (from --sc)
+VM_SP_OR_SC = $(VM_SC)
+# Deprecated
+VM_PCLI = 1
+# Deprecated: SystemC architecture to find link library path (from $SYSTEMC_ARCH)
+VM_SC_TARGET_ARCH = linux
+
+### Vars...
+# Design prefix (from --prefix)
+VM_PREFIX = Vtb
+# Module prefix (from --prefix)
+VM_MODPREFIX = Vtb
+# User CFLAGS (from -CFLAGS on Verilator command line)
+VM_USER_CFLAGS = \
+
+# User LDLIBS (from -LDFLAGS on Verilator command line)
+VM_USER_LDLIBS = \
+
+# User .cpp files (from .cpp's on Verilator command line)
+VM_USER_CLASSES = \
+ Vtb \
+
+# User .cpp directories (from .cpp's on Verilator command line)
+VM_USER_DIR = \
+ . \
+
+
+### Default rules...
+# Include list of all generated classes
+include Vtb_classes.mk
+# Include global rules
+include $(VERILATOR_ROOT)/include/verilated.mk
+
+### Executable rules... (from --exe)
+VPATH += $(VM_USER_DIR)
+
+Vtb.o: Vtb.cpp
+ $(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
+
+### Link rules... (from --exe)
+Vtb: $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a $(VM_HIER_LIBS)
+ $(LINK) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) $(LIBS) $(SC_LIBS) -o $@
+
+
+# Verilated -*- Makefile -*-
diff --git a/core/obj_dir/Vtb__ALL.cpp b/core/obj_dir/Vtb__ALL.cpp
new file mode 100644
index 0000000..aa3c816
--- /dev/null
+++ b/core/obj_dir/Vtb__ALL.cpp
@@ -0,0 +1,5 @@
+// DESCRIPTION: Generated by verilator_includer via makefile
+#define VL_INCLUDE_OPT include
+#include "Vtb.cpp"
+#include "Vtb__Slow.cpp"
+#include "Vtb__Syms.cpp"
diff --git a/core/obj_dir/Vtb__ALL.d b/core/obj_dir/Vtb__ALL.d
new file mode 100644
index 0000000..e790eff
--- /dev/null
+++ b/core/obj_dir/Vtb__ALL.d
@@ -0,0 +1,5 @@
+Vtb__ALL.o: Vtb__ALL.cpp Vtb.cpp Vtb.h \
+ /usr/share/verilator/include/verilated_heavy.h \
+ /usr/share/verilator/include/verilated.h \
+ /usr/share/verilator/include/verilatedos.h Vtb__Syms.h Vtb__Slow.cpp \
+ Vtb__Syms.cpp
diff --git a/core/obj_dir/Vtb__Slow.cpp b/core/obj_dir/Vtb__Slow.cpp
new file mode 100644
index 0000000..2423d7b
--- /dev/null
+++ b/core/obj_dir/Vtb__Slow.cpp
@@ -0,0 +1,117 @@
+// Verilated -*- C++ -*-
+// DESCRIPTION: Verilator output: Design implementation internals
+// See Vtb.h for the primary calling header
+
+#include "Vtb.h"
+#include "Vtb__Syms.h"
+
+//==========
+
+VL_CTOR_IMP(Vtb) {
+ Vtb__Syms* __restrict vlSymsp = __VlSymsp = new Vtb__Syms(this, name());
+ Vtb* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
+ // Reset internal values
+
+ // Reset structure values
+ _ctor_var_reset();
+}
+
+void Vtb::__Vconfigure(Vtb__Syms* vlSymsp, bool first) {
+ if (false && first) {} // Prevent unused
+ this->__VlSymsp = vlSymsp;
+ if (false && this->__VlSymsp) {} // Prevent unused
+ Verilated::timeunit(-3);
+ Verilated::timeprecision(-3);
+}
+
+Vtb::~Vtb() {
+ VL_DO_CLEAR(delete __VlSymsp, __VlSymsp = nullptr);
+}
+
+void Vtb::_initial__TOP__1(Vtb__Syms* __restrict vlSymsp) {
+ VL_DEBUG_IF(VL_DBG_MSGF("+ Vtb::_initial__TOP__1\n"); );
+ Vtb* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
+ // Body
+ VL_WRITEF("%10# %10#\n",32,(IData)(vlTOPp->tb__DOT__val1),
+ 32,(IData)(vlTOPp->tb__DOT__val2));
+ vlTOPp->tb__DOT__write = 2U;
+ vlTOPp->tb__DOT__write_data = 0x14ULL;
+ vlTOPp->tb__DOT__read1 = 1U;
+ vlTOPp->tb__DOT__read2 = 2U;
+ VL_WRITEF("%10# %10#\n",32,(IData)(vlTOPp->tb__DOT__val1),
+ 32,(IData)(vlTOPp->tb__DOT__val2));
+ VL_STOP_MT("tb.v", 48, "");
+ vlTOPp->__Vtask_tb__DOT__r__DOT__write_reg__0__data = 0x14ULL;
+ vlTOPp->__Vtask_tb__DOT__r__DOT__write_reg__0__regid = 2U;
+ vlTOPp->tb__DOT__r__DOT__reg_array[2U] = 0x14ULL;
+}
+
+void Vtb::_settle__TOP__2(Vtb__Syms* __restrict vlSymsp) {
+ VL_DEBUG_IF(VL_DBG_MSGF("+ Vtb::_settle__TOP__2\n"); );
+ Vtb* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
+ // Variables
+ CData/*4:0*/ __Vfunc_tb__DOT__r__DOT__read_reg__1__regid;
+ CData/*4:0*/ __Vfunc_tb__DOT__r__DOT__read_reg__2__regid;
+ QData/*63:0*/ __Vfunc_tb__DOT__r__DOT__read_reg__1__Vfuncout;
+ QData/*63:0*/ __Vfunc_tb__DOT__r__DOT__read_reg__2__Vfuncout;
+ // Body
+ vlTOPp->__Vtask_tb__DOT__r__DOT__write_reg__0__data
+ = vlTOPp->tb__DOT__write_data;
+ vlTOPp->__Vtask_tb__DOT__r__DOT__write_reg__0__regid
+ = vlTOPp->tb__DOT__write;
+ vlTOPp->tb__DOT__r__DOT__reg_array[vlTOPp->__Vtask_tb__DOT__r__DOT__write_reg__0__regid]
+ = vlTOPp->__Vtask_tb__DOT__r__DOT__write_reg__0__data;
+ __Vfunc_tb__DOT__r__DOT__read_reg__1__regid = vlTOPp->tb__DOT__read1;
+ __Vfunc_tb__DOT__r__DOT__read_reg__1__Vfuncout
+ = vlTOPp->tb__DOT__r__DOT__reg_array[__Vfunc_tb__DOT__r__DOT__read_reg__1__regid];
+ __Vfunc_tb__DOT__r__DOT__read_reg__2__regid = vlTOPp->tb__DOT__read2;
+ __Vfunc_tb__DOT__r__DOT__read_reg__2__Vfuncout
+ = vlTOPp->tb__DOT__r__DOT__reg_array[__Vfunc_tb__DOT__r__DOT__read_reg__2__regid];
+ __Vfunc_tb__DOT__r__DOT__read_reg__1__regid = vlTOPp->tb__DOT__read1;
+ __Vfunc_tb__DOT__r__DOT__read_reg__1__Vfuncout
+ = vlTOPp->tb__DOT__r__DOT__reg_array[__Vfunc_tb__DOT__r__DOT__read_reg__1__regid];
+ vlTOPp->tb__DOT__val1 = __Vfunc_tb__DOT__r__DOT__read_reg__1__Vfuncout;
+ __Vfunc_tb__DOT__r__DOT__read_reg__2__regid = vlTOPp->tb__DOT__read2;
+ __Vfunc_tb__DOT__r__DOT__read_reg__2__Vfuncout
+ = vlTOPp->tb__DOT__r__DOT__reg_array[__Vfunc_tb__DOT__r__DOT__read_reg__2__regid];
+ vlTOPp->tb__DOT__val2 = __Vfunc_tb__DOT__r__DOT__read_reg__2__Vfuncout;
+}
+
+void Vtb::_eval_initial(Vtb__Syms* __restrict vlSymsp) {
+ VL_DEBUG_IF(VL_DBG_MSGF("+ Vtb::_eval_initial\n"); );
+ Vtb* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
+ // Body
+ vlTOPp->_initial__TOP__1(vlSymsp);
+}
+
+void Vtb::final() {
+ VL_DEBUG_IF(VL_DBG_MSGF("+ Vtb::final\n"); );
+ // Variables
+ Vtb__Syms* __restrict vlSymsp = this->__VlSymsp;
+ Vtb* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
+}
+
+void Vtb::_eval_settle(Vtb__Syms* __restrict vlSymsp) {
+ VL_DEBUG_IF(VL_DBG_MSGF("+ Vtb::_eval_settle\n"); );
+ Vtb* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
+ // Body
+ vlTOPp->_settle__TOP__2(vlSymsp);
+}
+
+void Vtb::_ctor_var_reset() {
+ VL_DEBUG_IF(VL_DBG_MSGF("+ Vtb::_ctor_var_reset\n"); );
+ // Body
+ tb__DOT__read1 = VL_RAND_RESET_I(5);
+ tb__DOT__read2 = VL_RAND_RESET_I(5);
+ tb__DOT__val1 = VL_RAND_RESET_Q(64);
+ tb__DOT__val2 = VL_RAND_RESET_Q(64);
+ tb__DOT__write = VL_RAND_RESET_I(5);
+ tb__DOT__write_data = VL_RAND_RESET_Q(64);
+ for (int __Vi0=0; __Vi0<32; ++__Vi0) {
+ tb__DOT__r__DOT__reg_array[__Vi0] = VL_RAND_RESET_Q(64);
+ }
+ __Vtask_tb__DOT__r__DOT__write_reg__0__regid = VL_RAND_RESET_I(5);
+ __Vtask_tb__DOT__r__DOT__write_reg__0__data = VL_RAND_RESET_Q(64);
+ __Vchglast__TOP__tb__DOT__val1 = VL_RAND_RESET_Q(64);
+ __Vchglast__TOP__tb__DOT__val2 = VL_RAND_RESET_Q(64);
+}
diff --git a/core/obj_dir/Vtb__Syms.cpp b/core/obj_dir/Vtb__Syms.cpp
new file mode 100644
index 0000000..5f8019a
--- /dev/null
+++ b/core/obj_dir/Vtb__Syms.cpp
@@ -0,0 +1,21 @@
+// Verilated -*- C++ -*-
+// DESCRIPTION: Verilator output: Symbol table implementation internals
+
+#include "Vtb__Syms.h"
+#include "Vtb.h"
+
+
+
+// FUNCTIONS
+Vtb__Syms::Vtb__Syms(Vtb* topp, const char* namep)
+ // Setup locals
+ : __Vm_namep(namep)
+ , __Vm_didInit(false)
+ // Setup submodule names
+{
+ // Pointer to top level
+ TOPp = topp;
+ // Setup each module's pointers to their submodules
+ // Setup each module's pointer back to symbol table (for public functions)
+ TOPp->__Vconfigure(this, true);
+}
diff --git a/core/obj_dir/Vtb__Syms.h b/core/obj_dir/Vtb__Syms.h
new file mode 100644
index 0000000..3d4db64
--- /dev/null
+++ b/core/obj_dir/Vtb__Syms.h
@@ -0,0 +1,35 @@
+// Verilated -*- C++ -*-
+// DESCRIPTION: Verilator output: Symbol table internal header
+//
+// Internal details; most calling programs do not need this header,
+// unless using verilator public meta comments.
+
+#ifndef _VTB__SYMS_H_
+#define _VTB__SYMS_H_ // guard
+
+#include "verilated_heavy.h"
+
+// INCLUDE MODULE CLASSES
+#include "Vtb.h"
+
+// SYMS CLASS
+class Vtb__Syms : public VerilatedSyms {
+ public:
+
+ // LOCAL STATE
+ const char* __Vm_namep;
+ bool __Vm_didInit;
+
+ // SUBCELL STATE
+ Vtb* TOPp;
+
+ // CREATORS
+ Vtb__Syms(Vtb* topp, const char* namep);
+ ~Vtb__Syms() = default;
+
+ // METHODS
+ inline const char* name() { return __Vm_namep; }
+
+} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);
+
+#endif // guard
diff --git a/core/obj_dir/Vtb__ver.d b/core/obj_dir/Vtb__ver.d
new file mode 100644
index 0000000..3e2c57e
--- /dev/null
+++ b/core/obj_dir/Vtb__ver.d
@@ -0,0 +1 @@
+obj_dir/Vtb.cpp obj_dir/Vtb.h obj_dir/Vtb.mk obj_dir/Vtb__Slow.cpp obj_dir/Vtb__Syms.cpp obj_dir/Vtb__Syms.h obj_dir/Vtb__ver.d obj_dir/Vtb_classes.mk : /usr/bin/verilator_bin /usr/bin/verilator_bin regs.v tb.v
diff --git a/core/obj_dir/Vtb__verFiles.dat b/core/obj_dir/Vtb__verFiles.dat
new file mode 100644
index 0000000..5cfe1ca
--- /dev/null
+++ b/core/obj_dir/Vtb__verFiles.dat
@@ -0,0 +1,14 @@
+# DESCRIPTION: Verilator output: Timestamp data for --skip-identical. Delete at will.
+C "-cc -Wall -Wno-UNOPTFLAT -Wno-STMTDLY -Wno-UNDRIVEN -Wno-UNUSED -Wno-IGNOREDRETURN tb.v --exe --build Vtb.cpp"
+S 8158392 13113442 1608512454 749492301 1607455047 0 "/usr/bin/verilator_bin"
+T 3853 9588217 1612668578 766783891 1612668578 766783891 "obj_dir/Vtb.cpp"
+T 2966 9588210 1612668578 766783891 1612668578 766783891 "obj_dir/Vtb.h"
+T 1742 9588708 1612668578 766783891 1612668578 766783891 "obj_dir/Vtb.mk"
+T 4812 9588212 1612668578 766783891 1612668578 766783891 "obj_dir/Vtb__Slow.cpp"
+T 524 9587930 1612668578 766783891 1612668578 766783891 "obj_dir/Vtb__Syms.cpp"
+T 774 9587948 1612668578 766783891 1612668578 766783891 "obj_dir/Vtb__Syms.h"
+T 213 9588712 1612668578 766783891 1612668578 766783891 "obj_dir/Vtb__ver.d"
+T 0 0 1612668578 766783891 1612668578 766783891 "obj_dir/Vtb__verFiles.dat"
+T 1576 9588704 1612668578 766783891 1612668578 766783891 "obj_dir/Vtb_classes.mk"
+S 1031 9587412 1612667707 796752074 1612667707 796752074 "regs.v"
+S 1009 9587945 1612667697 96751683 1612667697 96751683 "tb.v"
diff --git a/core/obj_dir/Vtb_classes.mk b/core/obj_dir/Vtb_classes.mk
new file mode 100644
index 0000000..f3651f2
--- /dev/null
+++ b/core/obj_dir/Vtb_classes.mk
@@ -0,0 +1,49 @@
+# Verilated -*- Makefile -*-
+# DESCRIPTION: Verilator output: Make include file with class lists
+#
+# This file lists generated Verilated files, for including in higher level makefiles.
+# See Vtb.mk for the caller.
+
+### Switches...
+# C11 constructs required? 0/1 (always on now)
+VM_C11 = 1
+# Coverage output mode? 0/1 (from --coverage)
+VM_COVERAGE = 0
+# Parallel builds? 0/1 (from --output-split)
+VM_PARALLEL_BUILDS = 0
+# Threaded output mode? 0/1/N threads (from --threads)
+VM_THREADS = 0
+# Tracing output mode? 0/1 (from --trace/--trace-fst)
+VM_TRACE = 0
+# Tracing output mode in FST format? 0/1 (from --trace-fst)
+VM_TRACE_FST = 0
+# Tracing threaded output mode? 0/1/N threads (from --trace-thread)
+VM_TRACE_THREADS = 0
+# Separate FST writer thread? 0/1 (from --trace-fst with --trace-thread > 0)
+VM_TRACE_FST_WRITER_THREAD = 0
+
+### Object file lists...
+# Generated module classes, fast-path, compile with highest optimization
+VM_CLASSES_FAST += \
+ Vtb \
+
+# Generated module classes, non-fast-path, compile with low/medium optimization
+VM_CLASSES_SLOW += \
+ Vtb__Slow \
+
+# Generated support classes, fast-path, compile with highest optimization
+VM_SUPPORT_FAST += \
+
+# Generated support classes, non-fast-path, compile with low/medium optimization
+VM_SUPPORT_SLOW += \
+ Vtb__Syms \
+
+# Global classes, need linked once per executable, fast-path, compile with highest optimization
+VM_GLOBAL_FAST += \
+ verilated \
+
+# Global classes, need linked once per executable, non-fast-path, compile with low/medium optimization
+VM_GLOBAL_SLOW += \
+
+
+# Verilated -*- Makefile -*-
diff --git a/core/obj_dir/verilated.d b/core/obj_dir/verilated.d
new file mode 100644
index 0000000..8efb1e5
--- /dev/null
+++ b/core/obj_dir/verilated.d
@@ -0,0 +1,8 @@
+verilated.o: /usr/share/verilator/include/verilated.cpp \
+ /usr/share/verilator/include/verilatedos.h \
+ /usr/share/verilator/include/verilated_imp.h \
+ /usr/share/verilator/include/verilated.h \
+ /usr/share/verilator/include/verilated_heavy.h \
+ /usr/share/verilator/include/verilated_syms.h \
+ /usr/share/verilator/include/verilated_sym_props.h \
+ /usr/share/verilator/include/verilated_config.h
diff --git a/core/regs.v b/core/regs.v
new file mode 100644
index 0000000..7d2025c
--- /dev/null
+++ b/core/regs.v
@@ -0,0 +1,42 @@
+`timescale 1ms/1ms
+
+module regs(
+ input wire clk, reset,
+ input wire [4:0] reg_read1, [4:0] reg_read2,
+ input wire [4:0] reg_write,
+ input wire [63:0] write_data,
+ input wire write_en,
+ output reg [63:0] reg_read1_out,
+ output reg [63:0] reg_read2_out
+ );
+
+ reg [63:0] reg_array [31:0]; // 2D array of all regs, including pc
+
+ function write_reg;
+ input reg [4:0] regid;
+ input reg [63:0] data;
+ begin
+ // if (regid > 0 || regid <= 32) // Must not write <x0 and x32>
+ reg_array[regid] = data;
+ write_reg = 1;
+ end
+ endfunction // write_reg
+
+ function [63:0] read_reg;
+ input reg [4:0] regid;
+ begin
+ read_reg = reg_array[regid];
+ end
+ endfunction // read_reg
+
+ always @(write_en) begin
+ write_reg(reg_write, write_data);
+ end
+
+ always @* begin
+ assign reg_read1_out = read_reg(reg_read1);
+ assign reg_read2_out = read_reg(reg_read2);
+ end
+
+
+endmodule // regs
diff --git a/core/tb.v b/core/tb.v
new file mode 100644
index 0000000..b6f4645
--- /dev/null
+++ b/core/tb.v
@@ -0,0 +1,54 @@
+// Testbench for CPU components
+
+`timescale 1ms/1ms
+
+
+module tb;
+ wire clk, reset;
+ reg [4:0] read1;
+ reg [4:0] read2;
+ wire [63:0] val1;
+ wire [63:0] val2;
+ reg [4:0] write;
+ reg [63:0] write_data;
+ reg write_en;
+
+ regs r
+ (.clk(clk), .reset(reset),
+ .reg_read1(read1), .reg_read2(read2),
+ .reg_write(write), .write_data(write_data), .write_en(write_en),
+ .reg_read1_out(val1), .reg_read2_out(val2)
+ );
+
+ initial begin;
+ #100;
+ read1 = 1;
+ read2 = 2;
+ $display("%d %d", val1[31:0], val2[31:0]);
+ #200;
+ write = 1;
+ write_data = 10;
+ write_en = 1;
+ #250;
+ write_en = 0;
+ #300;
+ write = 2;
+ write_data = 20;
+ write_en = 1;
+ #350;
+ write_en = 0;
+ #400;
+ read1 = 3;
+ read2 = 4;
+ #450
+ read1 = 1;
+ read2 = 2;
+ $display("%d %d", val1[31:0], val2[31:0]);
+ #500;
+ $stop;
+ end
+
+
+endmodule // regs_tb
+
+