🐛 Fix PTW return empty TLB entry and w flag

This commit is contained in:
Florian Zaruba 2017-06-17 15:11:15 +02:00
parent 82903ecedf
commit 6eeb2942da
2 changed files with 34 additions and 22 deletions

View file

@ -291,7 +291,7 @@ module mmu #(
// this is a store
if (lsu_is_store_i) begin
// check if the page is write-able and we are not violating privileges
if (dtlb_content.w || daccess_err) begin
if (!dtlb_content.w || daccess_err) begin
lsu_exception_o = {ST_ACCESS_FAULT, lsu_vaddr_i, 1'b1};
end
// this is a load, check for sufficient access privileges

View file

@ -74,10 +74,11 @@ module ptw #(
pte_t pte;
assign pte = pte_t'(data_rdata_i);
enum logic[1:0] {
enum logic[2:0] {
IDLE,
WAIT_GRANT,
PTE_LOOKUP,
WAIT_RVALID,
PROPAGATE_ERROR
} CS, NS;
@ -115,7 +116,7 @@ module ptw #(
// output the correct ASID
assign update_asid_o = tlb_update_asid_q;
// set the global mapping bit
assign update_content_o = pte || (global_mapping_q << 5);
assign update_content_o = pte | (global_mapping_q << 5);
assign tag_valid_o = tag_valid_q;
//-------------------
@ -167,6 +168,7 @@ module ptw #(
// by default we start with the top-most page table
ptw_lvl_n = LVL1;
global_mapping_n = 1'b0;
is_instr_ptw_n = 1'b0;
// if we got an ITLB miss
if (enable_translation_i & itlb_access_i & itlb_miss_i & ~dtlb_access_i) begin
ptw_pptr_n = {satp_ppn_i, itlb_vaddr_i[38:30], 3'b0};
@ -177,7 +179,6 @@ module ptw #(
// we got an DTLB miss
end else if (enable_translation_i & dtlb_access_i & dtlb_miss_i) begin
ptw_pptr_n = {satp_ppn_i, dtlb_vaddr_i[38:30], 3'b0};
is_instr_ptw_n = 1'b0;
tlb_update_asid_n = asid_i;
vaddr_n = dtlb_vaddr_i;
NS = WAIT_GRANT;
@ -187,14 +188,6 @@ module ptw #(
WAIT_GRANT: begin
// send a request out
data_req_o = 1'b1;
// depending on the current level send the right address
if (ptw_lvl_q == LVL2)
ptw_pptr_n = {pte.ppn, vaddr_q[29:21], 3'b0};
if (ptw_lvl_q == LVL3)
ptw_pptr_n = {pte.ppn, vaddr_q[20:12], 3'b0};
// wait for the WAIT_GRANT
if (data_gnt_i) begin
// send the tag valid signal one cycle later
@ -206,6 +199,7 @@ module ptw #(
PTE_LOOKUP: begin
// we wait for the valid signal
if (data_rvalid_i) begin
// check if the global mapping bit is set
if (pte.g)
global_mapping_n = 1'b1;
@ -262,11 +256,17 @@ module ptw #(
// this is a pointer to the next TLB level
end else begin
// pointer to next level of page table
if (ptw_lvl_q == LVL1)
ptw_lvl_n = LVL2;
if (ptw_lvl_q == LVL1) begin
// we are in the second level now
ptw_lvl_n = LVL2;
ptw_pptr_n = {pte.ppn, vaddr_q[29:21], 3'b0};
end
if (ptw_lvl_q == LVL2)
ptw_lvl_n = LVL3;
if (ptw_lvl_q == LVL2) begin
// here we received a pointer to the third level
ptw_lvl_n = LVL3;
ptw_pptr_n = {pte.ppn, vaddr_q[20:12], 3'b0};
end
NS = WAIT_GRANT;
@ -285,21 +285,33 @@ module ptw #(
NS = IDLE;
ptw_error_o = 1'b1;
end
// wait for the rvalid before going back to IDLE
WAIT_RVALID: begin
if (data_rvalid_i)
NS = IDLE;
end
endcase
// -------
// Flush
// -------
// check if we are walking a store, if not than go back to IDLE because
// all other operations are speculative
if (flush_i && !lsu_is_store_i) begin
NS = IDLE;
// should we have flushed before we got an rvalid, wait for it until going back to IDLE
if (flush_i) begin
// check if we are walking a store, if not than go back to IDLE because
// all other operations are speculative
if ((CS == WAIT_GRANT) && data_gnt_i)
NS = WAIT_RVALID;
// keep the state if we are serving a store
else if (flush_i && lsu_is_store_i)
NS = CS;
else
NS = IDLE;
end
end
// sequential process
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
CS <= IDLE;
CS <= IDLE;
is_instr_ptw_q <= 1'b0;
ptw_lvl_q <= LVL1;
tag_valid_q <= 1'b0;
@ -308,7 +320,7 @@ module ptw #(
ptw_pptr_q <= '{default: 0};
global_mapping_q <= 1'b0;
end else begin
CS <= NS;
CS <= NS;
ptw_pptr_q <= ptw_pptr_n;
is_instr_ptw_q <= is_instr_ptw_n;
ptw_lvl_q <= ptw_lvl_n;