mirror of https://github.com/YosysHQ/picorv32.git
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.
|
software.
|
||||||
|
|
||||||
The optional Pico Co-Processor Interface (PCPI) can be used to implement
|
The optional Pico Co-Processor Interface (PCPI) can be used to implement
|
||||||
non-branching instructions in an external coprocessor. An implementation
|
non-branching instructions in an external coprocessor. Implementations
|
||||||
of a core that implements the `MUL[H[SU|U]]` instructions is provided.
|
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
|
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
|
core that implements the `MUL[H[SU|U]]` instructions. The external PCPI
|
||||||
interface only becomes functional when ENABLE_PCPI is set as well.
|
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)
|
#### ENABLE_IRQ (default = 0)
|
||||||
|
|
||||||
Set this to 1 to enable IRQs. (see "Custom Instructions for IRQ Handling" below
|
Set this to 1 to enable IRQs. (see "Custom Instructions for IRQ Handling" below
|
||||||
|
|
|
@ -435,6 +435,11 @@ start:
|
||||||
TEST(mulhu)
|
TEST(mulhu)
|
||||||
TEST(mul)
|
TEST(mul)
|
||||||
|
|
||||||
|
TEST(div)
|
||||||
|
TEST(divu)
|
||||||
|
TEST(rem)
|
||||||
|
TEST(remu)
|
||||||
|
|
||||||
TEST(simple)
|
TEST(simple)
|
||||||
|
|
||||||
/* set stack pointer */
|
/* set stack pointer */
|
||||||
|
|
122
picorv32.v
122
picorv32.v
|
@ -50,6 +50,7 @@ module picorv32 #(
|
||||||
parameter [ 0:0] CATCH_ILLINSN = 1,
|
parameter [ 0:0] CATCH_ILLINSN = 1,
|
||||||
parameter [ 0:0] ENABLE_PCPI = 0,
|
parameter [ 0:0] ENABLE_PCPI = 0,
|
||||||
parameter [ 0:0] ENABLE_MUL = 0,
|
parameter [ 0:0] ENABLE_MUL = 0,
|
||||||
|
parameter [ 0:0] ENABLE_DIV = 0,
|
||||||
parameter [ 0:0] ENABLE_IRQ = 0,
|
parameter [ 0:0] ENABLE_IRQ = 0,
|
||||||
parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
|
parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
|
||||||
parameter [ 0:0] ENABLE_IRQ_TIMER = 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 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 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 [63:0] count_cycle, count_instr;
|
||||||
reg [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out;
|
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_wait;
|
||||||
wire pcpi_mul_ready;
|
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 pcpi_int_wr;
|
||||||
reg [31:0] pcpi_int_rd;
|
reg [31:0] pcpi_int_rd;
|
||||||
reg pcpi_int_wait;
|
reg pcpi_int_wait;
|
||||||
|
@ -152,11 +158,31 @@ module picorv32 #(
|
||||||
assign pcpi_mul_ready = 0;
|
assign pcpi_mul_ready = 0;
|
||||||
end endgenerate
|
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
|
always @* begin
|
||||||
pcpi_int_wr = 0;
|
pcpi_int_wr = 0;
|
||||||
pcpi_int_rd = 1'bx;
|
pcpi_int_rd = 1'bx;
|
||||||
pcpi_int_wait = |{ENABLE_PCPI && pcpi_wait, ENABLE_MUL && pcpi_mul_wait};
|
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};
|
pcpi_int_ready = |{ENABLE_PCPI && pcpi_ready, ENABLE_MUL && pcpi_mul_ready, ENABLE_DIV && pcpi_div_ready};
|
||||||
|
|
||||||
(* parallel_case *)
|
(* parallel_case *)
|
||||||
case (1'b1)
|
case (1'b1)
|
||||||
|
@ -168,6 +194,10 @@ module picorv32 #(
|
||||||
pcpi_int_wr = pcpi_mul_wr;
|
pcpi_int_wr = pcpi_mul_wr;
|
||||||
pcpi_int_rd = pcpi_mul_rd;
|
pcpi_int_rd = pcpi_mul_rd;
|
||||||
end
|
end
|
||||||
|
ENABLE_DIV && pcpi_div_ready: begin
|
||||||
|
pcpi_int_wr = pcpi_div_wr;
|
||||||
|
pcpi_int_rd = pcpi_div_rd;
|
||||||
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1548,6 +1578,90 @@ module picorv32_pcpi_mul #(
|
||||||
endmodule
|
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
|
* picorv32_axi
|
||||||
***************************************************************/
|
***************************************************************/
|
||||||
|
@ -1564,6 +1678,7 @@ module picorv32_axi #(
|
||||||
parameter [ 0:0] CATCH_ILLINSN = 1,
|
parameter [ 0:0] CATCH_ILLINSN = 1,
|
||||||
parameter [ 0:0] ENABLE_PCPI = 0,
|
parameter [ 0:0] ENABLE_PCPI = 0,
|
||||||
parameter [ 0:0] ENABLE_MUL = 0,
|
parameter [ 0:0] ENABLE_MUL = 0,
|
||||||
|
parameter [ 0:0] ENABLE_DIV = 0,
|
||||||
parameter [ 0:0] ENABLE_IRQ = 0,
|
parameter [ 0:0] ENABLE_IRQ = 0,
|
||||||
parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
|
parameter [ 0:0] ENABLE_IRQ_QREGS = 1,
|
||||||
parameter [ 0:0] ENABLE_IRQ_TIMER = 1,
|
parameter [ 0:0] ENABLE_IRQ_TIMER = 1,
|
||||||
|
@ -1662,6 +1777,7 @@ module picorv32_axi #(
|
||||||
.CATCH_ILLINSN (CATCH_ILLINSN ),
|
.CATCH_ILLINSN (CATCH_ILLINSN ),
|
||||||
.ENABLE_PCPI (ENABLE_PCPI ),
|
.ENABLE_PCPI (ENABLE_PCPI ),
|
||||||
.ENABLE_MUL (ENABLE_MUL ),
|
.ENABLE_MUL (ENABLE_MUL ),
|
||||||
|
.ENABLE_DIV (ENABLE_DIV ),
|
||||||
.ENABLE_IRQ (ENABLE_IRQ ),
|
.ENABLE_IRQ (ENABLE_IRQ ),
|
||||||
.ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ),
|
.ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ),
|
||||||
.ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ),
|
.ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ),
|
||||||
|
|
|
@ -118,6 +118,7 @@ module picorv32_wrapper #(
|
||||||
.COMPRESSED_ISA(1),
|
.COMPRESSED_ISA(1),
|
||||||
`endif
|
`endif
|
||||||
.ENABLE_MUL(1),
|
.ENABLE_MUL(1),
|
||||||
|
.ENABLE_DIV(1),
|
||||||
.ENABLE_IRQ(1)
|
.ENABLE_IRQ(1)
|
||||||
) uut (
|
) uut (
|
||||||
.clk (clk ),
|
.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