abstractaccelerator/uriscv/src/uriscv_branch.v

154 lines
4.7 KiB
Verilog

//-----------------------------------------------------------------
// uRISC-V CPU
// V0.5.0
// github.com/ultraembedded/core_uriscv
// Copyright 2015-2021
//
// admin@ultra-embedded.com
//
// License: Apache 2.0
//-----------------------------------------------------------------
// Copyright 2015-2021 github.com/ultraembedded
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//-----------------------------------------------------------------
module uriscv_branch
(
input [31:0] pc_i
,input [31:0] opcode_i
,input [31:0] rs1_val_i
,input [31:0] rs2_val_i
,output branch_o
,output [31:0] branch_target_o
);
//-----------------------------------------------------------------
// Includes
//-----------------------------------------------------------------
`include "uriscv_defs.v"
//-----------------------------------------------------------------
// less_than_signed: Less than operator (signed)
// Inputs: x = left operand, y = right operand
// Return: (int)x < (int)y
//-----------------------------------------------------------------
function [0:0] less_than_signed;
input [31:0] x;
input [31:0] y;
reg [31:0] v;
begin
v = (x - y);
if (x[31] != y[31])
less_than_signed = x[31];
else
less_than_signed = v[31];
end
endfunction
//-----------------------------------------------------------------
// greater_than_signed: Greater than operator (signed)
// Inputs: x = left operand, y = right operand
// Return: (int)x > (int)y
//-----------------------------------------------------------------
function [0:0] greater_than_signed;
input [31:0] x;
input [31:0] y;
reg [31:0] v;
begin
v = (y - x);
if (x[31] != y[31])
greater_than_signed = y[31];
else
greater_than_signed = v[31];
end
endfunction
//-----------------------------------------------------------------
// Branch Decode
//-----------------------------------------------------------------
wire type_branch_w = (opcode_i[6:2] == 5'b11000);
wire type_jalr_w = (opcode_i[6:2] == 5'b11001);
wire type_jal_w = (opcode_i[6:2] == 5'b11011);
wire [2:0] func3_w = opcode_i[14:12]; // R, I, S
wire [6:0] func7_w = opcode_i[31:25]; // R
wire branch_beq_w = (func3_w == 3'b000);
wire branch_bne_w = (func3_w == 3'b001);
wire branch_blt_w = (func3_w == 3'b100);
wire branch_bge_w = (func3_w == 3'b101);
wire branch_bltu_w = (func3_w == 3'b110);
wire branch_bgeu_w = (func3_w == 3'b111);
reg branch_r;
reg [31:0] branch_target_r;
reg [31:0] imm12_r;
reg [31:0] bimm_r;
reg [31:0] jimm20_r;
always @ *
begin
branch_r = 1'b0;
branch_target_r = 32'b0;
// Opcode decode
imm12_r = {{20{opcode_i[31]}}, opcode_i[31:20]};
bimm_r = {{19{opcode_i[31]}}, opcode_i[31], opcode_i[7], opcode_i[30:25], opcode_i[11:8], 1'b0};
jimm20_r = {{12{opcode_i[31]}}, opcode_i[19:12], opcode_i[20], opcode_i[30:25], opcode_i[24:21], 1'b0};
// Default branch target is relative to current PC
branch_target_r = (pc_i + bimm_r);
if (type_jal_w)
begin
branch_r = 1'b1;
branch_target_r = pc_i + jimm20_r;
end
else if (type_jalr_w)
begin
branch_r = 1'b1;
branch_target_r = rs1_val_i + imm12_r;
branch_target_r[0] = 1'b0;
end
else if (type_branch_w)
begin
case (1'b1)
branch_beq_w: // beq
branch_r = (rs1_val_i == rs2_val_i);
branch_bne_w: // bne
branch_r = (rs1_val_i != rs2_val_i);
branch_blt_w: // blt
branch_r = less_than_signed(rs1_val_i, rs2_val_i);
branch_bge_w: // bge
branch_r = greater_than_signed(rs1_val_i, rs2_val_i) | (rs1_val_i == rs2_val_i);
branch_bltu_w: // bltu
branch_r = (rs1_val_i < rs2_val_i);
branch_bgeu_w: // bgeu
branch_r = (rs1_val_i >= rs2_val_i);
default:
;
endcase
end
end
assign branch_o = branch_r;
assign branch_target_o = branch_target_r;
endmodule