From b4777b378d256e83d64b56a2ae686bc3c09d77c9 Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Sun, 2 Aug 2020 13:29:45 +0200 Subject: [PATCH 1/2] Add big-endian support Signed-off-by: Marcus Comstedt --- README.md | 15 ++++++++ picorv32.v | 110 ++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 90 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 3f41f0cd..a77084c4 100644 --- a/README.md +++ b/README.md @@ -320,6 +320,21 @@ uninitialized.) Note that the RISC-V calling convention requires the stack point to be aligned on 16 bytes boundaries (4 bytes for the RV32I soft float calling convention). +#### BIG_ENDIAN_OPERANDS (default 0) + +Set this to 1 to enable big endian addressing for sub-word memory accesses, +i.e. the most significant bits at the lowest address. + +#### BIG_ENDIAN_INSNS (default 0) + +Set this to 1 to enable big endian instruction streams, i.e. the parcel in +`mem_rdata[31:16]` logically precedes the one in `mem_rdata[15:0]`, +and provides lower numbered bits in case the parcels are part of the same +instruction. +This is how the official RISC-V documents say instructions should be encoded +on big endian, but note that current toolchains do not support generating +code in this format. + Cycles per Instruction Performance ---------------------------------- diff --git a/picorv32.v b/picorv32.v index 6364cbe7..89667343 100644 --- a/picorv32.v +++ b/picorv32.v @@ -85,7 +85,9 @@ module picorv32 #( parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, - parameter [31:0] STACKADDR = 32'h ffff_ffff + parameter [31:0] STACKADDR = 32'h ffff_ffff, + parameter [ 0:0] BIG_ENDIAN_OPERANDS = 0, + parameter [ 0:0] BIG_ENDIAN_INSNS = 0 ) ( input clk, resetn, output reg trap, @@ -366,6 +368,7 @@ module picorv32 #( reg clear_prefetched_high_word; reg [15:0] mem_16bit_buffer; + wire [31:0] mem_rdata_insn; wire [31:0] mem_rdata_latched_noshuffle; wire [31:0] mem_rdata_latched; @@ -381,7 +384,13 @@ module picorv32 #( (COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg) && !mem_la_secondword && &mem_rdata_latched[1:0])); assign mem_la_addr = (mem_do_prefetch || mem_do_rinst) ? {next_pc[31:2] + mem_la_firstword_xfer, 2'b00} : {reg_op1[31:2], 2'b00}; - assign mem_rdata_latched_noshuffle = (mem_xfer || LATCHED_MEM_RDATA) ? mem_rdata : mem_rdata_q; + generate if (BIG_ENDIAN_INSNS) begin + assign mem_rdata_insn = { mem_rdata[15:0], mem_rdata[31:16] }; + end else begin + assign mem_rdata_insn = mem_rdata; + end endgenerate + + assign mem_rdata_latched_noshuffle = (mem_xfer || LATCHED_MEM_RDATA) ? mem_rdata_insn : mem_rdata_q; assign mem_rdata_latched = COMPRESSED_ISA && mem_la_use_prefetched_high_word ? {16'bx, mem_16bit_buffer} : COMPRESSED_ISA && mem_la_secondword ? {mem_rdata_latched_noshuffle[15:0], mem_16bit_buffer} : @@ -398,39 +407,70 @@ module picorv32 #( end end - always @* begin - (* full_case *) - case (mem_wordsize) - 0: begin - mem_la_wdata = reg_op2; - mem_la_wstrb = 4'b1111; - mem_rdata_word = mem_rdata; - end - 1: begin - mem_la_wdata = {2{reg_op2[15:0]}}; - mem_la_wstrb = reg_op1[1] ? 4'b1100 : 4'b0011; - case (reg_op1[1]) - 1'b0: mem_rdata_word = {16'b0, mem_rdata[15: 0]}; - 1'b1: mem_rdata_word = {16'b0, mem_rdata[31:16]}; - endcase - end - 2: begin - mem_la_wdata = {4{reg_op2[7:0]}}; - mem_la_wstrb = 4'b0001 << reg_op1[1:0]; - case (reg_op1[1:0]) - 2'b00: mem_rdata_word = {24'b0, mem_rdata[ 7: 0]}; - 2'b01: mem_rdata_word = {24'b0, mem_rdata[15: 8]}; - 2'b10: mem_rdata_word = {24'b0, mem_rdata[23:16]}; - 2'b11: mem_rdata_word = {24'b0, mem_rdata[31:24]}; - endcase - end - endcase - end + generate if (BIG_ENDIAN_OPERANDS) begin + always @* begin + (* full_case *) + case (mem_wordsize) + 0: begin + mem_la_wdata = reg_op2; + mem_la_wstrb = 4'b1111; + mem_rdata_word = mem_rdata; + end + 1: begin + mem_la_wdata = {2{reg_op2[15:0]}}; + mem_la_wstrb = reg_op1[1] ? 4'b0011 : 4'b1100; + case (reg_op1[1]) + 1'b0: mem_rdata_word = {16'b0, mem_rdata[31:16]}; + 1'b1: mem_rdata_word = {16'b0, mem_rdata[15: 0]}; + endcase + end + 2: begin + mem_la_wdata = {4{reg_op2[7:0]}}; + mem_la_wstrb = 4'b1000 >> reg_op1[1:0]; + case (reg_op1[1:0]) + 2'b00: mem_rdata_word = {24'b0, mem_rdata[31:24]}; + 2'b01: mem_rdata_word = {24'b0, mem_rdata[23:16]}; + 2'b10: mem_rdata_word = {24'b0, mem_rdata[15: 8]}; + 2'b11: mem_rdata_word = {24'b0, mem_rdata[ 7: 0]}; + endcase + end + endcase + end + end else begin // if (BIG_ENDIAN_OPERANDS) + always @* begin + (* full_case *) + case (mem_wordsize) + 0: begin + mem_la_wdata = reg_op2; + mem_la_wstrb = 4'b1111; + mem_rdata_word = mem_rdata; + end + 1: begin + mem_la_wdata = {2{reg_op2[15:0]}}; + mem_la_wstrb = reg_op1[1] ? 4'b1100 : 4'b0011; + case (reg_op1[1]) + 1'b0: mem_rdata_word = {16'b0, mem_rdata[15: 0]}; + 1'b1: mem_rdata_word = {16'b0, mem_rdata[31:16]}; + endcase + end + 2: begin + mem_la_wdata = {4{reg_op2[7:0]}}; + mem_la_wstrb = 4'b0001 << reg_op1[1:0]; + case (reg_op1[1:0]) + 2'b00: mem_rdata_word = {24'b0, mem_rdata[ 7: 0]}; + 2'b01: mem_rdata_word = {24'b0, mem_rdata[15: 8]}; + 2'b10: mem_rdata_word = {24'b0, mem_rdata[23:16]}; + 2'b11: mem_rdata_word = {24'b0, mem_rdata[31:24]}; + endcase + end + endcase + end + end endgenerate // else: !if(BIG_ENDIAN_OPERANDS) always @(posedge clk) begin if (mem_xfer) begin - mem_rdata_q <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata; - next_insn_opcode <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata; + mem_rdata_q <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata_insn; + next_insn_opcode <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata_insn; end if (COMPRESSED_ISA && mem_done && (mem_do_prefetch || mem_do_rinst)) begin @@ -602,13 +642,13 @@ module picorv32 #( mem_valid <= 1; mem_la_secondword <= 1; if (!mem_la_use_prefetched_high_word) - mem_16bit_buffer <= mem_rdata[31:16]; + mem_16bit_buffer <= mem_rdata_insn[31:16]; end else begin mem_valid <= 0; mem_la_secondword <= 0; if (COMPRESSED_ISA && !mem_do_rdata) begin - if (~&mem_rdata[1:0] || mem_la_secondword) begin - mem_16bit_buffer <= mem_rdata[31:16]; + if (~&mem_rdata_insn[1:0] || mem_la_secondword) begin + mem_16bit_buffer <= mem_rdata_insn[31:16]; prefetched_high_word <= 1; end else begin prefetched_high_word <= 0; From cc1c843a660ace7958f622ba44ac8f369c270284 Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Tue, 20 Oct 2020 22:24:11 +0200 Subject: [PATCH 2/2] Update big endian instruction encoding Between draft-20181101-ebe1ca4 and draft-20190622-6993896 of the RISC-V Instruction Set Manual, the wording was changed from requiring "natural endianness" of instruction parcels to require them to be little endian. Update the big endian instruction pipe to reflect the newer requirement. Signed-off-by: Marcus Comstedt --- README.md | 10 +++------- picorv32.v | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a77084c4..77b9ce2a 100644 --- a/README.md +++ b/README.md @@ -327,13 +327,9 @@ i.e. the most significant bits at the lowest address. #### BIG_ENDIAN_INSNS (default 0) -Set this to 1 to enable big endian instruction streams, i.e. the parcel in -`mem_rdata[31:16]` logically precedes the one in `mem_rdata[15:0]`, -and provides lower numbered bits in case the parcels are part of the same -instruction. -This is how the official RISC-V documents say instructions should be encoded -on big endian, but note that current toolchains do not support generating -code in this format. +Set this to 1 to enable byteswapping of the instruction stream. +This is required on big endian because instructions are stored in little +endian byteorder. Cycles per Instruction Performance diff --git a/picorv32.v b/picorv32.v index 89667343..916178cd 100644 --- a/picorv32.v +++ b/picorv32.v @@ -385,7 +385,7 @@ module picorv32 #( assign mem_la_addr = (mem_do_prefetch || mem_do_rinst) ? {next_pc[31:2] + mem_la_firstword_xfer, 2'b00} : {reg_op1[31:2], 2'b00}; generate if (BIG_ENDIAN_INSNS) begin - assign mem_rdata_insn = { mem_rdata[15:0], mem_rdata[31:16] }; + assign mem_rdata_insn = { mem_rdata[7:0], mem_rdata[15:8], mem_rdata[23:16], mem_rdata[31:24] }; end else begin assign mem_rdata_insn = mem_rdata; end endgenerate