Vaguely implement wfi
This commit is contained in:
		
							parent
							
								
									375a6d60b7
								
							
						
					
					
						commit
						cc6a6c09ba
					
				|  | @ -185,6 +185,7 @@ wire [W_ADDR-1:0]    d_jump_offs; | ||||||
| wire                 d_jump_is_regoffs; | wire                 d_jump_is_regoffs; | ||||||
| wire [W_ADDR-1:0]    d_pc; | wire [W_ADDR-1:0]    d_pc; | ||||||
| wire [W_EXCEPT-1:0]  d_except; | wire [W_EXCEPT-1:0]  d_except; | ||||||
|  | wire                 d_wfi; | ||||||
| wire                 d_csr_ren; | wire                 d_csr_ren; | ||||||
| wire                 d_csr_wen; | wire                 d_csr_wen; | ||||||
| wire [1:0]           d_csr_wtype; | wire [1:0]           d_csr_wtype; | ||||||
|  | @ -229,7 +230,8 @@ hazard3_decode #( | ||||||
| 	.d_branchcond         (d_branchcond), | 	.d_branchcond         (d_branchcond), | ||||||
| 	.d_jump_offs          (d_jump_offs), | 	.d_jump_offs          (d_jump_offs), | ||||||
| 	.d_jump_is_regoffs    (d_jump_is_regoffs), | 	.d_jump_is_regoffs    (d_jump_is_regoffs), | ||||||
| 	.d_except             (d_except) | 	.d_except             (d_except), | ||||||
|  | 	.d_wfi                (d_wfi) | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| // ---------------------------------------------------------------------------- | // ---------------------------------------------------------------------------- | ||||||
|  | @ -267,6 +269,7 @@ reg  [W_DATA-1:0]    xm_result; | ||||||
| reg  [W_DATA-1:0]    xm_store_data; | reg  [W_DATA-1:0]    xm_store_data; | ||||||
| reg  [W_MEMOP-1:0]   xm_memop; | reg  [W_MEMOP-1:0]   xm_memop; | ||||||
| reg  [W_EXCEPT-1:0]  xm_except; | reg  [W_EXCEPT-1:0]  xm_except; | ||||||
|  | reg                  xm_wfi; | ||||||
| reg                  xm_delay_irq_entry; | reg                  xm_delay_irq_entry; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -496,6 +499,7 @@ always @ (posedge clk or negedge rst_n) begin | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| wire [W_ADDR-1:0] m_exception_return_addr; | wire [W_ADDR-1:0] m_exception_return_addr; | ||||||
|  | wire m_wfi_stall_clear; | ||||||
| 
 | 
 | ||||||
| // If an instruction causes an exceptional condition we do not consider it to have retired. | // 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; | wire x_except_counts_as_retire = x_except == EXCEPT_EBREAK || x_except == EXCEPT_MRET || x_except == EXCEPT_ECALL; | ||||||
|  | @ -542,6 +546,7 @@ hazard3_csr #( | ||||||
| 	.trap_enter_rdy             (m_trap_enter_rdy), | 	.trap_enter_rdy             (m_trap_enter_rdy), | ||||||
| 	.loadstore_dphase_pending   (!xm_memop[3]), | 	.loadstore_dphase_pending   (!xm_memop[3]), | ||||||
| 	.mepc_in                    (m_exception_return_addr), | 	.mepc_in                    (m_exception_return_addr), | ||||||
|  | 	.wfi_stall_clear            (m_wfi_stall_clear), | ||||||
| 
 | 
 | ||||||
| 	// IRQ and exception requests | 	// IRQ and exception requests | ||||||
| 	.delay_irq_entry            (xm_delay_irq_entry), | 	.delay_irq_entry            (xm_delay_irq_entry), | ||||||
|  | @ -565,6 +570,7 @@ always @ (posedge clk or negedge rst_n) begin | ||||||
| 	if (!rst_n) begin | 	if (!rst_n) begin | ||||||
| 		xm_memop <= MEMOP_NONE; | 		xm_memop <= MEMOP_NONE; | ||||||
| 		xm_except <= EXCEPT_NONE; | 		xm_except <= EXCEPT_NONE; | ||||||
|  | 		xm_wfi <= 1'b0; | ||||||
| 		{xm_rs1, xm_rs2, xm_rd} <= {3 * W_REGADDR{1'b0}}; | 		{xm_rs1, xm_rs2, xm_rd} <= {3 * W_REGADDR{1'b0}}; | ||||||
| 	end else begin | 	end else begin | ||||||
| 		if (!m_stall) begin | 		if (!m_stall) begin | ||||||
|  | @ -572,11 +578,13 @@ always @ (posedge clk or negedge rst_n) begin | ||||||
| 			// If the transfer is unaligned, make sure it is completely NOP'd on the bus | 			// If the transfer is unaligned, make sure it is completely NOP'd on the bus | ||||||
| 			xm_memop <= d_memop | {x_unaligned_addr, 3'h0}; | 			xm_memop <= d_memop | {x_unaligned_addr, 3'h0}; | ||||||
| 			xm_except <= x_except; | 			xm_except <= x_except; | ||||||
|  | 			xm_wfi <= d_wfi; | ||||||
| 			if (x_stall || m_trap_enter_soon) begin | 			if (x_stall || m_trap_enter_soon) begin | ||||||
| 				// Insert bubble | 				// Insert bubble | ||||||
| 				xm_rd <= {W_REGADDR{1'b0}}; | 				xm_rd <= {W_REGADDR{1'b0}}; | ||||||
| 				xm_memop <= MEMOP_NONE; | 				xm_memop <= MEMOP_NONE; | ||||||
| 				xm_except <= EXCEPT_NONE; | 				xm_except <= EXCEPT_NONE; | ||||||
|  | 				xm_wfi <= 1'b0; | ||||||
| 			end | 			end | ||||||
| 		end else if (bus_dph_err_d) begin | 		end else if (bus_dph_err_d) begin | ||||||
| 			// First phase of 2-phase AHBL error response. Pass the exception along on | 			// First phase of 2-phase AHBL error response. Pass the exception along on | ||||||
|  | @ -586,6 +594,7 @@ always @ (posedge clk or negedge rst_n) begin | ||||||
| 			assert(!xm_memop[3]); // Not NONE | 			assert(!xm_memop[3]); // Not NONE | ||||||
| `endif | `endif | ||||||
| 			xm_except <= xm_memop <= MEMOP_LBU ? EXCEPT_LOAD_FAULT : EXCEPT_STORE_FAULT; | 			xm_except <= xm_memop <= MEMOP_LBU ? EXCEPT_LOAD_FAULT : EXCEPT_STORE_FAULT; | ||||||
|  | 			xm_wfi <= 1'b0; | ||||||
| 		end | 		end | ||||||
| 	end | 	end | ||||||
| end | end | ||||||
|  | @ -624,7 +633,9 @@ assign f_jump_target = m_trap_enter_vld	? m_trap_addr : x_jump_target; | ||||||
| assign x_jump_not_except = !m_trap_enter_vld; | assign x_jump_not_except = !m_trap_enter_vld; | ||||||
| 
 | 
 | ||||||
| wire m_bus_stall = !xm_memop[3] && !bus_dph_ready_d; | wire m_bus_stall = !xm_memop[3] && !bus_dph_ready_d; | ||||||
| assign m_stall = m_bus_stall || (m_trap_enter_vld && !m_trap_enter_rdy && !m_trap_is_irq); | assign m_stall = m_bus_stall || | ||||||
|  | 	(m_trap_enter_vld && !m_trap_enter_rdy && !m_trap_is_irq) || | ||||||
|  | 	(xm_wfi && !m_wfi_stall_clear); | ||||||
| 
 | 
 | ||||||
| // Exception is taken against the instruction currently in M, so walk the PC | // Exception is taken against the instruction currently in M, so walk the PC | ||||||
| // back. IRQ is taken "in between" the instruction in M and the instruction | // back. IRQ is taken "in between" the instruction in M and the instruction | ||||||
|  |  | ||||||
|  | @ -91,6 +91,7 @@ module hazard3_csr #( | ||||||
| 	// mode. | 	// mode. | ||||||
| 	input  wire                loadstore_dphase_pending, | 	input  wire                loadstore_dphase_pending, | ||||||
| 	input  wire [XLEN-1:0]     mepc_in, | 	input  wire [XLEN-1:0]     mepc_in, | ||||||
|  | 	output wire                wfi_stall_clear, | ||||||
| 
 | 
 | ||||||
| 	// Exceptions must *not* be a function of bus stall. | 	// Exceptions must *not* be a function of bus stall. | ||||||
| 	input  wire [W_EXCEPT-1:0] except, | 	input  wire [W_EXCEPT-1:0] except, | ||||||
|  | @ -1019,6 +1020,10 @@ wire [31:0] mip_no_global = mip & ~(32'h800 & ~{XLEN{midcr_eivect}}); | ||||||
| wire standard_irq_active = |(mip_no_global & mie) && mstatus_mie && !dcsr_step; | wire standard_irq_active = |(mip_no_global & mie) && mstatus_mie && !dcsr_step; | ||||||
| wire external_irq_active = external_irq_pending && mstatus_mie && !dcsr_step && mie_meie; | wire external_irq_active = external_irq_pending && mstatus_mie && !dcsr_step && mie_meie; | ||||||
| 
 | 
 | ||||||
|  | // WFI clear respects individual interrupt enables but ignores mstatus.mie. | ||||||
|  | // Additionally, wfi is treated as a nop during single-stepping and D-mode. | ||||||
|  | assign wfi_stall_clear = |(mip & mie) || dcsr_step || debug_mode || want_halt_irq_if_no_exception; | ||||||
|  | 
 | ||||||
| wire [4:0] external_irq_num; | wire [4:0] external_irq_num; | ||||||
| wire [3:0] standard_irq_num; | wire [3:0] standard_irq_num; | ||||||
| assign mlei = external_irq_num; | assign mlei = external_irq_num; | ||||||
|  |  | ||||||
|  | @ -56,7 +56,8 @@ module hazard3_decode #( | ||||||
| 	output reg  [W_BCOND-1:0]   d_branchcond, | 	output reg  [W_BCOND-1:0]   d_branchcond, | ||||||
| 	output reg  [W_ADDR-1:0]    d_jump_offs, | 	output reg  [W_ADDR-1:0]    d_jump_offs, | ||||||
| 	output reg                  d_jump_is_regoffs, | 	output reg                  d_jump_is_regoffs, | ||||||
| 	output reg  [W_EXCEPT-1:0]  d_except | 	output reg  [W_EXCEPT-1:0]  d_except, | ||||||
|  | 	output reg                  d_wfi | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| `include "rv_opcodes.vh" | `include "rv_opcodes.vh" | ||||||
|  | @ -193,6 +194,7 @@ always @ (*) begin | ||||||
| 	d_jump_is_regoffs = 1'b0; | 	d_jump_is_regoffs = 1'b0; | ||||||
| 	d_invalid_32bit = 1'b0; | 	d_invalid_32bit = 1'b0; | ||||||
| 	d_except = EXCEPT_NONE; | 	d_except = EXCEPT_NONE; | ||||||
|  | 	d_wfi = 1'b0; | ||||||
| 
 | 
 | ||||||
| 	casez (d_instr) | 	casez (d_instr) | ||||||
| 	RV_BEQ:     begin d_invalid_32bit = DEBUG_SUPPORT && debug_mode; d_rd = X0; d_aluop = ALUOP_SUB; d_branchcond = BCOND_ZERO;  end | 	RV_BEQ:     begin d_invalid_32bit = DEBUG_SUPPORT && debug_mode; d_rd = X0; d_aluop = ALUOP_SUB; d_branchcond = BCOND_ZERO;  end | ||||||
|  | @ -251,6 +253,7 @@ always @ (*) begin | ||||||
| 	RV_ECALL:   if (HAVE_CSR) begin d_except = EXCEPT_ECALL;  d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end | 	RV_ECALL:   if (HAVE_CSR) begin d_except = EXCEPT_ECALL;  d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end | ||||||
| 	RV_EBREAK:  if (HAVE_CSR) begin d_except = EXCEPT_EBREAK; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end | 	RV_EBREAK:  if (HAVE_CSR) begin d_except = EXCEPT_EBREAK; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end | ||||||
| 	RV_MRET:    if (HAVE_CSR) begin d_except = EXCEPT_MRET;   d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end | 	RV_MRET:    if (HAVE_CSR) begin d_except = EXCEPT_MRET;   d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end | ||||||
|  | 	RV_WFI:     if (HAVE_CSR) begin d_wfi = 1'b1;             d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end | ||||||
| 	default:    begin d_invalid_32bit = 1'b1; end | 	default:    begin d_invalid_32bit = 1'b1; end | ||||||
| 	endcase | 	endcase | ||||||
| 
 | 
 | ||||||
|  | @ -263,6 +266,7 @@ always @ (*) begin | ||||||
| 		d_csr_ren    = 1'b0; | 		d_csr_ren    = 1'b0; | ||||||
| 		d_csr_wen    = 1'b0; | 		d_csr_wen    = 1'b0; | ||||||
| 		d_except     = EXCEPT_NONE; | 		d_except     = EXCEPT_NONE; | ||||||
|  | 		d_wfi        = 1'b0; | ||||||
| 		if (EXTENSION_M) | 		if (EXTENSION_M) | ||||||
| 			d_aluop = ALUOP_ADD; | 			d_aluop = ALUOP_ADD; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -55,6 +55,7 @@ localparam RV_CSRRSI      = 32'b?????????????????110?????1110011; | ||||||
| localparam RV_CSRRCI      = 32'b?????????????????111?????1110011; | localparam RV_CSRRCI      = 32'b?????????????????111?????1110011; | ||||||
| localparam RV_MRET        = 32'b00110000001000000000000001110011; | localparam RV_MRET        = 32'b00110000001000000000000001110011; | ||||||
| localparam RV_SYSTEM      = 32'b?????????????????????????1110011; | localparam RV_SYSTEM      = 32'b?????????????????????????1110011; | ||||||
|  | localparam RV_WFI         = 32'b00010000010100000000000001110011; | ||||||
| 
 | 
 | ||||||
| // M extension | // M extension | ||||||
| localparam RV_MUL         = 32'b0000001??????????000?????0110011; | localparam RV_MUL         = 32'b0000001??????????000?????0110011; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue