From f95a85de0082010e4af83e26e99299d601bb48d6 Mon Sep 17 00:00:00 2001
From: Steven Le Rouzic <steven.lerouzic@gmail.com>
Date: Mon, 13 May 2024 00:04:44 +0200
Subject: Some work on CSR

---
 emulator/bits.h                     |  15 ++
 emulator/csr.c                      |  51 ++++++
 emulator/csr.h                      |  36 ++++
 emulator/csr_machine_information.c  |  21 +++
 emulator/csr_machine_trap_setup.c   |  19 ++
 emulator/csr_unpriv_counter_timer.c |  33 ++++
 emulator/hart.c                     | 348 +++++++++++++-----------------------
 emulator/hart.h                     |  25 ++-
 emulator/instruction.h              |  80 +++++++++
 emulator/lib.c                      |   4 +
 emulator/main.c                     |   3 +-
 11 files changed, 407 insertions(+), 228 deletions(-)
 create mode 100644 emulator/bits.h
 create mode 100644 emulator/csr.c
 create mode 100644 emulator/csr.h
 create mode 100644 emulator/csr_machine_information.c
 create mode 100644 emulator/csr_machine_trap_setup.c
 create mode 100644 emulator/csr_unpriv_counter_timer.c
 create mode 100644 emulator/instruction.h

(limited to 'emulator')

diff --git a/emulator/bits.h b/emulator/bits.h
new file mode 100644
index 0000000..8d4bdff
--- /dev/null
+++ b/emulator/bits.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <stdint.h>
+
+static inline uint32_t sign_extend(uint32_t word, uint32_t size)
+{
+    const uint32_t mask = 1U << (size - 1);
+    return (word ^ mask) - mask;
+}
+
+static inline uint64_t sign_extend_64(uint64_t word, uint32_t size)
+{
+    const uint64_t mask = 1ULL << (size - 1);
+    return (word ^ mask) - mask;
+}
diff --git a/emulator/csr.c b/emulator/csr.c
new file mode 100644
index 0000000..d2527cf
--- /dev/null
+++ b/emulator/csr.c
@@ -0,0 +1,51 @@
+#include "emulator/csr.h"
+
+#include "emulator/hart.h"
+
+#include <stdbool.h>
+
+static inline uint8_t csr_priv(uint16_t id)
+{
+    return (id & 0x300) >> 8;
+}
+
+static inline bool csr_writable(uint16_t id)
+{
+    return (id & 0xC00) == 0xC00;
+}
+
+uint32_t csr_action(Hart* hart, uint16_t id, uint32_t value, enum CsrAction action)
+{
+    // @Todo exceptions (bad access (rw, level), non existent, etc)
+    if (id > 4096 || hart->csrs[id].action)
+    {
+        // @Todo
+        return 0;
+    }
+
+    if (action > CSR_R && csr_writable(id))
+    {
+        // @Todo
+        return 0;
+    }
+
+    if (csr_priv(id) > hart->priv)
+    {
+        // @Todo
+        return 0;
+    }
+
+    return hart->csrs[id].action(hart, value, action);
+}
+
+void csr_init_unpriv_counter_timer(Hart* hart);
+void csr_init_machine_trap_setup(Hart* hart);
+void csr_init_machine_information(Hart* hart);
+
+void csr_init(Hart* hart)
+{
+    csr_init_unpriv_counter_timer(hart);
+    csr_init_machine_trap_setup(hart);
+    csr_init_machine_information(hart);
+}
+
diff --git a/emulator/csr.h b/emulator/csr.h
new file mode 100644
index 0000000..89452b0
--- /dev/null
+++ b/emulator/csr.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <stdint.h>
+
+typedef struct Hart Hart;
+
+#define CSR_CYCLE        0xC00
+#define CSR_CYCLEH       0xC80
+#define CSR_INSTRET      0xC02
+#define CSR_INSTRETH     0xC82
+#define CSR_TIME         0xC01
+#define CSR_TIMEH        0xC81
+
+#define CSR_MVENDORID    0xF11
+#define CSR_MARCHID      0xF12
+#define CSR_MIMPID       0xF13
+#define CSR_MHARTID      0xF14
+
+#define CSR_MISA         0x301
+
+enum CsrAction
+{
+    CSR_R    = 0,
+    CSR_W    = 1,
+    CSR_RW   = 3,
+    CSR_RC   = 5,
+    CSR_RS   = 7,
+};
+
+struct Csr
+{
+    uint32_t (*action)(Hart* hart, uint32_t value_mask, enum CsrAction action);
+};
+typedef struct Csr Csr;
+
+uint32_t csr_action(Hart* hart, uint16_t id, uint32_t value, enum CsrAction action);
diff --git a/emulator/csr_machine_information.c b/emulator/csr_machine_information.c
new file mode 100644
index 0000000..38a33a1
--- /dev/null
+++ b/emulator/csr_machine_information.c
@@ -0,0 +1,21 @@
+#include "emulator/csr.h"
+
+#include "emulator/hart.h"
+
+static uint32_t csr_minfo_zero(Hart* hart, uint32_t v, enum CsrAction a)
+{
+    return 0;
+}
+
+static uint32_t csr_mhartid(Hart* hart, uint32_t v, enum CsrAction a)
+{
+    return hart->hartid;
+}
+
+void csr_init_machine_information(Hart* hart)
+{
+    hart->csrs[CSR_MVENDORID].action = csr_minfo_zero;
+    hart->csrs[CSR_MARCHID].action = csr_minfo_zero;
+    hart->csrs[CSR_MIMPID].action = csr_minfo_zero;
+    hart->csrs[CSR_MHARTID].action = csr_mhartid;
+}
diff --git a/emulator/csr_machine_trap_setup.c b/emulator/csr_machine_trap_setup.c
new file mode 100644
index 0000000..385460f
--- /dev/null
+++ b/emulator/csr_machine_trap_setup.c
@@ -0,0 +1,19 @@
+#include "emulator/csr.h"
+
+#include "emulator/hart.h"
+
+static uint32_t csr_misa(Hart* hart, uint32_t v, enum CsrAction a)
+{
+    uint32_t misa = 0;
+    misa |= 1 << 30; // 32-bit
+    misa |= 1 << 8;  // Base ISA
+    misa |= 1 << 12; // M extension
+    misa |= 1 << 18; // Supervisor mode
+    misa |= 1 << 20; // User mode
+    return misa;
+}
+
+void csr_init_machine_trap_setup(Hart* hart)
+{
+    hart->csrs[CSR_MISA].action = csr_misa;
+}
diff --git a/emulator/csr_unpriv_counter_timer.c b/emulator/csr_unpriv_counter_timer.c
new file mode 100644
index 0000000..e474520
--- /dev/null
+++ b/emulator/csr_unpriv_counter_timer.c
@@ -0,0 +1,33 @@
+#include "emulator/csr.h"
+
+#include "emulator/hart.h"
+
+static uint32_t csr_cycle(Hart* hart, uint32_t v, enum CsrAction a)
+{
+    return hart->instret & 0xFFFFFFFF;
+}
+
+static uint32_t csr_cycleh(Hart* hart, uint32_t v, enum CsrAction a)
+{
+    return hart->instret >> 32;
+}
+
+static uint32_t csr_time(Hart* hart, uint32_t v, enum CsrAction a)
+{
+    return hart->time & 0xFFFFFFFF;
+}
+
+static uint32_t csr_timeh(Hart* hart, uint32_t v, enum CsrAction a)
+{
+    return hart->time >> 32;
+}
+
+void csr_init_unpriv_counter_timer(Hart* hart)
+{
+    hart->csrs[CSR_CYCLE].action = csr_cycle;
+    hart->csrs[CSR_CYCLEH].action = csr_cycleh;
+    hart->csrs[CSR_INSTRET].action = csr_cycle;
+    hart->csrs[CSR_INSTRETH].action = csr_cycleh;
+    hart->csrs[CSR_TIME].action = csr_time;
+    hart->csrs[CSR_TIMEH].action = csr_timeh;
+}
diff --git a/emulator/hart.c b/emulator/hart.c
index 297148b..efa0556 100644
--- a/emulator/hart.c
+++ b/emulator/hart.c
@@ -1,129 +1,106 @@
 #include "emulator/hart.h"
 
+#include "emulator/bits.h"
+#include "emulator/instruction.h"
+#include "emulator/csr.h"
+
 #include <stdio.h>
 #include <inttypes.h>
 #include <assert.h>
 #include <stdbool.h>
 #include <string.h>
 
-#define REG_ZERO 0 
-#define REG_RA   1 
-#define REG_SP   2 
-#define REG_GP   3 
-#define REG_TP   4 
-#define REG_T0   5 
-#define REG_T1   6 
-#define REG_T2   7 
-#define REG_S0   8 
-#define REG_S1   9 
-#define REG_A0   10 
-#define REG_A1   11 
-#define REG_A2   12 
-#define REG_A3   13 
-#define REG_A4   14 
-#define REG_A5   15 
-#define REG_A6   16 
-#define REG_A7   17 
-#define REG_S2   18 
-#define REG_S3   19 
-#define REG_S4   20 
-#define REG_S5   21 
-#define REG_S6   22 
-#define REG_S7   23 
-#define REG_S8   24 
-#define REG_S9   25 
-#define REG_S10  26 
-#define REG_S11  27 
-#define REG_T3   28 
-#define REG_T4   29 
-#define REG_T5   30 
-#define REG_T6   31 
-
-static inline uint32_t sign_extend(uint32_t word, uint32_t size)
+#define REG_ZERO 0
+#define REG_RA   1
+#define REG_SP   2
+#define REG_GP   3
+#define REG_TP   4
+#define REG_T0   5
+#define REG_T1   6
+#define REG_T2   7
+#define REG_S0   8
+#define REG_S1   9
+#define REG_A0   10
+#define REG_A1   11
+#define REG_A2   12
+#define REG_A3   13
+#define REG_A4   14
+#define REG_A5   15
+#define REG_A6   16
+#define REG_A7   17
+#define REG_S2   18
+#define REG_S3   19
+#define REG_S4   20
+#define REG_S5   21
+#define REG_S6   22
+#define REG_S7   23
+#define REG_S8   24
+#define REG_S9   25
+#define REG_S10  26
+#define REG_S11  27
+#define REG_T3   28
+#define REG_T4   29
+#define REG_T5   30
+#define REG_T6   31
+
+static void handle_ecall(Hart* hart)
 {
-    const uint32_t mask = 1U << (size - 1);
-    return (word ^ mask) - mask;
 }
 
-static inline uint64_t sign_extend_64(uint64_t word, uint32_t size)
+static inline uint32_t load_size(Hart* hart, uint32_t address, uint32_t size)
 {
-    const uint64_t mask = 1ULL << (size - 1);
-    return (word ^ mask) - mask;
+    if ((address & 0x80000000) == 0)
+    {
+        assert(address + size < hart->mem_size);
+        uint32_t value = 0;
+        memcpy(&value, hart->mem + address, size);
+        return value;
+    }
+    
+    return 0;
 }
 
-struct Instruction
+static uint32_t load_byte(Hart* hart, uint32_t address)
 {
-    uint8_t  opcode;
-    uint8_t  rs1;
-    uint8_t  rs2;
-    uint8_t  rd;
-    uint8_t  funct3;
-    uint8_t  funct7;
-    uint32_t imm;
-};
-typedef struct Instruction Instruction;
-
-static Instruction decode_r_type(uint32_t word)
+    return load_size(hart, address, 1);
+}
+
+static uint32_t load_half(Hart* hart, uint32_t address)
 {
-    Instruction instruction = {0};
-    instruction.opcode =  word        & 0x7F;
-    instruction.rd     = (word >> 7)  & 0x1F;
-    instruction.funct3 = (word >> 12) & 0x07;
-    instruction.rs1    = (word >> 15) & 0x1F;
-    instruction.rs2    = (word >> 20) & 0x1F;
-    instruction.funct7 =  word >> 25;
-    return instruction;
-};
-
-static Instruction decode_i_type(uint32_t word)
+    return load_size(hart, address, 2);
+}
+
+static uint32_t load_word(Hart* hart, uint32_t address)
 {
-    Instruction instruction = {0};
-    instruction.opcode =  word        & 0x7F;
-    instruction.rd     = (word >> 7)  & 0x1F;
-    instruction.funct3 = (word >> 12) & 0x07;
-    instruction.rs1    = (word >> 15) & 0x1F;
-    instruction.imm    = sign_extend(word >> 20, 12);
-    return instruction;
-};
-
-static Instruction decode_s_type(uint32_t word)
+    return load_size(hart, address, 4);
+}
+
+static inline void store_size(Hart* hart, uint32_t address, uint32_t value, uint32_t size)
 {
-    Instruction instruction = {0};
-    instruction.opcode =  word        & 0x7F;
-    instruction.funct3 = (word >> 12) & 0x07;
-    instruction.rs1    = (word >> 15) & 0x1F;
-    instruction.rs2    = (word >> 20) & 0x1F;
-    instruction.imm    = sign_extend(((word >> 7) & 0x1F) | (word >> 25), 12);
-    return instruction;
-};
-
-static Instruction decode_b_type(uint32_t word)
+    if ((address & 0x80000000) == 0)
+    {
+        assert(address + size < hart->mem_size);
+        memcpy(hart->mem + address, &value, size);
+    }
+    else if (address == 0x80000000)
+    {
+        fwrite(&value, 1, size, stdout);
+    }
+}
+
+static void store_byte(Hart* hart, uint32_t address, uint8_t value)
 {
-    Instruction instruction = decode_s_type(word);
-    instruction.imm = ((instruction.imm << 11) & 0x800) | (instruction.imm & 0xfffff7ff);
-    return instruction;
-};
+    store_size(hart, address, value, 1);
+}
 
-static Instruction decode_u_type(uint32_t word)
+static void store_half(Hart* hart, uint32_t address, uint16_t value)
 {
-    Instruction instruction = {0};
-    instruction.opcode =  word        & 0x7F;
-    instruction.rd     = (word >> 7)  & 0x1F;
-    instruction.imm    =  word        & 0xFFFFF000;
-    return instruction;
-};
-
-static Instruction decode_j_type(uint32_t word)
+    store_size(hart, address, value, 2);
+}
+
+static void store_word(Hart* hart, uint32_t address, uint32_t value)
 {
-    Instruction instruction = {0};
-    instruction.opcode =  word        & 0x7F;
-    instruction.rd     = (word >> 7)  & 0x1F;
-    instruction.imm    = sign_extend(
-        ((word & 0x80000000) >> 11) |
-        ((word & 0x000FF000) >> 0)  |
-        ((word & 0x00100000) >> 9)  |
-        ((word & 0x7FE00000) >> 20), 21);
-    return instruction;
+    store_size(hart, address, value, 4);
 }
 
 static void execute_op_imm(Hart* hart, uint32_t instruction)
@@ -338,62 +315,6 @@ static void execute_branch(Hart* hart, uint32_t instruction)
     }
 }
 
-static inline uint32_t load_size(Hart* hart, uint32_t address, uint32_t size)
-{
-    if ((address & 0x80000000) == 0)
-    {
-        assert(address + size < hart->mem_size);
-        uint32_t value = 0;
-        memcpy(&value, hart->mem + address, size);
-        return value;
-    }
-    
-    return 0;
-}
-
-static uint32_t load_byte(Hart* hart, uint32_t address)
-{
-    return load_size(hart, address, 1);
-}
-
-static uint32_t load_half(Hart* hart, uint32_t address)
-{
-    return load_size(hart, address, 2);
-}
-
-static uint32_t load_word(Hart* hart, uint32_t address)
-{
-    return load_size(hart, address, 4);
-}
-
-static inline void store_size(Hart* hart, uint32_t address, uint32_t value, uint32_t size)
-{
-    if ((address & 0x80000000) == 0)
-    {
-        assert(address + size < hart->mem_size);
-        memcpy(hart->mem + address, &value, size);
-    }
-    else if (address == 0x80000000)
-    {
-        fwrite(&value, 1, size, stdout);
-    }
-}
-
-static void store_byte(Hart* hart, uint32_t address, uint8_t value)
-{
-    store_size(hart, address, value, 1);
-}
-
-static void store_half(Hart* hart, uint32_t address, uint16_t value)
-{
-    store_size(hart, address, value, 2);
-}
-
-static void store_word(Hart* hart, uint32_t address, uint32_t value)
-{
-    store_size(hart, address, value, 4);
-}
-
 static void execute_load(Hart* hart, uint32_t instruction)
 {
     const Instruction inst = decode_i_type(instruction);
@@ -462,43 +383,6 @@ static void execute_misc_mem(Hart* hart, uint32_t instruction)
     }
 }
 
-static void handle_ecall(Hart* hart)
-{
-    if (hart->regs[REG_A0] == 0)
-    {
-        hart->halted = true;
-    }
-}
-
-static uint32_t crs_read(Hart* hart, uint16_t id)
-{
-    // @Todo
-    return 0;
-}
-
-static void crs_write(Hart* hart, uint16_t id, uint32_t new_value)
-{
-    // @Todo
-}
-
-static uint32_t crs_read_write(Hart* hart, uint16_t id, uint32_t new_value)
-{
-    // @Todo
-    return 0;
-}
-
-static uint32_t crs_read_clear(Hart* hart, uint16_t id, uint32_t mask)
-{
-    // @Todo
-    return 0;
-}
-
-static uint32_t crs_read_set(Hart* hart, uint16_t id, uint32_t mask)
-{
-    // @Todo
-    return 0;
-}
-
 static void execute_system(Hart* hart, uint32_t instruction)
 {
     const Instruction inst = decode_i_type(instruction);
@@ -528,32 +412,32 @@ static void execute_system(Hart* hart, uint32_t instruction)
             }
             break;
         }
-        case 1: // CRSRW
+        case 1: // CSRRW
         {
-            uint16_t crs_id = inst.imm & 0xFFF;
+            uint16_t csr_id = inst.imm & 0xFFF;
             
             if (inst.rd == 0)
             {
-                crs_write(hart, crs_id, hart->regs[inst.rs1]);
+                csr_action(hart, csr_id, hart->regs[inst.rs1], CSR_W);
             }
             else
             {
-                hart->regs[inst.rd] = crs_read_write(hart, crs_id, hart->regs[inst.rs1]);
+                hart->regs[inst.rd] = csr_action(hart, csr_id, hart->regs[inst.rs1], CSR_RW);
             }
             break;
         }
-        case 2: // CRSRS
+        case 2: // CSRRS
         {
-            uint16_t crs_id = inst.imm & 0xFFF;
+            uint16_t csr_id = inst.imm & 0xFFF;
             uint32_t value = 0;
             
             if (inst.rs1 == 0)
             {
-                value = crs_read(hart, crs_id);
+                value = csr_action(hart, csr_id, 0, CSR_R);
             }
             else
             {
-                value = crs_read_set(hart, crs_id, hart->regs[inst.rs1]);
+                value = csr_action(hart, csr_id, hart->regs[inst.rs1], CSR_RS);
             }
             
             if (inst.rd != 0)
@@ -562,18 +446,18 @@ static void execute_system(Hart* hart, uint32_t instruction)
             }
             break;
         }
-        case 3: // CRSRC
+        case 3: // CSRRC
         {
-            uint16_t crs_id = inst.imm & 0xFFF;
+            uint16_t csr_id = inst.imm & 0xFFF;
             uint32_t value = 0;
             
             if (inst.rs1 == 0)
             {
-                value = crs_read(hart, crs_id);
+                value = csr_action(hart, csr_id, 0, CSR_R);
             }
             else
             {
-                value = crs_read_clear(hart, crs_id, hart->regs[inst.rs1]);
+                value = csr_action(hart, csr_id, hart->regs[inst.rs1], CSR_RC);
             }
             
             if (inst.rd != 0)
@@ -582,32 +466,32 @@ static void execute_system(Hart* hart, uint32_t instruction)
             }
             break;
         }
-        case 5: // CRSRWI
+        case 5: // CSRRWI
         {
-            uint16_t crs_id = inst.imm & 0xFFF;
+            uint16_t csr_id = inst.imm & 0xFFF;
             
             if (inst.rd == 0)
             {
-                crs_write(hart, crs_id, inst.rs1);
+                csr_action(hart, csr_id, inst.rs1, CSR_W);
             }
             else
             {
-                hart->regs[inst.rd] = crs_read_write(hart, crs_id, inst.rs1);
+                hart->regs[inst.rd] = csr_action(hart, csr_id, inst.rs1, CSR_RW);
             }
             break;
         }
-        case 6: // CRSRSI
+        case 6: // CSRRSI
         {
-            uint16_t crs_id = inst.imm & 0xFFF;
+            uint16_t csr_id = inst.imm & 0xFFF;
             uint32_t value = 0;
             
             if (inst.rs1 == 0)
             {
-                value = crs_read(hart, crs_id);
+                value = csr_action(hart, csr_id, 0, CSR_R);
             }
             else
             {
-                value = crs_read_set(hart, crs_id, inst.rs1);
+                value = csr_action(hart, csr_id, inst.rs1, CSR_RS);
             }
             
             if (inst.rd != 0)
@@ -616,18 +500,18 @@ static void execute_system(Hart* hart, uint32_t instruction)
             }
             break;
         }
-        case 7: // CRSRCI
+        case 7: // CSRRCI
         {
-            uint16_t crs_id = inst.imm & 0xFFF;
+            uint16_t csr_id = inst.imm & 0xFFF;
             uint32_t value = 0;
             
             if (inst.rs1 == 0)
             {
-                value = crs_read(hart, crs_id);
+                value = csr_action(hart, csr_id, 0, CSR_R);
             }
             else
             {
-                value = crs_read_clear(hart, crs_id, inst.rs1);
+                value = csr_action(hart, csr_id, inst.rs1, CSR_RC);
             }
             
             if (inst.rd != 0)
@@ -644,6 +528,10 @@ static void execute_system(Hart* hart, uint32_t instruction)
 
 void execute(Hart* hart, uint32_t instruction)
 {
+    // @Todo Better time (same on all cores)
+    // @Todo Memory-map mtime and mtimecmp
+    hart->time = __rdtsc();
+    
     switch (instruction & 0x7f)
     {
         case 0x03:
@@ -721,16 +609,30 @@ void execute(Hart* hart, uint32_t instruction)
     }
 
     assert(hart->regs[0] == 0);
+
+    hart->instret += 1;
 }
 
 void execute_from(Hart* hart, uint32_t start_address)
 {
     hart->pc = start_address;
-    hart->halted = false;
 
-    while (!hart->halted)
+    while (true)
     {
         uint32_t instruction = load_word(hart, hart->pc);
         execute(hart, instruction);
     }
 }
+
+void csr_init(Hart* hart);
+
+void hart_init(Hart* hart, uint32_t id, char* mem, uint32_t mem_size)
+{
+    memset(hart, 0, sizeof(Hart));
+    hart->hartid = id;
+    hart->priv = PRIV_M;
+    hart->mem = mem;
+    hart->mem_size = mem_size;
+    
+    csr_init(hart);
+}
diff --git a/emulator/hart.h b/emulator/hart.h
index 8e04d19..7135ed7 100644
--- a/emulator/hart.h
+++ b/emulator/hart.h
@@ -1,19 +1,38 @@
 #pragma once
 
+#include "emulator/csr.h"
+
 #include <stdint.h>
 #include <stdbool.h>
 
+#define PRIV_U 0
+#define PRIV_S 1
+#define PRIV_M 3
+
 struct Hart
 {
-    uint32_t pc;
+    uint32_t hartid;
+    
     uint32_t regs[32];
+
+    uint32_t pc;
+    uint8_t  priv;
     
+    // @Todo Proper memory system
     char*    mem;
     uint32_t mem_size;
-    
-    bool     halted;
+
+    // @Todo Deduplicate per machine
+    Csr      csrs[4096];
+
+    uint64_t instret;
+
+    // @Todo Deduplicate per machine
+    uint64_t time;
 };
 typedef struct Hart Hart;
 
+void hart_init(Hart* hart, uint32_t id, char* mem, uint32_t mem_size);
+
 void execute(Hart* hart, uint32_t instruction);
 void execute_from(Hart* hart, uint32_t start_address);
diff --git a/emulator/instruction.h b/emulator/instruction.h
new file mode 100644
index 0000000..97c9fe9
--- /dev/null
+++ b/emulator/instruction.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#include <stdint.h>
+
+#include "emulator/bits.h"
+
+struct Instruction
+{
+    uint8_t  opcode;
+    uint8_t  rs1;
+    uint8_t  rs2;
+    uint8_t  rd;
+    uint8_t  funct3;
+    uint8_t  funct7;
+    uint32_t imm;
+};
+typedef struct Instruction Instruction;
+
+static Instruction decode_r_type(uint32_t word)
+{
+    Instruction instruction = {0};
+    instruction.opcode =  word        & 0x7F;
+    instruction.rd     = (word >> 7)  & 0x1F;
+    instruction.funct3 = (word >> 12) & 0x07;
+    instruction.rs1    = (word >> 15) & 0x1F;
+    instruction.rs2    = (word >> 20) & 0x1F;
+    instruction.funct7 =  word >> 25;
+    return instruction;
+};
+
+static Instruction decode_i_type(uint32_t word)
+{
+    Instruction instruction = {0};
+    instruction.opcode =  word        & 0x7F;
+    instruction.rd     = (word >> 7)  & 0x1F;
+    instruction.funct3 = (word >> 12) & 0x07;
+    instruction.rs1    = (word >> 15) & 0x1F;
+    instruction.imm    = sign_extend(word >> 20, 12);
+    return instruction;
+};
+
+static Instruction decode_s_type(uint32_t word)
+{
+    Instruction instruction = {0};
+    instruction.opcode =  word        & 0x7F;
+    instruction.funct3 = (word >> 12) & 0x07;
+    instruction.rs1    = (word >> 15) & 0x1F;
+    instruction.rs2    = (word >> 20) & 0x1F;
+    instruction.imm    = sign_extend(((word >> 7) & 0x1F) | (word >> 25), 12);
+    return instruction;
+};
+
+static Instruction decode_b_type(uint32_t word)
+{
+    Instruction instruction = decode_s_type(word);
+    instruction.imm = ((instruction.imm << 11) & 0x800) | (instruction.imm & 0xfffff7ff);
+    return instruction;
+};
+
+static Instruction decode_u_type(uint32_t word)
+{
+    Instruction instruction = {0};
+    instruction.opcode =  word        & 0x7F;
+    instruction.rd     = (word >> 7)  & 0x1F;
+    instruction.imm    =  word        & 0xFFFFF000;
+    return instruction;
+};
+
+static Instruction decode_j_type(uint32_t word)
+{
+    Instruction instruction = {0};
+    instruction.opcode =  word        & 0x7F;
+    instruction.rd     = (word >> 7)  & 0x1F;
+    instruction.imm    = sign_extend(
+        ((word & 0x80000000) >> 11) |
+        ((word & 0x000FF000) >> 0)  |
+        ((word & 0x00100000) >> 9)  |
+        ((word & 0x7FE00000) >> 20), 21);
+    return instruction;
+}
diff --git a/emulator/lib.c b/emulator/lib.c
index 453a3f9..6c3c7d9 100644
--- a/emulator/lib.c
+++ b/emulator/lib.c
@@ -1,3 +1,7 @@
 #include "hart.c"
 #include "elf.c"
+#include "csr.c"
+#include "csr_unpriv_counter_timer.c"
+#include "csr_machine_trap_setup.c"
+#include "csr_machine_information.c"
 
diff --git a/emulator/main.c b/emulator/main.c
index 4bf99a3..5cfbd53 100644
--- a/emulator/main.c
+++ b/emulator/main.c
@@ -24,8 +24,7 @@ int main(int argc, char* argv[])
     }
 
     struct Hart hart = {0};
-    hart.mem = mem;
-    hart.mem_size = mem_size;
+    hart_init(&hart, 0, mem, mem_size);
 
     execute_from(&hart, start_address);
 
-- 
cgit