aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2016-04-10 16:54:35 +0200
committerClifford Wolf <clifford@clifford.at>2016-04-10 16:54:35 +0200
commit00dd6ac38ee7e0b948a0a30d36f2e7a6fc2369ea (patch)
tree3e9c9c7b9fb8215da0a309cab8845e7bbb87d305
parent8f5845310950ee00dbc3084e76e3f11dd8493158 (diff)
downloadpicorv32-00dd6ac38ee7e0b948a0a30d36f2e7a6fc2369ea.tar.gz
picorv32-00dd6ac38ee7e0b948a0a30d36f2e7a6fc2369ea.zip
Added ENABLE_DIV and picorv32_pcpi_div
-rw-r--r--README.md11
-rw-r--r--firmware/start.S5
-rw-r--r--picorv32.v122
-rw-r--r--testbench.v1
-rw-r--r--tests/div.S41
-rw-r--r--tests/divu.S41
-rw-r--r--tests/rem.S41
-rw-r--r--tests/remu.S41
8 files changed, 298 insertions, 5 deletions
diff --git a/README.md b/README.md
index e35e270..ba27f0f 100644
--- a/README.md
+++ b/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
diff --git a/firmware/start.S b/firmware/start.S
index a5547b8..403ac24 100644
--- a/firmware/start.S
+++ b/firmware/start.S
@@ -435,6 +435,11 @@ start:
TEST(mulhu)
TEST(mul)
+ TEST(div)
+ TEST(divu)
+ TEST(rem)
+ TEST(remu)
+
TEST(simple)
/* set stack pointer */
diff --git a/picorv32.v b/picorv32.v
index 93a9a01..d163754 100644
--- a/picorv32.v
+++ b/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
@@ -1549,6 +1579,90 @@ 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 ),
diff --git a/testbench.v b/testbench.v
index ffbc13e..2a3f438 100644
--- a/testbench.v
+++ b/testbench.v
@@ -118,6 +118,7 @@ module picorv32_wrapper #(
.COMPRESSED_ISA(1),
`endif
.ENABLE_MUL(1),
+ .ENABLE_DIV(1),
.ENABLE_IRQ(1)
) uut (
.clk (clk ),
diff --git a/tests/div.S b/tests/div.S
new file mode 100644
index 0000000..a4504a7
--- /dev/null
+++ b/tests/div.S
@@ -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
diff --git a/tests/divu.S b/tests/divu.S
new file mode 100644
index 0000000..cd348c9
--- /dev/null
+++ b/tests/divu.S
@@ -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
diff --git a/tests/rem.S b/tests/rem.S
new file mode 100644
index 0000000..c318e2c
--- /dev/null
+++ b/tests/rem.S
@@ -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
diff --git a/tests/remu.S b/tests/remu.S
new file mode 100644
index 0000000..38d641d
--- /dev/null
+++ b/tests/remu.S
@@ -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