Add big-endian support

Signed-off-by: Marcus Comstedt <marcus@mc.pp.se>
This commit is contained in:
Marcus Comstedt 2020-08-02 13:29:45 +02:00
parent f9b1beb4cf
commit b4777b378d
2 changed files with 90 additions and 35 deletions

View File

@ -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 to be aligned on 16 bytes boundaries (4 bytes for the RV32I soft float calling
convention). 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 Cycles per Instruction Performance
---------------------------------- ----------------------------------

View File

@ -85,7 +85,9 @@ module picorv32 #(
parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff,
parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, parameter [31:0] PROGADDR_RESET = 32'h 0000_0000,
parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, 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, input clk, resetn,
output reg trap, output reg trap,
@ -366,6 +368,7 @@ module picorv32 #(
reg clear_prefetched_high_word; reg clear_prefetched_high_word;
reg [15:0] mem_16bit_buffer; 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_noshuffle;
wire [31:0] mem_rdata_latched; 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])); (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_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} : 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} : COMPRESSED_ISA && mem_la_secondword ? {mem_rdata_latched_noshuffle[15:0], mem_16bit_buffer} :
@ -398,39 +407,70 @@ module picorv32 #(
end end
end end
always @* begin generate if (BIG_ENDIAN_OPERANDS) begin
(* full_case *) always @* begin
case (mem_wordsize) (* full_case *)
0: begin case (mem_wordsize)
mem_la_wdata = reg_op2; 0: begin
mem_la_wstrb = 4'b1111; mem_la_wdata = reg_op2;
mem_rdata_word = mem_rdata; mem_la_wstrb = 4'b1111;
end mem_rdata_word = mem_rdata;
1: begin end
mem_la_wdata = {2{reg_op2[15:0]}}; 1: begin
mem_la_wstrb = reg_op1[1] ? 4'b1100 : 4'b0011; mem_la_wdata = {2{reg_op2[15:0]}};
case (reg_op1[1]) mem_la_wstrb = reg_op1[1] ? 4'b0011 : 4'b1100;
1'b0: mem_rdata_word = {16'b0, mem_rdata[15: 0]}; case (reg_op1[1])
1'b1: mem_rdata_word = {16'b0, mem_rdata[31:16]}; 1'b0: mem_rdata_word = {16'b0, mem_rdata[31:16]};
endcase 1'b1: mem_rdata_word = {16'b0, mem_rdata[15: 0]};
end endcase
2: begin end
mem_la_wdata = {4{reg_op2[7:0]}}; 2: begin
mem_la_wstrb = 4'b0001 << reg_op1[1:0]; mem_la_wdata = {4{reg_op2[7:0]}};
case (reg_op1[1:0]) mem_la_wstrb = 4'b1000 >> reg_op1[1:0];
2'b00: mem_rdata_word = {24'b0, mem_rdata[ 7: 0]}; case (reg_op1[1:0])
2'b01: mem_rdata_word = {24'b0, mem_rdata[15: 8]}; 2'b00: mem_rdata_word = {24'b0, mem_rdata[31:24]};
2'b10: mem_rdata_word = {24'b0, mem_rdata[23:16]}; 2'b01: mem_rdata_word = {24'b0, mem_rdata[23:16]};
2'b11: mem_rdata_word = {24'b0, mem_rdata[31:24]}; 2'b10: mem_rdata_word = {24'b0, mem_rdata[15: 8]};
endcase 2'b11: mem_rdata_word = {24'b0, mem_rdata[ 7: 0]};
end endcase
endcase end
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 always @(posedge clk) begin
if (mem_xfer) begin if (mem_xfer) begin
mem_rdata_q <= 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; next_insn_opcode <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata_insn;
end end
if (COMPRESSED_ISA && mem_done && (mem_do_prefetch || mem_do_rinst)) begin if (COMPRESSED_ISA && mem_done && (mem_do_prefetch || mem_do_rinst)) begin
@ -602,13 +642,13 @@ module picorv32 #(
mem_valid <= 1; mem_valid <= 1;
mem_la_secondword <= 1; mem_la_secondword <= 1;
if (!mem_la_use_prefetched_high_word) 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 end else begin
mem_valid <= 0; mem_valid <= 0;
mem_la_secondword <= 0; mem_la_secondword <= 0;
if (COMPRESSED_ISA && !mem_do_rdata) begin if (COMPRESSED_ISA && !mem_do_rdata) begin
if (~&mem_rdata[1:0] || mem_la_secondword) begin if (~&mem_rdata_insn[1:0] || mem_la_secondword) begin
mem_16bit_buffer <= mem_rdata[31:16]; mem_16bit_buffer <= mem_rdata_insn[31:16];
prefetched_high_word <= 1; prefetched_high_word <= 1;
end else begin end else begin
prefetched_high_word <= 0; prefetched_high_word <= 0;