mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
- Introduced new test cases for APU-P3 loader, control store, and sequencer functionality in . - Enhanced the APU ring scheduler and stream router testbenches to validate reset timing and state transitions. - Added comprehensive tests for APU microcode tools, ensuring assembler and interpreter consistency. - Updated register parity tests to synchronize APU RTL and SDK ABI across P3. - Expanded formal filelist generation to include APU loader and sequencer. - Improved SBY configuration for formal verification with Bitwuzla.
549 lines
24 KiB
Systemverilog
549 lines
24 KiB
Systemverilog
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
|
// SPDX-License-Identifier: MulanPSL-2.0
|
|
|
|
`include "apu_define.svh"
|
|
|
|
module apu_codec_sequencer (
|
|
// verilog_format: off -- preserve launch, predicate, store, and result columns
|
|
input logic clk_i,
|
|
input logic rst_n_i,
|
|
input logic soft_reset_i,
|
|
input logic resource_reset_i,
|
|
input logic counter_clear_i,
|
|
input logic abort_i,
|
|
input logic launch_i,
|
|
input logic [1:0] launch_entry_i,
|
|
input logic image_valid_i,
|
|
input logic [31:0] timeout_i,
|
|
input logic [2:0][10:0] entry_pc_i,
|
|
input logic [2:0][10:0] entry_first_i,
|
|
input logic [2:0][10:0] entry_last_i,
|
|
input logic [2:0][15:0] entry_max_loop_i,
|
|
input logic [2:0][23:0] entry_max_retired_i,
|
|
input logic input_exhausted_i,
|
|
input logic input_ready_i,
|
|
input logic output_ready_i,
|
|
input logic kernel_done_i,
|
|
input logic transport_idle_success_i,
|
|
input logic stall_i,
|
|
input logic cause_valid_i,
|
|
input logic [5:0] cause_code_i,
|
|
input logic [3:0] cause_stage_i,
|
|
input logic [1:0] cause_resp_i,
|
|
input logic [7:0] cause_index_i,
|
|
input logic [31:0] cause_addr_i,
|
|
input logic [31:0] cause_detail_i,
|
|
output logic fetch_o,
|
|
output logic [10:0] fetch_addr_o,
|
|
input logic [63:0] fetch_data_i,
|
|
input logic fetch_valid_i,
|
|
output logic [31:0] stat_o,
|
|
output logic [31:0] retired_o,
|
|
output logic [15:0][31:0] gpr_o,
|
|
output logic trapped_o,
|
|
output logic trap_event_o,
|
|
output logic abort_done_o,
|
|
output logic fault_valid_o,
|
|
output logic [5:0] fault_code_o,
|
|
output logic [3:0] fault_stage_o,
|
|
output logic [1:0] fault_resp_o,
|
|
output logic [7:0] fault_index_o,
|
|
output logic [31:0] fault_addr_o,
|
|
output logic [31:0] fault_detail_o,
|
|
output logic [63:0] perf_retired_o,
|
|
output logic idle_o
|
|
// verilog_format: on
|
|
);
|
|
import apu_microcode_pkg::*;
|
|
|
|
typedef enum logic [1:0] {
|
|
Idle,
|
|
FetchRequest,
|
|
FetchWait,
|
|
Execute
|
|
} sequencer_state_e;
|
|
|
|
sequencer_state_e s_state_q;
|
|
logic [15:0][31:0] s_gpr_q;
|
|
logic s_eq_q, s_signed_lt_q, s_unsigned_lt_q;
|
|
logic [3:0][10:0] s_return_pc_q;
|
|
logic [2:0] s_return_depth_q;
|
|
logic [3:0] s_loop_active_q;
|
|
logic [3:0][15:0] s_loop_count_q;
|
|
logic [3:0][10:0] s_loop_start_q;
|
|
logic [10:0] s_pc_q, s_first_pc_q, s_last_pc_q;
|
|
logic [15:0] s_max_loop_q;
|
|
logic [23:0] s_max_retired_q, s_frame_retired_q;
|
|
logic [31:0] s_watchdog_q;
|
|
logic [63:0] s_instruction_q;
|
|
logic [31:0] s_stat_q;
|
|
logic s_trapped_q;
|
|
logic [63:0] s_perf_retired_q;
|
|
|
|
logic [3:0] s_class, s_opcode, s_predicate, s_dst, s_src0, s_src1;
|
|
logic [5:0] s_aux;
|
|
logic [31:0] s_immediate, s_source0, s_source1;
|
|
logic s_predicate_true;
|
|
logic [11:0] s_forward_target, s_loop_target;
|
|
logic [31:0] s_sat_result;
|
|
logic s_trap_now;
|
|
logic [ 7:0] s_trap_reason;
|
|
logic [31:0] s_trap_detail;
|
|
|
|
assign s_class = s_instruction_q[63:60];
|
|
assign s_opcode = s_instruction_q[59:56];
|
|
assign s_predicate = s_instruction_q[55:52];
|
|
assign s_dst = s_instruction_q[51:48];
|
|
assign s_src0 = s_instruction_q[47:44];
|
|
assign s_src1 = s_instruction_q[43:40];
|
|
assign s_aux = s_instruction_q[37:32];
|
|
assign s_immediate = s_instruction_q[31:0];
|
|
assign s_source0 = s_gpr_q[s_src0];
|
|
assign s_source1 = s_gpr_q[s_src1];
|
|
assign s_forward_target = {1'b0, s_pc_q} + 1'b1 + {1'b0, s_immediate[10:0]};
|
|
assign s_loop_target = {1'b0, s_pc_q} + 1'b1 - {1'b0, s_immediate[10:0]};
|
|
assign fetch_o = s_state_q == FetchRequest;
|
|
assign fetch_addr_o = s_pc_q;
|
|
assign stat_o = s_stat_q;
|
|
assign retired_o = {8'd0, s_frame_retired_q};
|
|
assign gpr_o = s_gpr_q;
|
|
assign trapped_o = s_trapped_q;
|
|
assign perf_retired_o = s_perf_retired_q;
|
|
assign idle_o = s_state_q == Idle;
|
|
|
|
always_comb begin
|
|
unique case (s_predicate)
|
|
4'd0: s_predicate_true = 1'b1;
|
|
4'd1: s_predicate_true = s_eq_q;
|
|
4'd2: s_predicate_true = !s_eq_q;
|
|
4'd3: s_predicate_true = s_signed_lt_q;
|
|
4'd4: s_predicate_true = !s_signed_lt_q;
|
|
4'd5: s_predicate_true = s_unsigned_lt_q;
|
|
4'd6: s_predicate_true = !s_unsigned_lt_q;
|
|
4'd7: s_predicate_true = input_exhausted_i;
|
|
4'd8: s_predicate_true = input_ready_i;
|
|
4'd9: s_predicate_true = output_ready_i;
|
|
4'd10: s_predicate_true = kernel_done_i;
|
|
4'd11: s_predicate_true = transport_idle_success_i;
|
|
default: s_predicate_true = 1'b0;
|
|
endcase
|
|
end
|
|
|
|
always_comb begin
|
|
s_trap_now = 1'b0;
|
|
s_trap_reason = 8'd0;
|
|
s_trap_detail = 32'd0;
|
|
if (stall_i && (s_watchdog_q + 1'b1 >= timeout_i)) begin
|
|
s_trap_now = 1'b1;
|
|
s_trap_reason = 8'd7;
|
|
end else if (!instruction_encoding_valid(s_instruction_q)) begin
|
|
s_trap_now = 1'b1;
|
|
s_trap_reason = 8'd1;
|
|
end else if ((s_class >= 4'd2) || ((s_class == 4'd0) && (s_opcode == 4'd8))) begin
|
|
s_trap_now = 1'b1;
|
|
s_trap_reason = 8'd6;
|
|
end else if (s_frame_retired_q >= s_max_retired_q) begin
|
|
s_trap_now = 1'b1;
|
|
s_trap_reason = 8'd8;
|
|
end else if (!s_predicate_true && ((s_pc_q == s_last_pc_q) || (s_pc_q == 11'd2047))) begin
|
|
s_trap_now = 1'b1;
|
|
s_trap_reason = 8'd2;
|
|
end else if (s_predicate_true && (s_class == 4'd0)) begin
|
|
unique case (s_opcode)
|
|
4'd0: begin
|
|
s_trap_now = (s_pc_q == s_last_pc_q) || (s_pc_q == 11'd2047);
|
|
s_trap_reason = 8'd2;
|
|
end
|
|
4'd1: begin
|
|
end
|
|
4'd2: begin
|
|
s_trap_now = 1'b1;
|
|
s_trap_reason = 8'd10;
|
|
s_trap_detail = s_immediate;
|
|
end
|
|
4'd3, 4'd4: begin
|
|
if (s_forward_target[11] || (s_forward_target[10:0] < s_first_pc_q) ||
|
|
(s_forward_target[10:0] > s_last_pc_q)) begin
|
|
s_trap_now = 1'b1;
|
|
s_trap_reason = 8'd2;
|
|
end else if ((s_opcode == 4'd4) && (s_return_depth_q == 3'd4)) begin
|
|
s_trap_now = 1'b1;
|
|
s_trap_reason = 8'd3;
|
|
end
|
|
end
|
|
4'd5: begin
|
|
s_trap_now = s_return_depth_q == 3'd0;
|
|
s_trap_reason = 8'd3;
|
|
end
|
|
4'd6: begin
|
|
s_trap_now = s_loop_active_q[s_aux[1:0]] || (s_source0[15:0] == 16'd0) ||
|
|
(s_source0[15:0] > s_max_loop_q);
|
|
s_trap_reason = 8'd4;
|
|
end
|
|
4'd7: begin
|
|
s_trap_now = s_loop_target[11] || !s_loop_active_q[s_aux[1:0]] ||
|
|
(s_loop_target[10:0] != s_loop_start_q[s_aux[1:0]]) ||
|
|
(s_loop_target[10:0] < s_first_pc_q);
|
|
s_trap_reason = 8'd4;
|
|
end
|
|
default: begin
|
|
s_trap_now = 1'b1;
|
|
s_trap_reason = 8'd1;
|
|
end
|
|
endcase
|
|
end else if (s_predicate_true && (s_class == 4'd1) &&
|
|
((s_pc_q == s_last_pc_q) || (s_pc_q == 11'd2047))) begin
|
|
s_trap_now = 1'b1;
|
|
s_trap_reason = 8'd2;
|
|
end
|
|
if (s_trap_now && (s_trap_reason != 8'd10)) begin
|
|
s_trap_detail = trap_detail(s_trap_reason, s_pc_q, s_instruction_q);
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
logic signed [32:0] s_signed_value;
|
|
logic signed [32:0] s_signed_min;
|
|
logic signed [32:0] s_signed_max;
|
|
logic [ 4:0] s_width;
|
|
s_width = s_aux[4:0] == 5'd0 ? 5'd31 : s_aux[4:0];
|
|
s_signed_value = {s_source0[31], s_source0};
|
|
s_signed_min = -33'sh08000_0000;
|
|
s_signed_max = 33'sh07fff_ffff;
|
|
s_sat_result = s_source0;
|
|
if ((s_aux[4:0] != 5'd0) && s_aux[5]) begin
|
|
s_signed_value = {s_source0[31], s_source0};
|
|
s_signed_min = -(33'sd1 <<< (s_width - 1'b1));
|
|
s_signed_max = (33'sd1 <<< (s_width - 1'b1)) - 1'b1;
|
|
if (s_signed_value < s_signed_min) begin
|
|
s_sat_result = s_signed_min[31:0];
|
|
end else if (s_signed_value > s_signed_max) begin
|
|
s_sat_result = s_signed_max[31:0];
|
|
end
|
|
end else if ((s_aux[4:0] != 5'd0) && (s_source0 > ((32'd1 << s_aux[4:0]) - 1'b1))) begin
|
|
s_sat_result = (32'd1 << s_aux[4:0]) - 1'b1;
|
|
end
|
|
end
|
|
|
|
`define RETROSOC_APU__SET_TRAP(DETAIL) \
|
|
begin \
|
|
s_state_q <= Idle; \
|
|
s_trapped_q <= 1'b1; \
|
|
trap_event_o <= 1'b1; \
|
|
fault_valid_o <= 1'b1; \
|
|
fault_code_o <= `APB4_APU__ERROR_CODE_SEQUENCER; \
|
|
fault_stage_o <= `APB4_APU__ERROR_STAGE_LIFECYCLE; \
|
|
fault_resp_o <= 2'd0; \
|
|
fault_index_o <= 8'd0; \
|
|
fault_addr_o <= {18'd0, s_pc_q, 3'd0}; \
|
|
fault_detail_o <= DETAIL; \
|
|
s_stat_q <= {11'd0, |s_loop_active_q, stall_i, s_opcode, s_class, s_pc_q}; \
|
|
end
|
|
|
|
`define RETROSOC_APU__SET_FETCH_WATCHDOG_TRAP \
|
|
begin \
|
|
s_state_q <= Idle; \
|
|
s_trapped_q <= 1'b1; \
|
|
trap_event_o <= 1'b1; \
|
|
fault_valid_o <= 1'b1; \
|
|
fault_code_o <= `APB4_APU__ERROR_CODE_SEQUENCER; \
|
|
fault_stage_o <= `APB4_APU__ERROR_STAGE_LIFECYCLE; \
|
|
fault_resp_o <= 2'd0; \
|
|
fault_index_o <= 8'd0; \
|
|
fault_addr_o <= {18'd0, s_pc_q, 3'd0}; \
|
|
fault_detail_o <= trap_detail(8'd7, s_pc_q, 64'd0); \
|
|
s_stat_q <= {11'd0, |s_loop_active_q, 1'b0, 8'd0, s_pc_q}; \
|
|
end
|
|
|
|
always_ff @(posedge clk_i or negedge rst_n_i) begin
|
|
if (!rst_n_i) begin
|
|
s_state_q <= Idle;
|
|
s_gpr_q <= '0;
|
|
s_eq_q <= 1'b0;
|
|
s_signed_lt_q <= 1'b0;
|
|
s_unsigned_lt_q <= 1'b0;
|
|
s_return_pc_q <= '0;
|
|
s_return_depth_q <= 3'd0;
|
|
s_loop_active_q <= 4'd0;
|
|
s_loop_count_q <= '0;
|
|
s_loop_start_q <= '0;
|
|
s_pc_q <= 11'd0;
|
|
s_first_pc_q <= 11'd0;
|
|
s_last_pc_q <= 11'd0;
|
|
s_max_loop_q <= 16'd0;
|
|
s_max_retired_q <= 24'd0;
|
|
s_frame_retired_q <= 24'd0;
|
|
s_watchdog_q <= 32'd0;
|
|
s_instruction_q <= 64'd0;
|
|
s_stat_q <= 32'd0;
|
|
s_trapped_q <= 1'b0;
|
|
s_perf_retired_q <= 64'd0;
|
|
trap_event_o <= 1'b0;
|
|
abort_done_o <= 1'b0;
|
|
fault_valid_o <= 1'b0;
|
|
fault_code_o <= 6'd0;
|
|
fault_stage_o <= 4'd0;
|
|
fault_resp_o <= 2'd0;
|
|
fault_index_o <= 8'd0;
|
|
fault_addr_o <= 32'd0;
|
|
fault_detail_o <= 32'd0;
|
|
end else begin
|
|
trap_event_o <= 1'b0;
|
|
abort_done_o <= 1'b0;
|
|
fault_valid_o <= 1'b0;
|
|
if (counter_clear_i) s_perf_retired_q <= 64'd0;
|
|
if (soft_reset_i || resource_reset_i) begin
|
|
s_state_q <= Idle;
|
|
s_gpr_q <= '0;
|
|
s_eq_q <= 1'b0;
|
|
s_signed_lt_q <= 1'b0;
|
|
s_unsigned_lt_q <= 1'b0;
|
|
s_return_depth_q <= 3'd0;
|
|
s_loop_active_q <= 4'd0;
|
|
s_pc_q <= 11'd0;
|
|
s_frame_retired_q <= 24'd0;
|
|
s_watchdog_q <= 32'd0;
|
|
s_stat_q <= 32'd0;
|
|
s_trapped_q <= 1'b0;
|
|
s_perf_retired_q <= 64'd0;
|
|
end else begin
|
|
unique case (s_state_q)
|
|
Idle: begin
|
|
if (launch_i && image_valid_i && (launch_entry_i < 2'd3)) begin
|
|
s_state_q <= FetchRequest;
|
|
s_gpr_q <= '0;
|
|
s_eq_q <= 1'b0;
|
|
s_signed_lt_q <= 1'b0;
|
|
s_unsigned_lt_q <= 1'b0;
|
|
s_return_depth_q <= 3'd0;
|
|
s_loop_active_q <= 4'd0;
|
|
s_pc_q <= entry_pc_i[launch_entry_i];
|
|
s_first_pc_q <= entry_first_i[launch_entry_i];
|
|
s_last_pc_q <= entry_last_i[launch_entry_i];
|
|
s_max_loop_q <= entry_max_loop_i[launch_entry_i];
|
|
s_max_retired_q <= entry_max_retired_i[launch_entry_i];
|
|
s_frame_retired_q <= 24'd0;
|
|
s_watchdog_q <= 32'd0;
|
|
s_stat_q <= {21'd0, entry_pc_i[launch_entry_i]};
|
|
s_trapped_q <= 1'b0;
|
|
end
|
|
end
|
|
FetchRequest: begin
|
|
s_stat_q <= {21'd0, s_pc_q};
|
|
if (s_watchdog_q + 1'b1 >= timeout_i) begin
|
|
`RETROSOC_APU__SET_FETCH_WATCHDOG_TRAP;
|
|
end else if (abort_i) begin
|
|
s_state_q <= Idle;
|
|
abort_done_o <= 1'b1;
|
|
end else begin
|
|
s_watchdog_q <= s_watchdog_q + 1'b1;
|
|
s_state_q <= FetchWait;
|
|
end
|
|
end
|
|
FetchWait: begin
|
|
if (s_watchdog_q + 1'b1 >= timeout_i) begin
|
|
`RETROSOC_APU__SET_FETCH_WATCHDOG_TRAP;
|
|
end else if (abort_i) begin
|
|
s_state_q <= Idle;
|
|
abort_done_o <= 1'b1;
|
|
end else begin
|
|
s_watchdog_q <= s_watchdog_q + 1'b1;
|
|
if (fetch_valid_i) begin
|
|
s_instruction_q <= fetch_data_i;
|
|
s_stat_q <= {
|
|
11'd0, |s_loop_active_q, 1'b0, fetch_data_i[59:56], fetch_data_i[63:60], s_pc_q
|
|
};
|
|
s_state_q <= Execute;
|
|
end
|
|
end
|
|
end
|
|
Execute: begin
|
|
if (cause_valid_i) begin
|
|
s_state_q <= Idle;
|
|
s_trapped_q <= 1'b1;
|
|
trap_event_o <= 1'b1;
|
|
fault_valid_o <= 1'b1;
|
|
fault_code_o <= cause_code_i;
|
|
fault_stage_o <= cause_stage_i;
|
|
fault_resp_o <= cause_resp_i;
|
|
fault_index_o <= cause_index_i;
|
|
fault_addr_o <= cause_addr_i;
|
|
fault_detail_o <= cause_detail_i;
|
|
s_stat_q <= {11'd0, |s_loop_active_q, stall_i, s_opcode, s_class, s_pc_q};
|
|
end else if (s_trap_now) begin
|
|
`RETROSOC_APU__SET_TRAP(s_trap_detail);
|
|
end else if (abort_i) begin
|
|
s_state_q <= Idle;
|
|
abort_done_o <= 1'b1;
|
|
end else if (stall_i) begin
|
|
s_stat_q[19] <= 1'b1;
|
|
if (s_watchdog_q + 1'b1 >= timeout_i) begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd7, s_pc_q, s_instruction_q));
|
|
end else begin
|
|
s_watchdog_q <= s_watchdog_q + 1'b1;
|
|
end
|
|
end else if (!instruction_encoding_valid(s_instruction_q)) begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd1, s_pc_q, s_instruction_q));
|
|
end else if ((s_class >= 4'd2) || ((s_class == 4'd0) && (s_opcode == 4'd8))) begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd6, s_pc_q, s_instruction_q));
|
|
end else if (s_frame_retired_q >= s_max_retired_q) begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd8, s_pc_q, s_instruction_q));
|
|
end else begin
|
|
s_watchdog_q <= 32'd0;
|
|
s_stat_q[19] <= 1'b0;
|
|
s_frame_retired_q <= s_frame_retired_q + 1'b1;
|
|
if (!counter_clear_i && !(&s_perf_retired_q)) begin
|
|
s_perf_retired_q <= s_perf_retired_q + 1'b1;
|
|
end
|
|
if (!s_predicate_true) begin
|
|
if ((s_pc_q == s_last_pc_q) || (s_pc_q == 11'd2047)) begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd2, s_pc_q, s_instruction_q));
|
|
s_frame_retired_q <= s_frame_retired_q;
|
|
s_perf_retired_q <= s_perf_retired_q;
|
|
end else begin
|
|
s_pc_q <= s_pc_q + 1'b1;
|
|
s_state_q <= FetchRequest;
|
|
end
|
|
end else if (s_class == 4'd0) begin
|
|
unique case (s_opcode)
|
|
4'd0: begin
|
|
if ((s_pc_q == s_last_pc_q) || (s_pc_q == 11'd2047)) begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd2, s_pc_q, s_instruction_q));
|
|
s_frame_retired_q <= s_frame_retired_q;
|
|
s_perf_retired_q <= s_perf_retired_q;
|
|
end else begin
|
|
s_pc_q <= s_pc_q + 1'b1;
|
|
s_state_q <= FetchRequest;
|
|
end
|
|
end
|
|
4'd1: s_state_q <= Idle;
|
|
4'd2: begin
|
|
`RETROSOC_APU__SET_TRAP(s_immediate);
|
|
s_frame_retired_q <= s_frame_retired_q;
|
|
s_perf_retired_q <= s_perf_retired_q;
|
|
end
|
|
4'd3: begin
|
|
if (s_forward_target[11] || (s_forward_target[10:0] < s_first_pc_q) ||
|
|
(s_forward_target[10:0] > s_last_pc_q)) begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd2, s_pc_q, s_instruction_q));
|
|
s_frame_retired_q <= s_frame_retired_q;
|
|
s_perf_retired_q <= s_perf_retired_q;
|
|
end else begin
|
|
s_pc_q <= s_forward_target[10:0];
|
|
s_state_q <= FetchRequest;
|
|
end
|
|
end
|
|
4'd4: begin
|
|
if (s_return_depth_q == 3'd4) begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd3, s_pc_q, s_instruction_q));
|
|
s_frame_retired_q <= s_frame_retired_q;
|
|
s_perf_retired_q <= s_perf_retired_q;
|
|
end else begin
|
|
s_return_pc_q[s_return_depth_q] <= s_pc_q + 1'b1;
|
|
s_return_depth_q <= s_return_depth_q + 1'b1;
|
|
s_pc_q <= s_forward_target[10:0];
|
|
s_state_q <= FetchRequest;
|
|
end
|
|
end
|
|
4'd5: begin
|
|
if (s_return_depth_q == 3'd0) begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd3, s_pc_q, s_instruction_q));
|
|
s_frame_retired_q <= s_frame_retired_q;
|
|
s_perf_retired_q <= s_perf_retired_q;
|
|
end else begin
|
|
s_return_depth_q <= s_return_depth_q - 1'b1;
|
|
s_pc_q <= s_return_pc_q[s_return_depth_q-1'b1];
|
|
s_state_q <= FetchRequest;
|
|
end
|
|
end
|
|
4'd6: begin
|
|
if (s_loop_active_q[s_aux[1:0]] || (s_source0[15:0] == 16'd0) ||
|
|
(s_source0[15:0] > s_max_loop_q)) begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd4, s_pc_q, s_instruction_q));
|
|
s_frame_retired_q <= s_frame_retired_q;
|
|
s_perf_retired_q <= s_perf_retired_q;
|
|
end else begin
|
|
s_loop_active_q[s_aux[1:0]] <= 1'b1;
|
|
s_loop_count_q[s_aux[1:0]] <= s_source0[15:0];
|
|
s_loop_start_q[s_aux[1:0]] <= s_pc_q + 1'b1;
|
|
s_pc_q <= s_pc_q + 1'b1;
|
|
s_state_q <= FetchRequest;
|
|
end
|
|
end
|
|
4'd7: begin
|
|
if (s_loop_target[11] || !s_loop_active_q[s_aux[1:0]] ||
|
|
(s_loop_target[10:0] != s_loop_start_q[s_aux[1:0]]) ||
|
|
(s_loop_target[10:0] < s_first_pc_q)) begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd4, s_pc_q, s_instruction_q));
|
|
s_frame_retired_q <= s_frame_retired_q;
|
|
s_perf_retired_q <= s_perf_retired_q;
|
|
end else if (s_loop_count_q[s_aux[1:0]] > 16'd1) begin
|
|
s_loop_count_q[s_aux[1:0]] <= s_loop_count_q[s_aux[1:0]] - 1'b1;
|
|
s_pc_q <= s_loop_target[10:0];
|
|
s_state_q <= FetchRequest;
|
|
end else begin
|
|
s_loop_active_q[s_aux[1:0]] <= 1'b0;
|
|
s_pc_q <= s_pc_q + 1'b1;
|
|
s_state_q <= FetchRequest;
|
|
end
|
|
end
|
|
default: begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd1, s_pc_q, s_instruction_q));
|
|
s_frame_retired_q <= s_frame_retired_q;
|
|
s_perf_retired_q <= s_perf_retired_q;
|
|
end
|
|
endcase
|
|
end else begin
|
|
unique case (s_opcode)
|
|
4'd0: s_gpr_q[s_dst] <= s_source0;
|
|
4'd1: s_gpr_q[s_dst] <= s_immediate;
|
|
4'd2: s_gpr_q[s_dst] <= s_source0 + s_source1;
|
|
4'd3: s_gpr_q[s_dst] <= s_source0 - s_source1;
|
|
4'd4: s_gpr_q[s_dst] <= s_source0 & s_source1;
|
|
4'd5: s_gpr_q[s_dst] <= s_source0 | s_source1;
|
|
4'd6: s_gpr_q[s_dst] <= s_source0 ^ s_source1;
|
|
4'd7: s_gpr_q[s_dst] <= s_source0 << s_source1[4:0];
|
|
4'd8: s_gpr_q[s_dst] <= s_source0 >> s_source1[4:0];
|
|
4'd9: s_gpr_q[s_dst] <= $unsigned($signed(s_source0) >>> s_source1[4:0]);
|
|
4'd10: begin
|
|
s_eq_q <= s_source0 == s_source1;
|
|
s_signed_lt_q <= $signed(s_source0) < $signed(s_source1);
|
|
s_unsigned_lt_q <= s_source0 < s_source1;
|
|
end
|
|
4'd11:
|
|
s_gpr_q[s_dst] <= s_aux[0] ? (($signed(
|
|
s_source0
|
|
) < $signed(
|
|
s_source1
|
|
)) ? s_source0 : s_source1) : ((s_source0 < s_source1) ? s_source0 : s_source1);
|
|
4'd12:
|
|
s_gpr_q[s_dst] <= s_aux[0] ? (($signed(
|
|
s_source0
|
|
) > $signed(
|
|
s_source1
|
|
)) ? s_source0 : s_source1) : ((s_source0 > s_source1) ? s_source0 : s_source1);
|
|
4'd13: s_gpr_q[s_dst] <= s_sat_result;
|
|
default: begin
|
|
end
|
|
endcase
|
|
if ((s_pc_q == s_last_pc_q) || (s_pc_q == 11'd2047)) begin
|
|
`RETROSOC_APU__SET_TRAP(trap_detail(8'd2, s_pc_q, s_instruction_q));
|
|
s_frame_retired_q <= s_frame_retired_q;
|
|
s_perf_retired_q <= s_perf_retired_q;
|
|
end else begin
|
|
s_pc_q <= s_pc_q + 1'b1;
|
|
s_state_q <= FetchRequest;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
default: s_state_q <= Idle;
|
|
endcase
|
|
end
|
|
end
|
|
end
|
|
endmodule
|
|
|
|
`undef RETROSOC_APU__SET_TRAP
|
|
`undef RETROSOC_APU__SET_FETCH_WATCHDOG_TRAP
|