Added ENABLE_DIV and picorv32_pcpi_div
This commit is contained in:
		
							parent
							
								
									8f58453109
								
							
						
					
					
						commit
						00dd6ac38e
					
				
							
								
								
									
										11
									
								
								README.md
								
								
								
								
							
							
						
						
									
										11
									
								
								README.md
								
								
								
								
							|  | @ -67,8 +67,9 @@ fault handlers, or catch instructions from a larger ISA and emulate them in | |||
| software. | ||||
| 
 | ||||
| The optional Pico Co-Processor Interface (PCPI) can be used to implement | ||||
| non-branching instructions in an external coprocessor. An implementation | ||||
| of a core that implements the `MUL[H[SU|U]]` instructions is provided. | ||||
| non-branching instructions in an external coprocessor. Implementations | ||||
| of PCPI cores that implement the M Standard Extension instructions | ||||
| `MUL[H[SU|U]]` and `DIV[U]/REM[U]` are included in this package. | ||||
| 
 | ||||
| 
 | ||||
| Files in this Repository | ||||
|  | @ -209,6 +210,12 @@ This parameter internally enables PCPI and instantiates the `picorv32_pcpi_mul` | |||
| core that implements the `MUL[H[SU|U]]` instructions. The external PCPI | ||||
| interface only becomes functional when ENABLE_PCPI is set as well. | ||||
| 
 | ||||
| #### ENABLE_DIV (default = 0) | ||||
| 
 | ||||
| This parameter internally enables PCPI and instantiates the `picorv32_pcpi_div` | ||||
| core that implements the `DIV[U]/REM[U]` instructions. The external PCPI | ||||
| interface only becomes functional when ENABLE_PCPI is set as well. | ||||
| 
 | ||||
| #### ENABLE_IRQ (default = 0) | ||||
| 
 | ||||
| Set this to 1 to enable IRQs. (see "Custom Instructions for IRQ Handling" below | ||||
|  |  | |||
|  | @ -435,6 +435,11 @@ start: | |||
| 	TEST(mulhu) | ||||
| 	TEST(mul) | ||||
| 
 | ||||
| 	TEST(div) | ||||
| 	TEST(divu) | ||||
| 	TEST(rem) | ||||
| 	TEST(remu) | ||||
| 
 | ||||
| 	TEST(simple) | ||||
| 
 | ||||
| 	/* set stack pointer */ | ||||
|  |  | |||
							
								
								
									
										122
									
								
								picorv32.v
								
								
								
								
							
							
						
						
									
										122
									
								
								picorv32.v
								
								
								
								
							|  | @ -50,6 +50,7 @@ module picorv32 #( | |||
| 	parameter [ 0:0] CATCH_ILLINSN = 1, | ||||
| 	parameter [ 0:0] ENABLE_PCPI = 0, | ||||
| 	parameter [ 0:0] ENABLE_MUL = 0, | ||||
| 	parameter [ 0:0] ENABLE_DIV = 0, | ||||
| 	parameter [ 0:0] ENABLE_IRQ = 0, | ||||
| 	parameter [ 0:0] ENABLE_IRQ_QREGS = 1, | ||||
| 	parameter [ 0:0] ENABLE_IRQ_TIMER = 1, | ||||
|  | @ -99,7 +100,7 @@ module picorv32 #( | |||
| 	localparam integer regfile_size = (ENABLE_REGS_16_31 ? 32 : 16) + 4*ENABLE_IRQ*ENABLE_IRQ_QREGS; | ||||
| 	localparam integer regindex_bits = (ENABLE_REGS_16_31 ? 5 : 4) + ENABLE_IRQ*ENABLE_IRQ_QREGS; | ||||
| 
 | ||||
| 	localparam WITH_PCPI = ENABLE_PCPI || ENABLE_MUL; | ||||
| 	localparam WITH_PCPI = ENABLE_PCPI || ENABLE_MUL || ENABLE_DIV; | ||||
| 
 | ||||
| 	reg [63:0] count_cycle, count_instr; | ||||
| 	reg [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out; | ||||
|  | @ -127,6 +128,11 @@ module picorv32 #( | |||
| 	wire        pcpi_mul_wait; | ||||
| 	wire        pcpi_mul_ready; | ||||
| 
 | ||||
| 	wire        pcpi_div_wr; | ||||
| 	wire [31:0] pcpi_div_rd; | ||||
| 	wire        pcpi_div_wait; | ||||
| 	wire        pcpi_div_ready; | ||||
| 
 | ||||
| 	reg        pcpi_int_wr; | ||||
| 	reg [31:0] pcpi_int_rd; | ||||
| 	reg        pcpi_int_wait; | ||||
|  | @ -152,11 +158,31 @@ module picorv32 #( | |||
| 		assign pcpi_mul_ready = 0; | ||||
| 	end endgenerate | ||||
| 
 | ||||
| 	generate if (ENABLE_DIV) begin | ||||
| 		picorv32_pcpi_div pcpi_div ( | ||||
| 			.clk       (clk            ), | ||||
| 			.resetn    (resetn         ), | ||||
| 			.pcpi_valid(pcpi_valid     ), | ||||
| 			.pcpi_insn (pcpi_insn      ), | ||||
| 			.pcpi_rs1  (pcpi_rs1       ), | ||||
| 			.pcpi_rs2  (pcpi_rs2       ), | ||||
| 			.pcpi_wr   (pcpi_div_wr    ), | ||||
| 			.pcpi_rd   (pcpi_div_rd    ), | ||||
| 			.pcpi_wait (pcpi_div_wait  ), | ||||
| 			.pcpi_ready(pcpi_div_ready ) | ||||
| 		); | ||||
| 	end else begin | ||||
| 		assign pcpi_div_wr = 0; | ||||
| 		assign pcpi_div_rd = 1'bx; | ||||
| 		assign pcpi_div_wait = 0; | ||||
| 		assign pcpi_div_ready = 0; | ||||
| 	end endgenerate | ||||
| 
 | ||||
| 	always @* begin | ||||
| 		pcpi_int_wr = 0; | ||||
| 		pcpi_int_rd = 1'bx; | ||||
| 		pcpi_int_wait  = |{ENABLE_PCPI && pcpi_wait,  ENABLE_MUL && pcpi_mul_wait}; | ||||
| 		pcpi_int_ready = |{ENABLE_PCPI && pcpi_ready, ENABLE_MUL && pcpi_mul_ready}; | ||||
| 		pcpi_int_wait  = |{ENABLE_PCPI && pcpi_wait,  ENABLE_MUL && pcpi_mul_wait,  ENABLE_DIV && pcpi_div_wait}; | ||||
| 		pcpi_int_ready = |{ENABLE_PCPI && pcpi_ready, ENABLE_MUL && pcpi_mul_ready, ENABLE_DIV && pcpi_div_ready}; | ||||
| 
 | ||||
| 		(* parallel_case *) | ||||
| 		case (1'b1) | ||||
|  | @ -168,6 +194,10 @@ module picorv32 #( | |||
| 				pcpi_int_wr = pcpi_mul_wr; | ||||
| 				pcpi_int_rd = pcpi_mul_rd; | ||||
| 			end | ||||
| 			ENABLE_DIV && pcpi_div_ready: begin | ||||
| 				pcpi_int_wr = pcpi_div_wr; | ||||
| 				pcpi_int_rd = pcpi_div_rd; | ||||
| 			end | ||||
| 		endcase | ||||
| 	end | ||||
| 
 | ||||
|  | @ -1548,6 +1578,90 @@ module picorv32_pcpi_mul #( | |||
| endmodule | ||||
| 
 | ||||
| 
 | ||||
| /*************************************************************** | ||||
|  * picorv32_pcpi_div | ||||
|  ***************************************************************/ | ||||
| 
 | ||||
| module picorv32_pcpi_div ( | ||||
| 	input clk, resetn, | ||||
| 
 | ||||
| 	input             pcpi_valid, | ||||
| 	input      [31:0] pcpi_insn, | ||||
| 	input      [31:0] pcpi_rs1, | ||||
| 	input      [31:0] pcpi_rs2, | ||||
| 	output reg        pcpi_wr, | ||||
| 	output reg [31:0] pcpi_rd, | ||||
| 	output reg        pcpi_wait, | ||||
| 	output reg        pcpi_ready | ||||
| ); | ||||
| 	reg instr_div, instr_divu, instr_rem, instr_remu; | ||||
| 	wire instr_any_div_rem = |{instr_div, instr_divu, instr_rem, instr_remu}; | ||||
| 
 | ||||
| 	reg pcpi_wait_q; | ||||
| 	wire start = pcpi_wait && !pcpi_wait_q; | ||||
| 
 | ||||
| 	always @(posedge clk) begin | ||||
| 		instr_div <= 0; | ||||
| 		instr_divu <= 0; | ||||
| 		instr_rem <= 0; | ||||
| 		instr_remu <= 0; | ||||
| 
 | ||||
| 		if (resetn && pcpi_valid && !pcpi_ready && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin | ||||
| 			case (pcpi_insn[14:12]) | ||||
| 				3'b100: instr_div <= 1; | ||||
| 				3'b101: instr_divu <= 1; | ||||
| 				3'b110: instr_rem <= 1; | ||||
| 				3'b111: instr_remu <= 1; | ||||
| 			endcase | ||||
| 		end | ||||
| 
 | ||||
| 		pcpi_wait <= instr_any_div_rem; | ||||
| 		pcpi_wait_q <= pcpi_wait; | ||||
| 	end | ||||
| 
 | ||||
| 	reg [31:0] dividend; | ||||
| 	reg [62:0] divisor; | ||||
| 	reg [31:0] quotient; | ||||
| 	reg [31:0] quotient_msk; | ||||
| 	reg running; | ||||
| 	reg outsign; | ||||
| 
 | ||||
| 	always @(posedge clk) begin | ||||
| 		pcpi_ready <= 0; | ||||
| 		pcpi_wr <= 0; | ||||
| 		pcpi_rd <= 'bx; | ||||
| 
 | ||||
| 		if (!resetn) begin | ||||
| 			running <= 0; | ||||
| 		end else | ||||
| 		if (start) begin | ||||
| 			running <= 1; | ||||
| 			dividend <= (instr_div || instr_rem) && pcpi_rs1[31] ? -pcpi_rs1 : pcpi_rs1; | ||||
| 			divisor <= ((instr_div || instr_rem) && pcpi_rs2[31] ? -pcpi_rs2 : pcpi_rs2) << 31; | ||||
| 			outsign <= (instr_div && (pcpi_rs1[31] != pcpi_rs2[31])) || (instr_rem && pcpi_rs1[31]); | ||||
| 			quotient <= 0; | ||||
| 			quotient_msk <= 1 << 31; | ||||
| 		end else | ||||
| 		if (!quotient_msk && running) begin | ||||
| 			running <= 0; | ||||
| 			pcpi_ready <= 1; | ||||
| 			pcpi_wr <= 1; | ||||
| 			if (instr_div || instr_divu) | ||||
| 				pcpi_rd <= outsign ? -quotient : quotient; | ||||
| 			else | ||||
| 				pcpi_rd <= outsign ? -dividend : dividend; | ||||
| 		end else begin | ||||
| 			if (divisor <= dividend) begin | ||||
| 				dividend <= dividend - divisor; | ||||
| 				quotient <= quotient | quotient_msk; | ||||
| 			end | ||||
| 			divisor <= divisor >> 1; | ||||
| 			quotient_msk <= quotient_msk >> 1; | ||||
| 		end | ||||
| 	end | ||||
| endmodule | ||||
| 
 | ||||
| 
 | ||||
| /*************************************************************** | ||||
|  * picorv32_axi | ||||
|  ***************************************************************/ | ||||
|  | @ -1564,6 +1678,7 @@ module picorv32_axi #( | |||
| 	parameter [ 0:0] CATCH_ILLINSN = 1, | ||||
| 	parameter [ 0:0] ENABLE_PCPI = 0, | ||||
| 	parameter [ 0:0] ENABLE_MUL = 0, | ||||
| 	parameter [ 0:0] ENABLE_DIV = 0, | ||||
| 	parameter [ 0:0] ENABLE_IRQ = 0, | ||||
| 	parameter [ 0:0] ENABLE_IRQ_QREGS = 1, | ||||
| 	parameter [ 0:0] ENABLE_IRQ_TIMER = 1, | ||||
|  | @ -1662,6 +1777,7 @@ module picorv32_axi #( | |||
| 		.CATCH_ILLINSN       (CATCH_ILLINSN       ), | ||||
| 		.ENABLE_PCPI         (ENABLE_PCPI         ), | ||||
| 		.ENABLE_MUL          (ENABLE_MUL          ), | ||||
| 		.ENABLE_DIV          (ENABLE_DIV          ), | ||||
| 		.ENABLE_IRQ          (ENABLE_IRQ          ), | ||||
| 		.ENABLE_IRQ_QREGS    (ENABLE_IRQ_QREGS    ), | ||||
| 		.ENABLE_IRQ_TIMER    (ENABLE_IRQ_TIMER    ), | ||||
|  |  | |||
|  | @ -118,6 +118,7 @@ module picorv32_wrapper #( | |||
| 		.COMPRESSED_ISA(1), | ||||
| `endif | ||||
| 		.ENABLE_MUL(1), | ||||
| 		.ENABLE_DIV(1), | ||||
| 		.ENABLE_IRQ(1) | ||||
| 	) uut ( | ||||
| 		.clk            (clk            ), | ||||
|  |  | |||
|  | @ -0,0 +1,41 @@ | |||
| # See LICENSE for license details. | ||||
| 
 | ||||
| #***************************************************************************** | ||||
| # div.S | ||||
| #----------------------------------------------------------------------------- | ||||
| # | ||||
| # Test div instruction. | ||||
| # | ||||
| 
 | ||||
| #include "riscv_test.h" | ||||
| #include "test_macros.h" | ||||
| 
 | ||||
| RVTEST_RV32U | ||||
| RVTEST_CODE_BEGIN | ||||
| 
 | ||||
|   #------------------------------------------------------------- | ||||
|   # Arithmetic tests | ||||
|   #------------------------------------------------------------- | ||||
| 
 | ||||
|   TEST_RR_OP( 2, div,  3,  20,   6 );
 | ||||
|   TEST_RR_OP( 3, div, -3, -20,   6 );
 | ||||
|   TEST_RR_OP( 4, div, -3,  20,  -6 );
 | ||||
|   TEST_RR_OP( 5, div,  3, -20,  -6 );
 | ||||
| 
 | ||||
|   TEST_RR_OP( 6, div, -1<<63, -1<<63,  1 );
 | ||||
|   TEST_RR_OP( 7, div, -1<<63, -1<<63, -1 );
 | ||||
| 
 | ||||
|   TEST_RR_OP( 8, div, -1, -1<<63, 0 );
 | ||||
|   TEST_RR_OP( 9, div, -1,      1, 0 );
 | ||||
|   TEST_RR_OP(10, div, -1,      0, 0 );
 | ||||
| 
 | ||||
|   TEST_PASSFAIL | ||||
| 
 | ||||
| RVTEST_CODE_END | ||||
| 
 | ||||
|   .data | ||||
| RVTEST_DATA_BEGIN | ||||
| 
 | ||||
|   TEST_DATA | ||||
| 
 | ||||
| RVTEST_DATA_END | ||||
|  | @ -0,0 +1,41 @@ | |||
| # See LICENSE for license details. | ||||
| 
 | ||||
| #***************************************************************************** | ||||
| # divu.S | ||||
| #----------------------------------------------------------------------------- | ||||
| # | ||||
| # Test divu instruction. | ||||
| # | ||||
| 
 | ||||
| #include "riscv_test.h" | ||||
| #include "test_macros.h" | ||||
| 
 | ||||
| RVTEST_RV32U | ||||
| RVTEST_CODE_BEGIN | ||||
| 
 | ||||
|   #------------------------------------------------------------- | ||||
|   # Arithmetic tests | ||||
|   #------------------------------------------------------------- | ||||
| 
 | ||||
|   TEST_RR_OP( 2, divu,                   3,  20,   6 );
 | ||||
|   TEST_RR_OP( 3, divu,           715827879, -20,   6 );
 | ||||
|   TEST_RR_OP( 4, divu,                   0,  20,  -6 );
 | ||||
|   TEST_RR_OP( 5, divu,                   0, -20,  -6 );
 | ||||
| 
 | ||||
|   TEST_RR_OP( 6, divu, -1<<31, -1<<31,  1 );
 | ||||
|   TEST_RR_OP( 7, divu,     0,  -1<<31, -1 );
 | ||||
| 
 | ||||
|   TEST_RR_OP( 8, divu, -1, -1<<31, 0 );
 | ||||
|   TEST_RR_OP( 9, divu, -1,      1, 0 );
 | ||||
|   TEST_RR_OP(10, divu, -1,      0, 0 );
 | ||||
| 
 | ||||
|   TEST_PASSFAIL | ||||
| 
 | ||||
| RVTEST_CODE_END | ||||
| 
 | ||||
|   .data | ||||
| RVTEST_DATA_BEGIN | ||||
| 
 | ||||
|   TEST_DATA | ||||
| 
 | ||||
| RVTEST_DATA_END | ||||
|  | @ -0,0 +1,41 @@ | |||
| # See LICENSE for license details. | ||||
| 
 | ||||
| #***************************************************************************** | ||||
| # rem.S | ||||
| #----------------------------------------------------------------------------- | ||||
| # | ||||
| # Test rem instruction. | ||||
| # | ||||
| 
 | ||||
| #include "riscv_test.h" | ||||
| #include "test_macros.h" | ||||
| 
 | ||||
| RVTEST_RV32U | ||||
| RVTEST_CODE_BEGIN | ||||
| 
 | ||||
|   #------------------------------------------------------------- | ||||
|   # Arithmetic tests | ||||
|   #------------------------------------------------------------- | ||||
| 
 | ||||
|   TEST_RR_OP( 2, rem,  2,  20,   6 );
 | ||||
|   TEST_RR_OP( 3, rem, -2, -20,   6 );
 | ||||
|   TEST_RR_OP( 4, rem,  2,  20,  -6 );
 | ||||
|   TEST_RR_OP( 5, rem, -2, -20,  -6 );
 | ||||
| 
 | ||||
|   TEST_RR_OP( 6, rem,  0, -1<<63,  1 );
 | ||||
|   TEST_RR_OP( 7, rem,  0, -1<<63, -1 );
 | ||||
| 
 | ||||
|   TEST_RR_OP( 8, rem, -1<<63, -1<<63, 0 );
 | ||||
|   TEST_RR_OP( 9, rem,      1,      1, 0 );
 | ||||
|   TEST_RR_OP(10, rem,      0,      0, 0 );
 | ||||
| 
 | ||||
|   TEST_PASSFAIL | ||||
| 
 | ||||
| RVTEST_CODE_END | ||||
| 
 | ||||
|   .data | ||||
| RVTEST_DATA_BEGIN | ||||
| 
 | ||||
|   TEST_DATA | ||||
| 
 | ||||
| RVTEST_DATA_END | ||||
|  | @ -0,0 +1,41 @@ | |||
| # See LICENSE for license details. | ||||
| 
 | ||||
| #***************************************************************************** | ||||
| # remu.S | ||||
| #----------------------------------------------------------------------------- | ||||
| # | ||||
| # Test remu instruction. | ||||
| # | ||||
| 
 | ||||
| #include "riscv_test.h" | ||||
| #include "test_macros.h" | ||||
| 
 | ||||
| RVTEST_RV32U | ||||
| RVTEST_CODE_BEGIN | ||||
| 
 | ||||
|   #------------------------------------------------------------- | ||||
|   # Arithmetic tests | ||||
|   #------------------------------------------------------------- | ||||
| 
 | ||||
|   TEST_RR_OP( 2, remu,   2,  20,   6 );
 | ||||
|   TEST_RR_OP( 3, remu,   2, -20,   6 );
 | ||||
|   TEST_RR_OP( 4, remu,  20,  20,  -6 );
 | ||||
|   TEST_RR_OP( 5, remu, -20, -20,  -6 );
 | ||||
| 
 | ||||
|   TEST_RR_OP( 6, remu,      0, -1<<63,  1 );
 | ||||
|   TEST_RR_OP( 7, remu, -1<<63, -1<<63, -1 );
 | ||||
| 
 | ||||
|   TEST_RR_OP( 8, remu, -1<<63, -1<<63, 0 );
 | ||||
|   TEST_RR_OP( 9, remu,      1,      1, 0 );
 | ||||
|   TEST_RR_OP(10, remu,      0,      0, 0 );
 | ||||
| 
 | ||||
|   TEST_PASSFAIL | ||||
| 
 | ||||
| RVTEST_CODE_END | ||||
| 
 | ||||
|   .data | ||||
| RVTEST_DATA_BEGIN | ||||
| 
 | ||||
|   TEST_DATA | ||||
| 
 | ||||
| RVTEST_DATA_END | ||||
		Loading…
	
		Reference in New Issue