Integrate PMP, and fix a couple of PMP bugs
This commit is contained in:
		
							parent
							
								
									4878a752d6
								
							
						
					
					
						commit
						c93228d13e
					
				|  | @ -12,4 +12,5 @@ file hazard3_instr_decompress.v | |||
| file hazard3_decode.v | ||||
| file hazard3_csr.v | ||||
| file hazard3_regfile_1w2r.v | ||||
| file hazard3_pmp.v | ||||
| include . | ||||
|  |  | |||
|  | @ -434,7 +434,9 @@ hazard3_alu #( | |||
| 	.cmp        (x_alu_cmp) | ||||
| ); | ||||
| 
 | ||||
| // AHB transaction request | ||||
| // Load/store bus request | ||||
| 
 | ||||
| wire x_loadstore_pmp_fail; | ||||
| 
 | ||||
| wire x_unaligned_addr = d_memop != MEMOP_NONE && ( | ||||
| 	bus_hsize_d == HSIZE_WORD && |bus_haddr_d[1:0] || | ||||
|  | @ -574,6 +576,7 @@ always @ (*) begin | |||
| 	bus_aph_req_d = x_memop_vld && !( | ||||
| 		x_stall_on_raw || | ||||
| 		x_stall_on_exclusive_overlap || | ||||
| 		x_loadstore_pmp_fail || | ||||
| 		x_unaligned_addr || | ||||
| 		m_trap_enter_soon || | ||||
| 		(xm_wfi && !m_wfi_stall_clear) // FIXME will cause a timing issue, better to stall til *after* clear | ||||
|  | @ -713,6 +716,51 @@ wire x_jump_req_if_aligned = !x_stall_on_raw && ( | |||
| 
 | ||||
| assign x_jump_req = x_jump_req_if_aligned && !x_jump_misaligned; | ||||
| 
 | ||||
| // Memory protection | ||||
| 
 | ||||
| wire [11:0]       x_pmp_cfg_addr; | ||||
| wire              x_pmp_cfg_wen; | ||||
| wire [W_DATA-1:0] x_pmp_cfg_wdata; | ||||
| wire [W_DATA-1:0] x_pmp_cfg_rdata; | ||||
| 
 | ||||
| wire x_exec_pmp_fail; | ||||
| 
 | ||||
| generate | ||||
| if (PMP_REGIONS > 0) begin: have_pmp | ||||
| 
 | ||||
| 	hazard3_pmp #( | ||||
| 	`include "hazard3_config_inst.vh" | ||||
| 	) pmp ( | ||||
| 		.clk              (clk), | ||||
| 		.rst_n            (rst_n), | ||||
| 
 | ||||
| 		.mstatus_mxr      (1'b0), // Only used when S mode present | ||||
| 
 | ||||
| 		.cfg_addr         (x_pmp_cfg_addr), | ||||
| 		.cfg_wen          (x_pmp_cfg_wen), | ||||
| 		.cfg_wdata        (x_pmp_cfg_wdata), | ||||
| 		.cfg_rdata        (x_pmp_cfg_rdata), | ||||
| 
 | ||||
| 		.i_addr           (d_pc), | ||||
| 		.i_instr_is_32bit (&fd_cir[1:0]), | ||||
| 		.i_m_mode         (x_mmode_execution), | ||||
| 		.i_kill           (x_exec_pmp_fail), | ||||
| 
 | ||||
| 		.d_addr           (bus_haddr_d), | ||||
| 		.d_m_mode         (x_mmode_loadstore), | ||||
| 		.d_write          (bus_hwrite_d), | ||||
| 		.d_kill           (x_loadstore_pmp_fail) | ||||
| 	); | ||||
| 
 | ||||
| end else begin: no_pmp | ||||
| 
 | ||||
| 	assign x_pmp_cfg_rdata = 1'b0; | ||||
| 	assign x_loadstore_pmp_fail = 1'b0; | ||||
| 	assign x_exec_pmp_fail = 1'b0; | ||||
| 
 | ||||
| end | ||||
| endgenerate | ||||
| 
 | ||||
| // CSRs and Trap Handling | ||||
| 
 | ||||
| wire [W_DATA-1:0] x_csr_wdata = d_csr_w_imm ? | ||||
|  | @ -754,13 +802,16 @@ end | |||
| wire [W_ADDR-1:0] m_exception_return_addr; | ||||
| 
 | ||||
| wire [W_EXCEPT-1:0] x_except = | ||||
| 	x_jump_req_if_aligned && x_jump_misaligned             ? EXCEPT_INSTR_MISALIGN : | ||||
| 	x_csr_illegal_access                                   ? EXCEPT_INSTR_ILLEGAL  : | ||||
| 	|EXTENSION_A && x_unaligned_addr &&  d_memop_is_amo    ? EXCEPT_STORE_ALIGN    : | ||||
| 	|EXTENSION_A && x_amo_phase == 3'h4 && x_unaligned_addr? EXCEPT_STORE_ALIGN    : | ||||
| 	|EXTENSION_A && x_amo_phase == 3'h4                    ? EXCEPT_STORE_FAULT    : | ||||
| 	x_unaligned_addr &&  x_memop_write                     ? EXCEPT_STORE_ALIGN    : | ||||
| 	x_unaligned_addr && !x_memop_write                     ? EXCEPT_LOAD_ALIGN     : d_except; | ||||
| 	x_jump_req_if_aligned && x_jump_misaligned               ? EXCEPT_INSTR_MISALIGN : | ||||
| 	x_exec_pmp_fail                                          ? EXCEPT_INSTR_FAULT    : | ||||
| 	x_csr_illegal_access                                     ? EXCEPT_INSTR_ILLEGAL  : | ||||
| 	|EXTENSION_A && x_unaligned_addr &&  d_memop_is_amo      ? EXCEPT_STORE_ALIGN    : | ||||
| 	|EXTENSION_A && x_amo_phase == 3'h4 && x_unaligned_addr  ? EXCEPT_STORE_ALIGN    : | ||||
| 	|EXTENSION_A && x_amo_phase == 3'h4                      ? EXCEPT_STORE_FAULT    : | ||||
| 	x_unaligned_addr &&  x_memop_write                       ? EXCEPT_STORE_ALIGN    : | ||||
| 	x_unaligned_addr && !x_memop_write                       ? EXCEPT_LOAD_ALIGN     : | ||||
| 	x_loadstore_pmp_fail && (d_memop_is_amo || bus_hwrite_d) ? EXCEPT_STORE_FAULT    : | ||||
| 	x_loadstore_pmp_fail                                     ? EXCEPT_LOAD_FAULT     : d_except; | ||||
| 
 | ||||
| // If an instruction causes an exceptional condition we do not consider it to have retired. | ||||
| wire x_except_counts_as_retire = x_except == EXCEPT_EBREAK || x_except == EXCEPT_MRET || x_except == EXCEPT_ECALL; | ||||
|  | @ -821,6 +872,11 @@ hazard3_csr #( | |||
| 	.irq_timer                  (timer_irq), | ||||
| 	.except                     (xm_except), | ||||
| 
 | ||||
| 	.pmp_cfg_addr               (x_pmp_cfg_addr), | ||||
| 	.pmp_cfg_wen                (x_pmp_cfg_wen), | ||||
| 	.pmp_cfg_wdata              (x_pmp_cfg_wdata), | ||||
| 	.pmp_cfg_rdata              (x_pmp_cfg_rdata), | ||||
| 
 | ||||
| 	// Other CSR-specific signalling | ||||
| 	.instr_ret                  (|x_instr_ret) | ||||
| ); | ||||
|  | @ -1080,4 +1136,6 @@ hazard3_regfile_1w2r #( | |||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| `ifndef YOSYS | ||||
| `default_nettype wire | ||||
| `endif | ||||
|  |  | |||
|  | @ -82,9 +82,9 @@ module hazard3_csr #( | |||
| 	output wire                wfi_stall_clear, | ||||
| 
 | ||||
| 	// Each of these may be performed at a different privilege level from the others: | ||||
| 	output wire m_mode_execution, | ||||
| 	output wire m_mode_trap_entry, | ||||
| 	output wire m_mode_loadstore, | ||||
| 	output wire                m_mode_execution, | ||||
| 	output wire                m_mode_trap_entry, | ||||
| 	output wire                m_mode_loadstore, | ||||
| 
 | ||||
| 	// Exceptions must *not* be a function of bus stall. | ||||
| 	input  wire [W_EXCEPT-1:0] except, | ||||
|  | @ -95,6 +95,11 @@ module hazard3_csr #( | |||
| 	input  wire                irq_software, | ||||
| 	input  wire                irq_timer, | ||||
| 
 | ||||
| 	// PMP config interface | ||||
| 	output wire [11:0]         pmp_cfg_addr, | ||||
| 	output reg                 pmp_cfg_wen, | ||||
| 	output wire [W_DATA-1:0]   pmp_cfg_wdata, | ||||
| 	input  wire [W_DATA-1:0]   pmp_cfg_rdata, | ||||
| 
 | ||||
| 	// Other CSR-specific signalling | ||||
| 	input  wire                instr_ret | ||||
|  | @ -451,6 +456,7 @@ wire match_uro = U_MODE && !wen_soon; | |||
| always @ (*) begin | ||||
| 	decode_match = 1'b0; | ||||
| 	rdata = {XLEN{1'b0}}; | ||||
| 	pmp_cfg_wen = 1'b0; | ||||
| 	case (addr) | ||||
| 
 | ||||
|     // ------------------------------------------------------------------------ | ||||
|  | @ -712,6 +718,112 @@ always @ (*) begin | |||
| 		}; | ||||
| 	end | ||||
| 
 | ||||
|     // ------------------------------------------------------------------------ | ||||
|     // PMP CSRs (bridge to PMP config interface) | ||||
| 
 | ||||
|     // If PMP is present, all 16 registers are present, but some may be WARL'd | ||||
|     // to 0 depending on how many regions are actually implemented. | ||||
| 	PMPCFG0:   if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPCFG1:   if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPCFG2:   if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPCFG3:   if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR0:  if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR1:  if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR2:  if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR3:  if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR4:  if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR5:  if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR6:  if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR7:  if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR8:  if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR9:  if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR10: if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR11: if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR12: if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR13: if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR14: if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 	PMPADDR15: if (PMP_REGIONS > 0) begin | ||||
| 		decode_match = match_mrw; | ||||
| 		pmp_cfg_wen = match_mrw && wen; | ||||
| 		rdata = pmp_cfg_rdata; | ||||
| 	end | ||||
| 
 | ||||
|     // ------------------------------------------------------------------------ | ||||
|     // U-mode CSRs | ||||
| 
 | ||||
|  | @ -1036,6 +1148,9 @@ assign mcause_code_next = exception_req_any ? {2'h0, except} : mcause_irq_num; | |||
| // ---------------------------------------------------------------------------- | ||||
| // Privilege state outputs | ||||
| 
 | ||||
| assign pmp_cfg_addr = addr; | ||||
| assign pmp_cfg_wdata = wdata_update; | ||||
| 
 | ||||
| // Effective privilege for execution. Used for: | ||||
| // - Privilege level of branch target fetches (frontend keeps fetch privilege | ||||
| //   constant during sequential fetch) | ||||
|  |  | |||
|  | @ -274,7 +274,7 @@ reg              mem_addr_vld_r; | |||
| 
 | ||||
| // Downstream accesses are always word-sized word-aligned. | ||||
| assign mem_addr = mem_addr_r; | ||||
| assign mem_priv = mem_addr_r; | ||||
| assign mem_priv = mem_priv_r; | ||||
| assign mem_addr_vld = mem_addr_vld_r && !reset_holdoff; | ||||
| assign mem_size = 1'b1; | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,7 +12,6 @@ module hazard3_pmp #( | |||
| ) ( | ||||
| 	input  wire              clk, | ||||
| 	input  wire              rst_n, | ||||
| 	input  wire              m_mode, | ||||
| 	input  wire              mstatus_mxr, // make executable readable | ||||
| 
 | ||||
| 	// Config interface passed through CSR block | ||||
|  | @ -67,18 +66,18 @@ always @ (posedge clk or negedge rst_n) begin: cfg_update | |||
| 		end | ||||
| 	end else if (cfg_wen) begin | ||||
| 		for (i = 0; i < PMP_REGIONS; i = i + 1) begin | ||||
| 			if (cfg_addr == PMPCFG0 + i / 4) begin | ||||
| 			if (cfg_addr == PMPCFG0 + i / 4 && !pmpcfg_l[i]) begin | ||||
| 				pmpcfg_l[i] <= cfg_wdata[i % 4 * 8 + 7]; | ||||
| 				// TOR is not supported, gets mapped to OFF: | ||||
| 				pmpcfg_a[i] <= { | ||||
| 					cfg_wdata[i % 4 * 8 + 4], | ||||
| 					cfg_wdata[i % 4 * 8 + 3] && csr[i % 4 * 8 + 4] | ||||
| 					cfg_wdata[i % 4 * 8 + 3] && cfg_wdata[i % 4 * 8 + 4] | ||||
| 				}; | ||||
| 				pmpcfg_r[i] <= cfg_wdata[i % 4 * 8 + 2]; | ||||
| 				pmpcfg_w[i] <= cfg_wdata[i % 4 * 8 + 1]; | ||||
| 				pmpcfg_x[i] <= cfg_wdata[i % 4 * 8 + 0]; | ||||
| 			end | ||||
| 			if (cfg_addr == PMPADDR0 + i) begin | ||||
| 			if (cfg_addr == PMPADDR0 + i && !pmpcfg_l[i]) begin | ||||
| 				pmpaddr[i] <= cfg_wdata[W_ADDR-3:0]; | ||||
| 			end | ||||
| 		end | ||||
|  | @ -218,7 +217,7 @@ always @ (*) begin: check_i_match | |||
| 	i_partial_match = 1'b0; | ||||
| 	i_l = 1'b0; | ||||
| 	i_x = 1'b0; | ||||
| 	for (i = PMP_REGIONS - 1; i >= 0; i = i -q 1) begin | ||||
| 	for (i = PMP_REGIONS - 1; i >= 0; i = i - 1) begin | ||||
| 		match_hw0 = |pmpcfg_a[i] && (i_addr     & match_mask[i]) == match_addr[i]; | ||||
| 		match_hw1 = |pmpcfg_a[i] && (i_addr_hw1 & match_mask[i]) == match_addr[i]; | ||||
| 		if (match_hw0 || match_hw1) begin | ||||
|  | @ -248,4 +247,6 @@ assign i_kill = i_partial_match || ( | |||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| `default_nettype wire | ||||
| `ifndef YOSYS | ||||
| `default_nettype wire | ||||
| `endif | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue