mirror of
https://github.com/openhwgroup/cva5.git
synced 2025-04-22 21:17:46 -04:00
MMU updates
This commit is contained in:
parent
8bf7050a0e
commit
02d51444d4
3 changed files with 64 additions and 40 deletions
|
@ -143,7 +143,7 @@ interface mmu_interface;
|
|||
|
||||
//TLB response
|
||||
logic write_entry;
|
||||
logic [19:0] new_phys_addr;
|
||||
logic [19:0] upper_physical_address;
|
||||
logic is_fault;
|
||||
|
||||
//From CSR
|
||||
|
@ -152,8 +152,8 @@ interface mmu_interface;
|
|||
logic sum; //permit Supervisor User Memory access
|
||||
logic [1:0] privilege;
|
||||
|
||||
modport mmu (input virtual_address, new_request, execute, rnw, ppn, mxr, sum, privilege, output write_entry, new_phys_addr, is_fault);
|
||||
modport tlb (input write_entry, new_phys_addr, is_fault, output new_request, virtual_address, execute, rnw);
|
||||
modport mmu (input virtual_address, new_request, execute, rnw, ppn, mxr, sum, privilege, output write_entry, upper_physical_address, is_fault);
|
||||
modport tlb (input write_entry, upper_physical_address, is_fault, output new_request, virtual_address, execute, rnw);
|
||||
modport csr (output ppn, mxr, sum, privilege);
|
||||
|
||||
endinterface
|
||||
|
|
96
core/mmu.sv
96
core/mmu.sv
|
@ -48,9 +48,17 @@ module mmu
|
|||
logic v;
|
||||
} pte_t;
|
||||
|
||||
typedef enum {IDLE, SEND_REQUEST_1, WAIT_REQUEST_1, SEND_REQUEST_2, WAIT_REQUEST_2, COMPLETE_SUCCESS, COMPLETE_FAULT} mmu_state_t;
|
||||
mmu_state_t state;
|
||||
mmu_state_t next_state;
|
||||
typedef enum {
|
||||
IDLE = 0,
|
||||
SEND_REQUEST_1 = 1,
|
||||
WAIT_REQUEST_1 = 2,
|
||||
SEND_REQUEST_2 = 3,
|
||||
WAIT_REQUEST_2 = 4,
|
||||
COMPLETE_SUCCESS = 5,
|
||||
COMPLETE_FAULT = 6
|
||||
} mmu_state_t;
|
||||
logic [6:0] state;
|
||||
logic [6:0] next_state;
|
||||
|
||||
pte_t pte;
|
||||
logic access_valid;
|
||||
|
@ -66,28 +74,27 @@ module mmu
|
|||
assign l1_request.is_amo = 0;
|
||||
assign l1_request.amo = 0;
|
||||
|
||||
always_ff @ (posedge clk) begin
|
||||
if (rst | l1_request.ack)
|
||||
l1_request.request <= 0;
|
||||
else if (next_state inside {SEND_REQUEST_1, SEND_REQUEST_2})
|
||||
l1_request.request <= 1;
|
||||
end
|
||||
assign l1_request.request = state[SEND_REQUEST_1] | state[SEND_REQUEST_2];
|
||||
|
||||
//Page Table addresses
|
||||
always_ff @ (posedge clk) begin
|
||||
if (next_state == SEND_REQUEST_2)
|
||||
l1_request.addr <= {{pte.ppn1[9:0], pte.ppn0}, mmu.virtual_address[21:12], 2'b00};
|
||||
else
|
||||
l1_request.addr <= {mmu.ppn[19:0], mmu.virtual_address[31:22], 2'b00};
|
||||
if (state[IDLE] | l1_response.data_valid) begin
|
||||
if (state[IDLE])
|
||||
l1_request.addr <= {mmu.ppn[19:0], mmu.virtual_address[31:22], 2'b00};
|
||||
else
|
||||
l1_request.addr <= {{pte.ppn1[9:0], pte.ppn0}, mmu.virtual_address[21:12], 2'b00};
|
||||
end
|
||||
end
|
||||
|
||||
assign pte = l1_response.data;
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
//Access and permission checks
|
||||
//A and D bits are software managed
|
||||
assign access_valid =
|
||||
(mmu.execute & pte.x) | //fetch
|
||||
(mmu.rnw & (pte.r | (pte.x & mmu.mxr))) | //load
|
||||
((~mmu.rnw & ~mmu.execute) & pte.w); //store
|
||||
(mmu.execute & pte.x & pte.a) | //fetch
|
||||
(mmu.rnw & (pte.r | (pte.x & mmu.mxr)) & pte.a) | //load
|
||||
((~mmu.rnw & ~mmu.execute) & pte.w & pte.a & pte.d); //store
|
||||
|
||||
assign privilege_valid =
|
||||
(mmu.privilege == MACHINE_PRIVILEGE) |
|
||||
|
@ -98,30 +105,47 @@ module mmu
|
|||
//State Machine
|
||||
always_comb begin
|
||||
next_state = state;
|
||||
case (state)
|
||||
IDLE : if (mmu.new_request) next_state = WAIT_REQUEST_1;
|
||||
SEND_REQUEST_1 : if (l1_request.ack) next_state = WAIT_REQUEST_1;
|
||||
WAIT_REQUEST_1 : begin
|
||||
case (1'b1)
|
||||
state[IDLE] :
|
||||
if (mmu.new_request) begin
|
||||
next_state = 2**SEND_REQUEST_1;
|
||||
end
|
||||
state[SEND_REQUEST_1] :
|
||||
if (l1_request.ack) begin
|
||||
next_state = 2**WAIT_REQUEST_1;
|
||||
end
|
||||
state[WAIT_REQUEST_1] :
|
||||
if (l1_response.data_valid) begin
|
||||
if (~pte.v | (~pte.r & pte.w)) //page not valid OR invalid xwr pattern
|
||||
next_state = COMPLETE_FAULT;
|
||||
else if (pte.v & (pte.r | pte.x)) //superpage (all remaining xwr patterns other than all zeros)
|
||||
next_state = (access_valid & privilege_valid) ? COMPLETE_SUCCESS : COMPLETE_FAULT;
|
||||
next_state = 2**COMPLETE_FAULT;
|
||||
else if (pte.v & (pte.r | pte.x)) begin//superpage (all remaining xwr patterns other than all zeros)
|
||||
if (access_valid & privilege_valid)
|
||||
next_state = 2**COMPLETE_SUCCESS;
|
||||
else
|
||||
next_state = 2**COMPLETE_FAULT;
|
||||
end
|
||||
else //(pte.v & ~pte.x & ~pte.w & ~pte.r) pointer to next level in page table
|
||||
next_state = SEND_REQUEST_2;
|
||||
next_state = 2**SEND_REQUEST_2;
|
||||
end
|
||||
end
|
||||
SEND_REQUEST_2 : if (l1_request.ack) next_state = WAIT_REQUEST_2;
|
||||
WAIT_REQUEST_2 : if (l1_response.data_valid) next_state = (access_valid & privilege_valid) ? COMPLETE_SUCCESS : COMPLETE_FAULT;
|
||||
COMPLETE_SUCCESS : next_state = IDLE;
|
||||
COMPLETE_FAULT : next_state = IDLE;
|
||||
default : next_state = IDLE;
|
||||
state[SEND_REQUEST_2] :
|
||||
if (l1_request.ack) begin
|
||||
next_state = 2**WAIT_REQUEST_2;
|
||||
end
|
||||
state[WAIT_REQUEST_2] :
|
||||
if (l1_response.data_valid) begin
|
||||
if (access_valid & privilege_valid)
|
||||
next_state = 2**COMPLETE_SUCCESS;
|
||||
else
|
||||
next_state = 2**COMPLETE_FAULT;
|
||||
end
|
||||
state[COMPLETE_SUCCESS], state[COMPLETE_FAULT] :
|
||||
next_state = 2**IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
always_ff @ (posedge clk) begin
|
||||
if (rst)
|
||||
state <= IDLE;
|
||||
state <= 2**IDLE;
|
||||
else
|
||||
state <= next_state;
|
||||
end
|
||||
|
@ -130,12 +154,12 @@ module mmu
|
|||
//TLB return path
|
||||
always_ff @ (posedge clk) begin
|
||||
if (l1_response.data_valid) begin
|
||||
mmu.new_phys_addr[19:10] <= pte.ppn1[9:0];
|
||||
mmu.new_phys_addr[9:0] <= (state == WAIT_REQUEST_2) ? pte.ppn0 : mmu.virtual_address[21:12];
|
||||
mmu.upper_physical_address[19:10] <= pte.ppn1[9:0];
|
||||
mmu.upper_physical_address[9:0] <= state[WAIT_REQUEST_2] ? pte.ppn0 : mmu.virtual_address[21:12];
|
||||
end
|
||||
end
|
||||
assign mmu.write_entry = (state == COMPLETE_SUCCESS);
|
||||
assign mmu.is_fault = (state == COMPLETE_FAULT);
|
||||
assign mmu.write_entry = state[COMPLETE_SUCCESS];
|
||||
assign mmu.is_fault = state[COMPLETE_FAULT];
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
//End of Implementation
|
||||
|
@ -144,7 +168,7 @@ module mmu
|
|||
////////////////////////////////////////////////////
|
||||
//Assertions
|
||||
mmu_spurious_l1_response:
|
||||
assert property (@(posedge clk) disable iff (rst) (l1_response.data_valid) |-> (state inside {WAIT_REQUEST_1, WAIT_REQUEST_2}))
|
||||
assert property (@(posedge clk) disable iff (rst) (l1_response.data_valid) |-> (state[WAIT_REQUEST_1] | state[WAIT_REQUEST_2]))
|
||||
else $error("mmu recieved response without a request");
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -79,7 +79,7 @@ module tlb_lut_ram #(
|
|||
|
||||
assign new_entry.valid = ~gc_tlb_flush;
|
||||
assign new_entry.tag = virtual_tag;
|
||||
assign new_entry.phys_addr = mmu.new_phys_addr;
|
||||
assign new_entry.phys_addr = mmu.upper_physical_address;
|
||||
|
||||
genvar i;
|
||||
generate
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue