From 607147f280ebad2a8a59417bb96288c4e3663dc1 Mon Sep 17 00:00:00 2001
From: Luke Wren <wren6991@gmail.com>
Date: Sat, 4 Dec 2021 12:08:54 +0000
Subject: [PATCH] Rewrite byte pick/sign-extend logic, preparing to handle more
 memops

---
 hdl/hazard3_core.v | 57 +++++++++++++++++++++++++---------------------
 1 file changed, 31 insertions(+), 26 deletions(-)

diff --git a/hdl/hazard3_core.v b/hdl/hazard3_core.v
index ccb8dc0..1b3ac26 100644
--- a/hdl/hazard3_core.v
+++ b/hdl/hazard3_core.v
@@ -360,9 +360,10 @@ hazard3_alu #(
 
 wire x_memop_vld = !d_memop[3];
 wire x_memop_write = d_memop == MEMOP_SW || d_memop == MEMOP_SH || d_memop == MEMOP_SB;
-wire x_unaligned_addr =
+wire x_unaligned_addr = d_memop != MEMOP_NONE && (
 	bus_hsize_d == HSIZE_WORD && |bus_haddr_d[1:0] ||
-	bus_hsize_d == HSIZE_HWORD && bus_haddr_d[0];
+	bus_hsize_d == HSIZE_HWORD && bus_haddr_d[0]
+);
 
 always @ (*) begin
 	// Need to be careful not to use anything hready-sourced to gate htrans!
@@ -374,7 +375,10 @@ always @ (*) begin
 		MEMOP_LH:  bus_hsize_d = HSIZE_HWORD;
 		MEMOP_LHU: bus_hsize_d = HSIZE_HWORD;
 		MEMOP_SH:  bus_hsize_d = HSIZE_HWORD;
-		default:   bus_hsize_d = HSIZE_BYTE;
+		MEMOP_LB:  bus_hsize_d = HSIZE_BYTE;
+		MEMOP_LBU: bus_hsize_d = HSIZE_BYTE;
+		MEMOP_SB:  bus_hsize_d = HSIZE_BYTE;
+		default:   bus_hsize_d = HSIZE_WORD;
 	endcase
 	bus_aph_req_d = x_memop_vld && !(
 		x_stall_raw ||
@@ -636,7 +640,7 @@ assign x_jump_req = !x_stall_raw && (
 // ----------------------------------------------------------------------------
 //                               Pipe Stage M
 
-reg [W_DATA-1:0] m_rdata_shift;
+reg [W_DATA-1:0] m_rdata_pick_sext;
 reg [W_DATA-1:0] m_wdata;
 reg [W_DATA-1:0] m_result;
 
@@ -653,7 +657,7 @@ assign m_stall = m_bus_stall ||
 // back. IRQ is taken "in between" the instruction in M and the instruction
 // in X, so set return to X program counter. Note that, if taking an
 // exception, we know that the previous instruction to be in X (now in M)
-// was *not* a branch, which is why we can just walk back the PC.
+// was *not* a taken branch, which is why we can just walk back the PC.
 assign m_exception_return_addr = d_pc - (
 	m_trap_is_irq         ? 32'h0 :
 	prev_instr_was_32_bit ? 32'h4 : 32'h2
@@ -673,29 +677,30 @@ always @ (*) begin
 		MEMOP_SB: bus_wdata_d = {4{m_wdata[7:0]}};
 		default:  bus_wdata_d = 32'h0;
 	endcase
-	// Pick out correct data from load access, and sign/unsign extend it.
-	// This is slightly cheaper than a normal shift:
-	case (xm_result[1:0])
-		2'b00: m_rdata_shift = bus_rdata_d;
-		2'b01: m_rdata_shift = {bus_rdata_d[31:8],  bus_rdata_d[15:8]};
-		2'b10: m_rdata_shift = {bus_rdata_d[31:16], bus_rdata_d[31:16]};
-		2'b11: m_rdata_shift = {bus_rdata_d[31:8],  bus_rdata_d[31:24]};
+
+	casez ({xm_memop, xm_result[1:0]})
+		{MEMOP_LH  , 2'b0z}: m_rdata_pick_sext = {{16{bus_rdata_d[15]}}, bus_rdata_d[15: 0]};
+		{MEMOP_LH  , 2'b1z}: m_rdata_pick_sext = {{16{bus_rdata_d[31]}}, bus_rdata_d[31:16]};
+		{MEMOP_LHU , 2'b0z}: m_rdata_pick_sext = {{16{1'b0           }}, bus_rdata_d[15: 0]};
+		{MEMOP_LHU , 2'b1z}: m_rdata_pick_sext = {{16{1'b0           }}, bus_rdata_d[31:16]};
+		{MEMOP_LB  , 2'b00}: m_rdata_pick_sext = {{24{bus_rdata_d[ 7]}}, bus_rdata_d[ 7: 0]};
+		{MEMOP_LB  , 2'b01}: m_rdata_pick_sext = {{24{bus_rdata_d[15]}}, bus_rdata_d[15: 8]};
+		{MEMOP_LB  , 2'b10}: m_rdata_pick_sext = {{24{bus_rdata_d[23]}}, bus_rdata_d[23:16]};
+		{MEMOP_LB  , 2'b11}: m_rdata_pick_sext = {{24{bus_rdata_d[31]}}, bus_rdata_d[31:24]};
+		{MEMOP_LBU , 2'b00}: m_rdata_pick_sext = {{24{1'b0           }}, bus_rdata_d[ 7: 0]};
+		{MEMOP_LBU , 2'b01}: m_rdata_pick_sext = {{24{1'b0           }}, bus_rdata_d[15: 8]};
+		{MEMOP_LBU , 2'b10}: m_rdata_pick_sext = {{24{1'b0           }}, bus_rdata_d[23:16]};
+		{MEMOP_LBU , 2'b11}: m_rdata_pick_sext = {{24{1'b0           }}, bus_rdata_d[31:24]};
+		default:             m_rdata_pick_sext = bus_rdata_d;
 	endcase
 
-	case (xm_memop)
-		MEMOP_LW:  m_result = m_rdata_shift;
-		MEMOP_LH:  m_result = {{16{m_rdata_shift[15]}}, m_rdata_shift[15:0]};
-		MEMOP_LHU: m_result = {16'h0, m_rdata_shift[15:0]};
-		MEMOP_LB:  m_result = {{24{m_rdata_shift[7]}}, m_rdata_shift[7:0]};
-		MEMOP_LBU: m_result = {24'h0, m_rdata_shift[7:0]};
-		default:   begin
-			if (MUL_FAST && m_fast_mul_result_vld) begin
-				m_result = m_fast_mul_result;
-			end else begin
-				m_result = xm_result;
-			end
-		end
-	endcase
+	if (xm_memop != MEMOP_NONE) begin
+		m_result = m_rdata_pick_sext;
+	end else if (MUL_FAST && m_fast_mul_result_vld) begin
+		m_result = m_fast_mul_result;
+	end else begin
+		m_result = xm_result;
+	end
 end