diff --git a/lacpu/README.md b/lacpu/README.md index 41e6b3d..1492953 100755 --- a/lacpu/README.md +++ b/lacpu/README.md @@ -18,13 +18,13 @@ - [x] `0 0 0 0 0 0 1` 开头, `0 0 0` - `1 1 1` 中间有缺项。 共 6 项:**slti, sltui, addi.w andi, ori, xori** - [x] `0 0 1 0 1 0 0` 开头,`0 0 0` - `1 1 0`。共 6 项:**ld.b, ld.h, ld.w, st.b, st.h, st.w** -- [x] `0 0 1 0 1 0 1` 开头,`0 0 0` - `0 0 1`。共 3 项:**ld.bu, ld.hu**, preld +- [ ] `0 0 1 0 1 0 1` 开头,`0 0 0` - `0 0 1`。共 3 项:**ld.bu, ld.hu**, preld #### op17 - [x] `0 0 0 0 0 0 0 0 0 0 0 1` 开头,`0 0 0 0 0` - `1 0 0 0 0` 中间有缺项。共 11 项:**add.w, sub.w, slt, sltu, nor, and, or, xor, sll.w, srl.w, sra.w** -- [ ] `0 0 0 0 0 0 0 0 0 0 0 1` 开头,`1 1 0 0 0` - `1 1 0 1 0` 。共 3 项:mul.w, mulh.w, mulh.wu -- [ ] `0 0 0 0 0 0 0 0 0 0 1 0` 开头,`0 0 0 0 0` - `0 0 0 1 1`。共 4 项:div.w, mod.w, div.wu, mod.wu +- [x] `0 0 0 0 0 0 0 0 0 0 0 1` 开头,`1 1 0 0 0` - `1 1 0 1 0` 。共 3 项:**mul.w, mulh.w, mulh.wu** +- [x] `0 0 0 0 0 0 0 0 0 0 1 0` 开头,`0 0 0 0 0` - `0 0 0 1 1`。共 4 项:**div.w, mod.w, div.wu, mod.wu** - [x] `0 0 0 0 0 0 0 0 0 1 0 0` 开头,`0 0` - `1 0` + `0 0 1`。共 3 项:**slli.w, srli.w, srai.w** - [ ] `0 0 1 1 1 0 0 0 0 1 1 1` 开头,`0 0 1 0 0` - `0 0 1 0 1` 。共 2 项:dbar, ibar diff --git a/lacpu/doc/龙芯架构32位精简版参考手册.pdf b/lacpu/doc/龙芯架构32位精简版参考手册.pdf index e2a71b5..5c826bc 100755 Binary files a/lacpu/doc/龙芯架构32位精简版参考手册.pdf and b/lacpu/doc/龙芯架构32位精简版参考手册.pdf differ diff --git a/lacpu/rtl/cpu/cpu_top.v b/lacpu/rtl/cpu/cpu_top.v index 64c6333..8a95379 100755 --- a/lacpu/rtl/cpu/cpu_top.v +++ b/lacpu/rtl/cpu/cpu_top.v @@ -15,6 +15,24 @@ module mycpu_top( output [31:0] data_sram_addr, output [31:0] data_sram_wdata, input [31:0] data_sram_rdata, + //div + output [31:0] div_divisor_data, + output div_divisor_valid, + input div_divisor_ready, + output [31:0] div_dividend_data, + output div_dividend_valid, + input div_dividend_ready, + input div_dout_valid, + input [63:0] div_dout_data, + //divu + output [31:0] divu_divisor_data, + output divu_divisor_valid, + input divu_divisor_ready, + output [31:0] divu_dividend_data, + output divu_dividend_valid, + input divu_dividend_ready, + input divu_dout_valid, + input [63:0] divu_dout_data, // trace debug interface output [31:0] debug_wb_pc, output [ 3:0] debug_wb_rf_wen, @@ -107,7 +125,25 @@ module mycpu_top( .data_sram_en (data_sram_en ), .data_sram_wen (data_sram_wen ), .data_sram_addr (data_sram_addr ), - .data_sram_wdata(data_sram_wdata) + .data_sram_wdata(data_sram_wdata), + //div + .div_divisor_data (div_divisor_data ), + .div_divisor_valid (div_divisor_valid ), + .div_divisor_ready (div_divisor_ready ), + .div_dividend_data (div_dividend_data ), + .div_dividend_valid (div_dividend_valid ), + .div_dividend_ready (div_dividend_ready ), + .div_dout_valid (div_dout_valid ), + .div_dout_data (div_dout_data ), + //divu + .divu_divisor_data (divu_divisor_data ), + .divu_divisor_valid (divu_divisor_valid ), + .divu_divisor_ready (divu_divisor_ready ), + .divu_dividend_data (divu_dividend_data ), + .divu_dividend_valid(divu_dividend_valid), + .divu_dividend_ready(divu_dividend_ready), + .divu_dout_valid (divu_dout_valid ), + .divu_dout_data (divu_dout_data ) ); // MEM stage mem_stage mem_stage( diff --git a/lacpu/rtl/cpu/exe_stage.v b/lacpu/rtl/cpu/exe_stage.v index f777956..8fe8d8f 100755 --- a/lacpu/rtl/cpu/exe_stage.v +++ b/lacpu/rtl/cpu/exe_stage.v @@ -24,14 +24,32 @@ module exe_stage( //from ms input [`MS_TO_ES_BUS_WD -1:0] ms_to_ds_bus , //from ws - input [`WS_TO_ES_BUS_WD -1:0] ws_to_ds_bus + input [`WS_TO_ES_BUS_WD -1:0] ws_to_ds_bus , + //div + output [31:0] div_divisor_data , + output div_divisor_valid , + input div_divisor_ready , + output [31:0] div_dividend_data , + output div_dividend_valid , + input div_dividend_ready , + input div_dout_valid , + input [63:0] div_dout_data , + //divu + output [31:0] divu_divisor_data , + output divu_divisor_valid , + input divu_divisor_ready , + output [31:0] divu_dividend_data , + output divu_dividend_valid , + input divu_dividend_ready , + input divu_dout_valid , + input [63:0] divu_dout_data ); reg es_valid ; wire es_ready_go ; reg [`DS_TO_ES_BUS_WD -1:0] ds_to_es_bus_r; - wire [11:0] es_alu_op; + wire [18:0] es_alu_op; wire es_src1_is_pc; wire es_src2_is_imm; wire es_src2_is_4; @@ -56,8 +74,7 @@ module exe_stage( wire es_src2_is_ms_dest; wire es_data_is_rf_wdata; - - assign {es_alu_op , //169:155 + assign {es_alu_op , //173:155 es_src1_is_pc , //154:154 es_src2_is_imm , //153:153 es_src2_is_4 , //152:152 @@ -93,6 +110,26 @@ module exe_stage( wire es_Sign ; wire es_Overflow ; wire es_Zero ; + wire [31:0] es_result ; + + reg div_divisor_valid_reg; + reg div_divisor_ready_flag; + reg div_dividend_valid_reg; + reg div_dividend_ready_flag; + reg divu_divisor_valid_reg; + reg divu_divisor_ready_flag; + reg divu_dividend_valid_reg; + reg divu_dividend_ready_flag; + + wire es_inst_divw ; + wire es_inst_modw ; + wire es_inst_divwu; + wire es_inst_modwu; + wire is_div_mod; + + wire [31:0] div_mod_result; + + assign es_result = is_div_mod ? div_mod_result : es_alu_result; assign es_to_ms_bus = {br_target , //120:89 es_branch_op , //88 :80 @@ -104,7 +141,7 @@ module exe_stage( es_mem_to_reg , //70 :70 es_reg_we , //69 :69 es_dest , //68 :64 - es_alu_result , //63 :32 + es_result , //63 :32 es_pc //31 :0 }; @@ -114,7 +151,7 @@ module exe_stage( es_mem_we }; - assign es_ready_go = 1'b1; + assign es_ready_go = (is_div_mod && !(div_dout_valid || divu_dout_valid)) ? 1'b1 : 1'b0; assign es_allowin = !es_valid || es_ready_go && ms_allowin; assign es_to_ms_valid = es_valid && es_ready_go; always @(posedge clk) begin @@ -140,8 +177,95 @@ module exe_stage( es_src2_is_ms_dest ? ws_rf_wdata : es_rf_rdata2; + assign is_div_mod = es_inst_divw | es_inst_modw | es_inst_divwu | es_inst_modwu; + assign es_inst_divw = es_alu_op[15]; + assign es_inst_modw = es_alu_op[16]; + assign es_inst_divwu = es_alu_op[17]; + assign es_inst_modwu = es_alu_op[18]; + + assign div_divisor_data = es_alu_src1; + assign div_dividend_data = es_alu_src2; + assign divu_divisor_data = es_alu_src1; + assign divu_dividend_data = es_alu_src2; + + always @(posedge clk) begin + if(reset) begin + div_divisor_valid_reg <= 0'b0; + div_divisor_ready_flag <= 0'b0; + end + else if(div_divisor_valid_reg && div_divisor_ready) begin + div_divisor_valid_reg <= 0'b0; + div_divisor_ready_flag <= 0'b1; + end + else if((es_inst_divw || es_inst_modw) && !div_divisor_ready_flag) begin + div_divisor_valid_reg <= 0'b1; + end + else if(es_ready_go) begin + div_divisor_ready_flag <= 1'b0; + end + end + always @(posedge clk) begin + if(reset) begin + div_dividend_valid_reg <= 0'b0; + div_dividend_ready_flag <= 0'b0; + end + else if(div_dividend_valid_reg && div_dividend_ready) begin + div_dividend_valid_reg <= 0'b0; + div_dividend_ready_flag <= 0'b1; + end + else if((es_inst_divw || es_inst_modw) && !div_dividend_ready_flag) begin + div_dividend_valid_reg <= 0'b1; + end + else if(es_ready_go) begin + div_dividend_ready_flag <= 1'b0; + end + end + always @(posedge clk) begin + if(reset) begin + divu_divisor_valid_reg <= 0'b0; + divu_divisor_ready_flag <= 0'b0; + end + else if(divu_divisor_valid_reg && divu_divisor_ready) begin + divu_divisor_valid_reg <= 0'b0; + divu_divisor_ready_flag <= 0'b1; + end + else if((es_inst_divw || es_inst_modw) && !divu_divisor_ready_flag) begin + divu_divisor_valid_reg <= 0'b1; + end + else if(es_ready_go) begin + divu_divisor_ready_flag <= 1'b0; + end + end + always @(posedge clk) begin + if(reset) begin + divu_dividend_valid_reg <= 0'b0; + divu_dividend_ready_flag <= 0'b0; + end + else if(divu_dividend_valid_reg && divu_dividend_ready) begin + divu_dividend_valid_reg <= 0'b0; + divu_dividend_ready_flag <= 0'b1; + end + else if((es_inst_divw || es_inst_modw) && !divu_dividend_ready_flag) begin + divu_dividend_valid_reg <= 0'b1; + end + else if(es_ready_go) begin + divu_dividend_ready_flag <= 1'b0; + end + end + + assign div_divisor_valid = div_divisor_valid_reg; + assign div_dividend_valid = div_dividend_valid_reg; + assign divu_divisor_valid = divu_divisor_valid_reg; + assign divu_dividend_valid = divu_dividend_valid_reg; + + assign div_mod_result = es_inst_divw ? div_dout_data[63:32] : + es_inst_modw ? div_dout_data[31: 0] : + es_inst_divwu ? divu_dout_data[63:32] : + es_inst_modwu ? divu_dout_data[31: 0] : + 32'b0; + alu u_alu( - .alu_op (es_alu_op ), + .alu_op (es_alu_op[14:0]), .alu_src1 (es_alu_src1 ), .alu_src2 (es_alu_src2 ), .alu_result (es_alu_result), diff --git a/lacpu/rtl/cpu/forward.v b/lacpu/rtl/cpu/forward.v index 0e0c253..07d0429 100644 --- a/lacpu/rtl/cpu/forward.v +++ b/lacpu/rtl/cpu/forward.v @@ -31,7 +31,7 @@ module forward( wire data_is_rf_wdata; assign {ds_rf_raddr1, ds_rf_raddr2 } = ds_to_fw_bus_r; - assign {es_rf_rdata2, es_dest, es_reg_we, es_mem_we} = es_to_fw_bus_r; + assign {es_rf_raddr2, es_dest, es_reg_we, es_mem_we} = es_to_fw_bus_r; assign {ms_dest , ms_reg_we} = ms_to_fw_bus_r; assign fw_to_es_bus = {src1_is_es_dest , //4:4 diff --git a/lacpu/rtl/cpu/id_stage.v b/lacpu/rtl/cpu/id_stage.v index 7c0e398..67ce21e 100755 --- a/lacpu/rtl/cpu/id_stage.v +++ b/lacpu/rtl/cpu/id_stage.v @@ -40,7 +40,7 @@ module id_stage( rf_wdata //31:0 } = ws_to_rf_bus; - wire [14:0] alu_op; + wire [18:0] alu_op; wire src1_is_pc; wire src2_is_imm; wire src2_is_4; @@ -84,6 +84,10 @@ module id_stage( wire inst_sraw; wire inst_slliw; wire inst_srliw; + wire inst_sraiw; + wire inst_mulw; + wire inst_mulhw; + wire inst_mulhwu; wire inst_beq; wire inst_bne; wire inst_blt; @@ -101,6 +105,12 @@ module id_stage( wire inst_stb; wire inst_sth; wire inst_stw; + wire inst_divw; + wire inst_modw; + wire inst_divwu; + wire inst_modwu; + + wire dst_is_r1; @@ -113,7 +123,7 @@ module id_stage( wire rj_lt_rd; wire rj_ltu_rd; - assign ds_to_es_bus = {alu_op , //169:155 + assign ds_to_es_bus = {alu_op , //173:155 src1_is_pc , //154:154 src2_is_imm , //153:153 src2_is_4 , //152:152 @@ -177,6 +187,10 @@ module id_stage( assign inst_mulw = (op[21: 5] == 12'b0000_0000_0001) & op17_d[5'b11000]; assign inst_mulhw = (op[21: 5] == 12'b0000_0000_0001) & op17_d[5'b11001]; assign inst_mulhwu = (op[21: 5] == 12'b0000_0000_0001) & op17_d[5'b11010]; + assign inst_divw = (op[21: 5] == 12'b0000_0000_0010) & op17_d[5'b00000]; + assign inst_modw = (op[21: 5] == 12'b0000_0000_0010) & op17_d[5'b00001]; + assign inst_divwu = (op[21: 5] == 12'b0000_0000_0010) & op17_d[5'b00010]; + assign inst_modwu = (op[21: 5] == 12'b0000_0000_0010) & op17_d[5'b00011]; assign inst_slti = (op[21:11] == 7'b0000_001 ) & op10_d[3'b000]; assign inst_sltui = (op[21:11] == 7'b0000_001 ) & op10_d[3'b001]; assign inst_addiw = (op[21:11] == 7'b0000_001 ) & op10_d[3'b010]; @@ -203,9 +217,6 @@ module id_stage( assign inst_bltu = (op[21:15] == 3'b011 ) & op6_d[3'b010]; assign inst_bgeu = (op[21:15] == 3'b011 ) & op6_d[3'b011]; - - - assign alu_op[ 0] = inst_addw | inst_addiw | inst_pcaddu12i | inst_ldb | inst_ldh | inst_ldbu | inst_ldhu | inst_ldw | inst_stb | inst_sth | inst_stw | inst_bl | inst_jirl; assign alu_op[ 1] = inst_subw; assign alu_op[ 2] = inst_slt | inst_slti; @@ -221,6 +232,10 @@ module id_stage( assign alu_op[12] = inst_mulw; assign alu_op[13] = inst_mulhw; assign alu_op[14] = inst_mulhwu; + assign alu_op[15] = inst_divw; + assign alu_op[16] = inst_modw; + assign alu_op[17] = inst_divwu; + assign alu_op[18] = inst_modwu; assign imm = {32{inst_slti | inst_sltui | inst_addiw | inst_ldb | inst_ldh | inst_ldw | inst_stb | inst_sth | inst_stw | inst_ldbu | inst_ldhu}} & {{20{ds_inst[21]}}, ds_inst[21:10]} | {32{inst_beq | inst_bne | inst_bge | inst_bgeu | inst_blt | inst_bltu | inst_jirl}} & {{14{ds_inst[25]}}, ds_inst[25:10], 2'b0} diff --git a/lacpu/rtl/cpu/mycpu.v b/lacpu/rtl/cpu/mycpu.v index f8323e0..7d36e7f 100644 --- a/lacpu/rtl/cpu/mycpu.v +++ b/lacpu/rtl/cpu/mycpu.v @@ -3,7 +3,7 @@ `define BR_BUS_WD 33 `define FS_TO_DS_BUS_WD 64 - `define DS_TO_ES_BUS_WD 170 + `define DS_TO_ES_BUS_WD 174 `define ES_TO_MS_BUS_WD 121 `define MS_TO_WS_BUS_WD 70 `define WS_TO_RF_BUS_WD 38 diff --git a/lacpu/rtl/soc_lite_top.v b/lacpu/rtl/soc_lite_top.v index 17b63f9..8ee4c5a 100755 --- a/lacpu/rtl/soc_lite_top.v +++ b/lacpu/rtl/soc_lite_top.v @@ -33,7 +33,25 @@ module soc_lite_top wire [31:0] cpu_data_addr; wire [31:0] cpu_data_wdata; wire [31:0] cpu_data_rdata; - + //div + wire [31:0] div_divisor_data; + wire div_divisor_valid; + wire div_divisor_ready; + wire [31:0] div_dividend_data; + wire div_dividend_valid; + wire div_dividend_ready; + wire div_dout_valid; + wire [63:0] div_dout_data; + //divu + wire [31:0] divu_divisor_data; + wire divu_divisor_valid; + wire divu_divisor_ready; + wire [31:0] divu_dividend_data; + wire divu_dividend_valid; + wire divu_dividend_ready; + wire divu_dout_valid; + wire [63:0] divu_dout_data; + //cpu mycpu_top cpu( .clk (cpu_clk ), @@ -51,6 +69,25 @@ module soc_lite_top .data_sram_wdata (cpu_data_wdata), .data_sram_rdata (cpu_data_rdata), + //div + .div_divisor_data (div_divisor_data ), + .div_divisor_valid (div_divisor_valid ), + .div_divisor_ready (div_divisor_ready ), + .div_dividend_data (div_dividend_data ), + .div_dividend_valid (div_dividend_valid ), + .div_dividend_ready (div_dividend_ready ), + .div_dout_valid (div_dout_valid ), + .div_dout_data (div_dout_data ), + //divu + .divu_divisor_data (divu_divisor_data ), + .divu_divisor_valid (divu_divisor_valid ), + .divu_divisor_ready (divu_divisor_ready ), + .divu_dividend_data (divu_dividend_data ), + .divu_dividend_valid(divu_dividend_valid), + .divu_dividend_ready(divu_dividend_ready), + .divu_dout_valid (divu_dout_valid ), + .divu_dout_data (divu_dout_data ), + //debug .debug_wb_pc (debug_wb_pc ), .debug_wb_rf_wen (debug_wb_rf_wen ), @@ -84,6 +121,32 @@ module soc_lite_top .dina (cpu_data_wdata ), //31:0 .douta (cpu_data_rdata ) //31:0 ); + + //div + div div( + .aclk (cpu_clk ), + .s_axis_divisor_tdata (div_divisor_data ), + .s_axis_divisor_tvalid (div_divisor_valid ), + .s_axis_divisor_tready (div_divisor_ready ), + .s_axis_dividend_tdata (div_dividend_data ), + .s_axis_dividend_tvalid (div_dividend_valid ), + .s_axis_dividend_tready (div_dividend_ready ), + .m_axis_dout_tvalid (div_dout_valid ), + .m_axis_dout_tdata (div_dout_data ) + ); + + //divu + divu divu( + .aclk (cpu_clk ), + .s_axis_divisor_tdata (divu_divisor_data ), + .s_axis_divisor_tvalid (divu_divisor_valid ), + .s_axis_divisor_tready (divu_divisor_ready ), + .s_axis_dividend_tdata (divu_dividend_data ), + .s_axis_dividend_tvalid (divu_dividend_valid), + .s_axis_dividend_tready (divu_dividend_ready), + .m_axis_dout_tvalid (divu_dout_valid ), + .m_axis_dout_tdata (divu_dout_data ) + ); `endif endmodule diff --git a/lacpu/run_vivado/la32r/la32r.xpr b/lacpu/run_vivado/la32r/la32r.xpr index 873694b..35869af 100644 --- a/lacpu/run_vivado/la32r/la32r.xpr +++ b/lacpu/run_vivado/la32r/la32r.xpr @@ -54,6 +54,20 @@ + + + + + + + + + + + + + + @@ -138,22 +152,6 @@ - - - - - - - - - - - - - - - -