Line 8... |
Line 8... |
// Email: admin@ultra-embedded.com
|
// Email: admin@ultra-embedded.com
|
//
|
//
|
// License: LGPL
|
// License: LGPL
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
//
|
//
|
// Copyright (C) 2011 - 2013 Ultra-Embedded.com
|
// Copyright (C) 2011 - 2014 Ultra-Embedded.com
|
//
|
//
|
// This source file may be used and distributed without
|
// This source file may be used and distributed without
|
// restriction provided that this copyright statement is not
|
// restriction provided that this copyright statement is not
|
// removed from the file and that any derivative work contains
|
// removed from the file and that any derivative work contains
|
// the original copyright notice and the associated disclaimer.
|
// the original copyright notice and the associated disclaimer.
|
Line 79... |
Line 79... |
parameter PIPELINED_FETCH = "DISABLED";
|
parameter PIPELINED_FETCH = "DISABLED";
|
|
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
// Registers
|
// Registers
|
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
reg r_rd;
|
reg rd_q;
|
reg [31:0] r_pc;
|
reg [31:0] pc_q;
|
reg [31:0] d_pc;
|
reg [31:0] pc_last_q;
|
|
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
// Next PC state machine
|
// Next PC state machine
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
wire [31:0] next_pc = r_pc + 32'd4;
|
wire [31:0] next_pc_w = pc_q + 32'd4;
|
|
|
always @ (posedge clk_i or posedge rst_i)
|
always @ (posedge clk_i or posedge rst_i)
|
begin
|
begin
|
if (rst_i)
|
if (rst_i)
|
begin
|
begin
|
r_pc <= BOOT_VECTOR + `VECTOR_RESET;
|
pc_q <= BOOT_VECTOR + `VECTOR_RESET;
|
d_pc <= BOOT_VECTOR + `VECTOR_RESET;
|
pc_last_q <= BOOT_VECTOR + `VECTOR_RESET;
|
r_rd <= 1'b1;
|
rd_q <= 1'b1;
|
end
|
end
|
else if (~stall_i)
|
else if (~stall_i)
|
begin
|
begin
|
r_rd <= 1'b0;
|
|
d_pc <= pc_o;
|
|
|
|
// Branch - Next PC = branch target + 4
|
// Branch - Next PC = branch target + 4
|
if (branch_i)
|
if (branch_i)
|
begin
|
begin
|
r_pc <= branch_pc_i + 4;
|
rd_q <= 1'b0;
|
|
pc_last_q <= pc_o;
|
|
pc_q <= branch_pc_i + 4;
|
end
|
end
|
// Normal sequential execution (and instruction is ready)
|
// Normal sequential execution (and instruction is ready)
|
else if (data_valid_i)
|
else if (data_valid_i)
|
begin
|
begin
|
// New cache line?
|
// New cache line?
|
if (next_pc[CACHE_LINE_SIZE_WIDTH-1:0] == {CACHE_LINE_SIZE_WIDTH{1'b0}})
|
if (next_pc_w[CACHE_LINE_SIZE_WIDTH-1:0] == {CACHE_LINE_SIZE_WIDTH{1'b0}})
|
begin
|
rd_q <= 1'b1;
|
// Start fetch of next line
|
else
|
r_rd <= 1'b1;
|
rd_q <= 1'b0;
|
end
|
|
|
|
r_pc <= next_pc;
|
pc_last_q <= pc_o;
|
|
pc_q <= next_pc_w;
|
|
end
|
|
else
|
|
begin
|
|
rd_q <= 1'b0;
|
|
pc_last_q <= pc_o;
|
end
|
end
|
end
|
end
|
end
|
end
|
|
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
// Assignments
|
|
//-------------------------------------------------------------------
|
|
|
|
// Instruction Fetch
|
// Instruction Fetch
|
|
//-------------------------------------------------------------------
|
always @ *
|
always @ *
|
begin
|
begin
|
// Stall, revert to last requested PC
|
// Stall, revert to last requested PC
|
if (stall_i)
|
if (stall_i)
|
pc_o = d_pc;
|
pc_o = pc_last_q;
|
else if (branch_i)
|
else if (branch_i)
|
pc_o = branch_pc_i;
|
pc_o = branch_pc_i;
|
else if (~data_valid_i)
|
else if (~data_valid_i)
|
pc_o = d_pc;
|
pc_o = pc_last_q;
|
else
|
else
|
pc_o = r_pc;
|
pc_o = pc_q;
|
end
|
end
|
|
|
assign fetch_o = branch_i ? 1'b1 : r_rd;
|
assign fetch_o = branch_i ? 1'b1 : rd_q;
|
|
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
// Opcode output (retiming)
|
// Opcode output (retiming)
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
generate
|
generate
|
if (PIPELINED_FETCH == "ENABLED")
|
if (PIPELINED_FETCH == "ENABLED")
|
begin: FETCH_FLOPS
|
begin: FETCH_FLOPS
|
reg [31:0] r_opcode;
|
reg [31:0] opcode_q;
|
reg [31:0] r_opcode_pc;
|
reg [31:0] opcode_pc_q;
|
reg r_opcode_valid;
|
reg opcode_valid_q;
|
reg r_branch;
|
reg branch_q;
|
|
|
always @ (posedge clk_i or posedge rst_i)
|
always @ (posedge clk_i or posedge rst_i)
|
begin
|
begin
|
if (rst_i)
|
if (rst_i)
|
begin
|
begin
|
r_opcode <= 32'b0;
|
opcode_q <= 32'b0;
|
r_opcode_pc <= 32'b0;
|
opcode_pc_q <= 32'b0;
|
r_opcode_valid <= 1'b0;
|
opcode_valid_q <= 1'b0;
|
r_branch <= 1'b0;
|
branch_q <= 1'b0;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
r_branch <= branch_i;
|
branch_q <= branch_i;
|
|
|
if (~stall_i)
|
if (~stall_i)
|
begin
|
begin
|
r_opcode_pc <= d_pc;
|
opcode_pc_q <= pc_last_q;
|
r_opcode <= data_i;
|
opcode_q <= data_i;
|
r_opcode_valid <= (data_valid_i & !branch_i);
|
opcode_valid_q <= (data_valid_i & !branch_i);
|
end
|
end
|
end
|
end
|
end
|
end
|
|
|
// Opcode output
|
// Opcode output
|
assign opcode_valid_o = r_opcode_valid & ~branch_i & ~r_branch;
|
assign opcode_valid_o = opcode_valid_q & ~branch_i & ~branch_q;
|
assign opcode_o = r_opcode;
|
assign opcode_o = opcode_q;
|
assign opcode_pc_o = r_opcode_pc;
|
assign opcode_pc_o = opcode_pc_q;
|
end
|
end
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
// Opcode output
|
// Opcode output
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
else
|
else
|
begin : NO_FETCH_FLOPS
|
begin : NO_FETCH_FLOPS
|
// Opcode output
|
|
assign opcode_valid_o = (data_valid_i & !branch_i);
|
assign opcode_valid_o = (data_valid_i & !branch_i);
|
assign opcode_o = data_i;
|
assign opcode_o = data_i;
|
assign opcode_pc_o = d_pc;
|
assign opcode_pc_o = pc_last_q;
|
end
|
end
|
endgenerate
|
endgenerate
|
|
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
// Opcode output
|
// Opcode output
|
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
// If simulation, RA = 03 if NOP instruction
|
// If simulation, RA = 03 if NOP instruction
|
`ifdef SIMULATION
|
`ifdef SIMULATION
|
wire [7:0] v_fetch_inst = {2'b00, opcode_o[31:26]};
|
wire [7:0] fetch_inst_w = {2'b00, opcode_o[31:26]};
|
wire v_is_nop = (v_fetch_inst == `INST_OR32_NOP);
|
wire nop_inst_w = (fetch_inst_w == `INST_OR32_NOP);
|
assign ra_o = v_is_nop ? 5'd3 : opcode_o[20:16];
|
assign ra_o = nop_inst_w ? 5'd3 : opcode_o[20:16];
|
`else
|
`else
|
assign ra_o = opcode_o[20:16];
|
assign ra_o = opcode_o[20:16];
|
`endif
|
`endif
|
|
|
assign rb_o = opcode_o[15:11];
|
assign rb_o = opcode_o[15:11];
|