summaryrefslogtreecommitdiff
path: root/rtl/core
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/core')
-rw-r--r--rtl/core/mmu/format.sv55
-rw-r--r--rtl/core/mmu/mmu.sv67
-rw-r--r--rtl/core/mmu/pagewalk.sv165
3 files changed, 285 insertions, 2 deletions
diff --git a/rtl/core/mmu/format.sv b/rtl/core/mmu/format.sv
index c0918a3..83ca3eb 100644
--- a/rtl/core/mmu/format.sv
+++ b/rtl/core/mmu/format.sv
@@ -8,13 +8,66 @@ typedef logic[17:0] mmu_base;
`define MMU_L1_PAGETABLE 2'b01
`define MMU_L1_SECTION 2'b10
+typedef struct packed
+{
+ logic[31:10] base;
+ logic[9:9] imp;
+ logic[8:5] domain;
+ logic[4:2] sbz;
+ logic[1:0] typ;
+} mmu_l1_pagetable;
+
+typedef struct packed
+{
+ logic[31:20] base;
+ logic[19:15] sbz0;
+ logic[14:12] tex;
+ logic[11:10] ap;
+ logic[9:9] imp;
+ logic[8:5] domain;
+ logic[4:4] sbz1;
+ logic[3:3] c;
+ logic[2:2] b;
+ logic[1:0] typ;
+} mmu_l1_section;
+
+`define MMU_SECTION_INDEX [17:0]
+
`define MMU_L2_INDEX [17:10]
`define MMU_L2_FAULT 2'b00
`define MMU_L2_LARGE 2'b01
`define MMU_L2_SMALL 2'b10
`define MMU_L2_SMALLEXT 2'b11
+typedef struct packed
+{
+ logic[31:16] base;
+ logic[15:15] sbz;
+ logic[14:12] tex;
+ logic[11:10] ap3;
+ logic[9:8] ap2;
+ logic[7:6] ap1;
+ logic[5:4] ap0;
+ logic[3:3] c;
+ logic[2:2] b;
+ logic[1:0] typ;
+} mmu_l2_large;
+
+typedef struct packed
+{
+ logic[31:12] base;
+ logic[11:10] ap3;
+ logic[9:8] ap2;
+ logic[7:6] ap1;
+ logic[5:4] ap0;
+ logic[3:3] c;
+ logic[2:2] b;
+ logic[1:0] typ;
+} mmu_l2_small;
+
+//TODO: struct mmu_l2_smallext
+
`define MMU_LARGE_INDEX [13:0]
-`define MMU_SMALL_INDEX [11:0]
+`define MMU_SMALL_INDEX [9:0]
`endif
diff --git a/rtl/core/mmu/mmu.sv b/rtl/core/mmu/mmu.sv
index a909537..504e447 100644
--- a/rtl/core/mmu/mmu.sv
+++ b/rtl/core/mmu/mmu.sv
@@ -1,8 +1,14 @@
+`include "core/mmu/format.sv"
+`include "core/uarch.sv"
+
module core_mmu
(
input logic clk,
rst_n,
+ input logic mmu_enable /*verilator public*/,
+ input mmu_base mmu_ttbr /*verilator public*/,
+
input logic bus_ready,
input word bus_data_rd,
data_data_wr,
@@ -24,9 +30,68 @@ module core_mmu
data_data_rd
);
- //TODO
+ ptr iphys_addr, dphys_addr;
+ word iphys_data_rd, dphys_data_rd, dphys_data_wr;
+ logic iphys_start, dphys_start, iphys_ready, dphys_ready, dphys_write;
+ logic[3:0] dphys_data_be;
+
+ core_mmu_pagewalk iwalk
+ (
+ .core_addr(insn_addr),
+ .core_start(insn_start),
+ .core_write(0),
+ .core_ready(insn_ready),
+ .core_data_wr(0),
+ .core_data_be(0),
+ .core_data_rd(insn_data_rd),
+
+ .bus_addr(iphys_addr),
+ .bus_start(iphys_start),
+ .bus_write(),
+ .bus_ready(iphys_ready),
+ .bus_data_wr(),
+ .bus_data_be(),
+ .bus_data_rd(iphys_data_rd),
+
+ .*
+ );
+
+ core_mmu_pagewalk dwalk
+ (
+ .core_addr(data_addr),
+ .core_start(data_start),
+ .core_write(data_write),
+ .core_ready(data_ready),
+ .core_data_wr(data_data_wr),
+ .core_data_be(data_data_be),
+ .core_data_rd(data_data_rd),
+
+ .bus_addr(dphys_addr),
+ .bus_start(dphys_start),
+ .bus_write(dphys_write),
+ .bus_ready(dphys_ready),
+ .bus_data_wr(dphys_data_wr),
+ .bus_data_be(dphys_data_be),
+ .bus_data_rd(dphys_data_rd),
+
+ .*
+ );
+
core_mmu_arbiter arbiter
(
+ .insn_addr(iphys_addr),
+ .insn_start(iphys_start),
+ .insn_ready(iphys_ready),
+ .insn_data_rd(iphys_data_rd),
+
+ .data_addr(dphys_addr),
+ .data_start(dphys_start),
+ .data_write(dphys_write),
+ .data_ready(dphys_ready),
+ .data_data_wr(dphys_data_wr),
+ .data_data_be(dphys_data_be),
+ .data_data_rd(dphys_data_rd),
+
.*
);
diff --git a/rtl/core/mmu/pagewalk.sv b/rtl/core/mmu/pagewalk.sv
new file mode 100644
index 0000000..b16ce26
--- /dev/null
+++ b/rtl/core/mmu/pagewalk.sv
@@ -0,0 +1,165 @@
+`include "core/mmu/format.sv"
+`include "core/uarch.sv"
+
+module core_mmu_pagewalk
+(
+ input logic clk,
+ rst_n,
+
+ input logic mmu_enable,
+ input mmu_base mmu_ttbr,
+
+ input logic bus_ready,
+ input word bus_data_rd,
+
+ input ptr core_addr,
+ input word core_data_wr,
+ input logic[3:0] core_data_be,
+ input logic core_start,
+ core_write,
+
+ output ptr bus_addr,
+ output word bus_data_wr,
+ output logic[3:0] bus_data_be,
+ output logic bus_start,
+ bus_write,
+
+ output logic core_ready,
+ output word core_data_rd
+);
+
+ enum int unsigned
+ {
+ IDLE,
+ L1,
+ L2,
+ DATA,
+ FAULT
+ } state;
+
+ mmu_l1_pagetable pagetable;
+ assign pagetable = bus_data_rd;
+
+ mmu_l1_section section;
+ assign section = bus_data_rd;
+
+ mmu_l2_large ptentry_large;
+ assign ptentry_large = bus_data_rd;
+
+ mmu_l2_small ptentry_small;
+ assign ptentry_small = bus_data_rd;
+
+ ptr target;
+ word hold_data;
+ logic[3:0] hold_be;
+
+ logic hold_write;
+
+ always @(posedge clk or negedge rst_n)
+ if(!rst_n) begin
+ state <= IDLE;
+ target <= 0;
+
+ hold_be <= 0;
+ hold_data <= 0;
+ hold_write <= 0;
+
+ bus_addr <= 0;
+ bus_start <= 0;
+ bus_write <= 0;
+ bus_data_be <= 0;
+ bus_data_wr <= 0;
+
+ core_ready <= 0;
+ core_data_rd <= 0;
+ end else begin
+ if(bus_start)
+ bus_start <= 0;
+
+ if(core_ready)
+ core_ready <= 0;
+
+ unique case(state)
+ IDLE:
+ if(core_start) begin
+ bus_start <= 1;
+
+ if(mmu_enable) begin
+ target <= core_addr;
+ hold_be <= core_data_be;
+ hold_data <= core_data_wr;
+ hold_write <= core_write;
+
+ state <= L1;
+ bus_addr <= {mmu_ttbr, core_addr `MMU_L1_INDEX};
+ end else begin
+ state <= DATA;
+ bus_addr <= core_addr;
+ bus_write <= core_write;
+ bus_data_wr <= core_data_wr;
+ bus_data_be <= core_data_be;
+ end
+ end
+
+ L1:
+ if(bus_ready)
+ unique case(bus_data_rd[1:0])
+ `MMU_L1_PAGETABLE: begin
+ state <= L2;
+ bus_addr <= {pagetable.base, target `MMU_L2_INDEX};
+ bus_start <= 1;
+ end
+
+ `MMU_L1_SECTION: begin
+ state <= DATA;
+
+ bus_addr <= {section.base, target `MMU_SECTION_INDEX};
+ bus_start <= 1;
+ bus_write <= hold_write;
+ bus_data_wr <= hold_data;
+ bus_data_be <= hold_be;
+ end
+
+ // Tiny (1KiB wtf?) pages and supersections not supported
+ default:
+ state <= FAULT;
+ endcase
+
+ L2:
+ if(bus_ready) begin
+ state <= DATA;
+
+ bus_write <= hold_write;
+ bus_data_wr <= hold_data;
+ bus_data_be <= hold_be;
+
+ unique case(bus_data_rd[1:0])
+ `MMU_L2_FAULT:
+ state <= FAULT;
+
+ `MMU_L2_LARGE: begin
+ bus_addr <= {ptentry_large.base, target `MMU_LARGE_INDEX};
+ bus_start <= 1;
+ end
+
+ `MMU_L2_SMALL, `MMU_L2_SMALLEXT: begin
+ bus_addr <= {ptentry_small.base, target `MMU_SMALL_INDEX};
+ bus_start <= 1;
+ end
+ endcase
+ end
+
+ DATA:
+ if(bus_ready) begin
+ state <= IDLE;
+ bus_write <= 0;
+ core_ready <= 1;
+ core_data_rd <= bus_data_rd;
+ end
+
+ //TODO
+ FAULT: ;
+ endcase
+ end
+
+endmodule