3414 lines
173 KiB
Plaintext
3414 lines
173 KiB
Plaintext
-- altera vhdl_input_version vhdl_2008
|
|
-- XXX: QSYS Fix (https://www.intel.com/content/www/us/en/support/programmable/articles/000079458.html)
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
use work.math_pkg.all;
|
|
use work.rtps_package.all;
|
|
use work.rtps_config_package.all;
|
|
use work.ros_package.all;
|
|
use work.Fibonacci_package.all;
|
|
use work.GoalStatus_package;
|
|
use work.CancelGoal_package;
|
|
use work.GoalStatusArray_package;
|
|
|
|
entity ros_action_server is
|
|
generic (
|
|
TIMEOUT_DURATION : ROS_DURATION_TYPE;
|
|
MAX_GOALS : natural;
|
|
MAX_RESULT_REQUESTS : natural
|
|
);
|
|
port (
|
|
-- SYSTEM
|
|
clk : in std_logic;
|
|
reset : in std_logic;
|
|
time : in ROS_TIME_TYPE;
|
|
-- *GOAL SERVICE*
|
|
start_g : out std_logic;
|
|
ack_g : in std_logic;
|
|
opcode_g : out ROS_SERVICE_OPCODE_TYPE;
|
|
service_info_g : in SERVICE_INFO_TYPE;
|
|
request_id_g : out REQUEST_ID_TYPE;
|
|
data_available_g : in std_logic;
|
|
taken_g : in std_logic;
|
|
done_g : in std_logic;
|
|
return_code_g : in std_logic_vector(ROS_RETCODE_WIDTH-1 downto 0);
|
|
-- REQUEST
|
|
goal_id_g : in std_logic_vector(UUID_WIDTH-1 downto 0);
|
|
-- RESPONSE
|
|
accepted_g : out std_logic;
|
|
stamp_g : out std_logic_vector(ROS_TIME_WIDTH-1 downto 0);
|
|
-- *RESULT SERVICE*
|
|
start_r : out std_logic;
|
|
ack_r : in std_logic;
|
|
opcode_r : out ROS_SERVICE_OPCODE_TYPE;
|
|
service_info_r : in SERVICE_INFO_TYPE;
|
|
request_id_r : out REQUEST_ID_TYPE;
|
|
data_available_r : in std_logic;
|
|
taken_r : in std_logic;
|
|
done_r : in std_logic;
|
|
return_code_r : in std_logic_vector(ROS_RETCODE_WIDTH-1 downto 0);
|
|
result_index : out std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
result_sel : out std_logic;
|
|
result_sel_ack : in std_logic;
|
|
-- REQUEST
|
|
goal_id_r : in std_logic_vector(UUID_WIDTH-1 downto 0);
|
|
-- RESPONSE
|
|
status_r : out std_logic_vector(CDR_INT8_WIDTH-1 downto 0);
|
|
-- *CANCEL SERVICE*
|
|
start_c : out std_logic;
|
|
ack_c : in std_logic;
|
|
opcode_c : out ROS_SERVICE_OPCODE_TYPE;
|
|
service_info_c : in SERVICE_INFO_TYPE;
|
|
request_id_c : out REQUEST_ID_TYPE;
|
|
data_available_c : in std_logic;
|
|
taken_c : in std_logic;
|
|
done_c : in std_logic;
|
|
return_code_c : in std_logic_vector(ROS_RETCODE_WIDTH-1 downto 0);
|
|
-- REQUEST
|
|
goal_info_goal_id_c : in std_logic_vector(UUID_WIDTH-1 downto 0);
|
|
goal_info_stamp_c : in std_logic_vector(ROS_TIME_WIDTH-1 downto 0);
|
|
-- RESPONSE
|
|
cancel_return_code_c : out std_logic_vector(CDR_INT8_WIDTH-1 downto 0);
|
|
goals_canceling_len_c : out std_logic_vector(CancelGoal_package.RR_GOALS_CANCELING_ADDR_WIDTH-1 downto 0);
|
|
goals_canceling_addr_c : out std_logic_vector(CancelGoal_package.RR_GOALS_CANCELING_ADDR_WIDTH-1 downto 0);
|
|
goals_canceling_ready_c : in std_logic;
|
|
goals_canceling_ren_c : out std_logic;
|
|
goals_canceling_wen_c : out std_logic;
|
|
goals_canceling_valid_c : in std_logic;
|
|
goals_canceling_ack_c : out std_logic;
|
|
goals_canceling_goal_id_r_c : in std_logic_vector(UUID_WIDTH-1 downto 0);
|
|
goals_canceling_goal_id_w_c : out std_logic_vector(UUID_WIDTH-1 downto 0);
|
|
goals_canceling_stamp_r_c : in std_logic_vector(ROS_TIME_WIDTH-1 downto 0);
|
|
goals_canceling_stamp_w_c : out std_logic_vector(ROS_TIME_WIDTH-1 downto 0);
|
|
-- *FEEDBACK TOPIC*
|
|
start_fb : out std_logic;
|
|
opcode_fb : out ROS_TOPIC_OPCODE_TYPE;
|
|
ack_fb : in std_logic;
|
|
done_fb : in std_logic;
|
|
return_code_fb : in std_logic_vector(ROS_RETCODE_WIDTH-1 downto 0);
|
|
goal_id_fb : out std_logic_vector(UUID_WIDTH-1 downto 0);
|
|
-- *STATUS TOPIC*
|
|
start_s : out std_logic;
|
|
opcode_s : out ROS_TOPIC_OPCODE_TYPE;
|
|
ack_s : in std_logic;
|
|
done_s : in std_logic;
|
|
return_code_s : in std_logic_vector(ROS_RETCODE_WIDTH-1 downto 0);
|
|
status_list_len_s : out std_logic_vector(GoalStatusArray_package.STATUS_LIST_ADDR_WIDTH-1 downto 0);
|
|
status_list_addr_s : out std_logic_vector(GoalStatusArray_package.STATUS_LIST_ADDR_WIDTH-1 downto 0);
|
|
status_list_ready_s : in std_logic;
|
|
status_list_ren_s : out std_logic;
|
|
status_list_wen_s : out std_logic;
|
|
status_list_valid_s : in std_logic;
|
|
status_list_ack_s : out std_logic;
|
|
status_list_goal_info_goal_id_r_s : in std_logic_vector(UUID_WIDTH-1 downto 0);
|
|
status_list_goal_info_goal_id_w_s : out std_logic_vector(UUID_WIDTH-1 downto 0);
|
|
status_list_goal_info_stamp_r_s : in std_logic_vector(ROS_TIME_WIDTH-1 downto 0);
|
|
status_list_goal_info_stamp_w_s : out std_logic_vector(ROS_TIME_WIDTH-1 downto 0);
|
|
status_list_status_r_s : in std_logic_vector(CDR_INT8_WIDTH-1 downto 0);
|
|
status_list_status_w_s : out std_logic_vector(CDR_INT8_WIDTH-1 downto 0);
|
|
-- *USER*
|
|
start : in std_logic;
|
|
opcode : in ROS_ACTION_OPCODE_TYPE;
|
|
ack : out std_logic;
|
|
done : out std_logic;
|
|
return_code : out std_logic_vector(ROS_RETCODE_WIDTH-1 downto 0);
|
|
goal_handle_in : in std_logic_vector(GOAL_HANDLE_WIDTH-1 downto 0);
|
|
goal_handle_out : out std_logic_vector(GOAL_HANDLE_WIDTH-1 downto 0);
|
|
goal_state_in : in std_logic_vector(CDR_INT8_WIDTH-1 downto 0);
|
|
goal_state_out : out std_logic_vector(CDR_INT8_WIDTH-1 downto 0);
|
|
goal_id : out std_logic_vector(UUID_WIDTH-1 downto 0);
|
|
goal_result_index : out std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
goal_stamp : out ROS_TIME_TYPE;
|
|
-- GOAL
|
|
new_goal_request : out std_logic;
|
|
new_goal_handle : out std_logic_vector(GOAL_HANDLE_WIDTH-1 downto 0);
|
|
new_goal_result_index : out std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
new_goal_accepted : in std_logic;
|
|
new_goal_response : in std_logic;
|
|
-- CANCEL
|
|
cancel_request : out std_logic;
|
|
cancel_request_handle : out std_logic_vector(GOAL_HANDLE_WIDTH-1 downto 0);
|
|
cancel_accepted : in std_logic;
|
|
cancel_response : in std_logic
|
|
);
|
|
end entity;
|
|
|
|
architecture arch of ros_action_server is
|
|
|
|
--*****CONSTANT DECLARATION*****
|
|
-- *GOAL MEMORY*
|
|
-- 4-Byte Word Size of a Goal Entry in Memory
|
|
function gen_goal_frame_size(TIMEOUT_DURATION : ROS_DURATION_TYPE) return natural is
|
|
begin
|
|
if (TIMEOUT_DURATION /= ROS_DURATION_INFINITE) then
|
|
return 12;
|
|
else
|
|
return 10;
|
|
end if;
|
|
end function;
|
|
constant GOAL_FRAME_SIZE : natural := gen_goal_frame_size(TIMEOUT_DURATION);
|
|
-- Goal Memory Size in 4-Byte Words
|
|
constant GOAL_MEMORY_SIZE : natural := MAX_GOALS * GOAL_FRAME_SIZE;
|
|
-- Goal Memory Address Width
|
|
constant GOAL_MEMORY_ADDR_WIDTH : natural := log2c(GOAL_MEMORY_SIZE);
|
|
-- Highest Goal Memory Address
|
|
constant GOAL_MEMORY_MAX_ADDRESS : unsigned(GOAL_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(GOAL_MEMORY_SIZE-1, GOAL_MEMORY_ADDR_WIDTH);
|
|
-- Highest Goal Frame Address
|
|
constant MAX_GOAL_ADDRESS : unsigned(GOAL_MEMORY_ADDR_WIDTH-1 downto 0) := GOAL_MEMORY_MAX_ADDRESS - GOAL_FRAME_SIZE + 1;
|
|
-- Address pointing to the beginning of the first Goal Data Frame
|
|
constant FIRST_GOAL_ADDRESS : unsigned(GOAL_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- *RESULT REQUEST MEMORY*
|
|
-- 4-Byte Word Size of a Result Request Entry in Memory
|
|
constant RRQ_FRAME_SIZE : natural := 9;
|
|
-- Result Request Memory Size in 4-Byte Words
|
|
constant RRQ_MEMORY_SIZE : natural := MAX_RESULT_REQUESTS * RRQ_FRAME_SIZE;
|
|
-- Result Request Memory Address Width
|
|
constant RRQ_MEMORY_ADDR_WIDTH : natural := log2c(RRQ_MEMORY_SIZE);
|
|
-- Highest Result Request Memory Address
|
|
constant RRQ_MEMORY_MAX_ADDRESS : unsigned(RRQ_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(RRQ_MEMORY_SIZE-1, RRQ_MEMORY_ADDR_WIDTH);
|
|
-- Highest Result Request Frame Address
|
|
constant MAX_RRQ_ADDRESS : unsigned(RRQ_MEMORY_ADDR_WIDTH-1 downto 0) := RRQ_MEMORY_MAX_ADDRESS - RRQ_FRAME_SIZE + 1;
|
|
-- Address pointing to the beginning of the first Result Request Data Frame
|
|
constant FIRST_RRQ_ADDRESS : unsigned(RRQ_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
|
|
-- *GOAL MEMORY FRAME FIELD OFFSETS*
|
|
-- 4-Byte Word Offsets to Beginning of Respective Fields in the Goal Memory Frame
|
|
constant GMF_STATE_OFFSET : natural := 0;
|
|
constant GMF_GOAL_ID_OFFSET : natural := 1;
|
|
constant GMF_STAMP_OFFSET : natural := 5;
|
|
constant GMF_DEADLINE_OFFSET : natural := 7;
|
|
function gen_gmf_result_index_offset(TIMEOUT_DURATION : ROS_DURATION_TYPE) return natural is
|
|
variable ret : natural := 0;
|
|
begin
|
|
if (TIMEOUT_DURATION = ROS_DURATION_INFINITE) then
|
|
ret := GMF_DEADLINE_OFFSET + 2;
|
|
else
|
|
ret := GMF_DEADLINE_OFFSET;
|
|
end if;
|
|
return ret;
|
|
end function;
|
|
constant GMF_RESULT_INDEX_OFFSET : natural := gen_gmf_result_index_offset(TIMEOUT_DURATION);
|
|
constant GMF_NEXT_ADDR_OFFSET : natural := GMF_RESULT_INDEX_OFFSET + 1;
|
|
constant GMF_PREV_ADDR_OFFSET : natural := GMF_NEXT_ADDR_OFFSET + 1;
|
|
-- *RESULT REQUEST MEMORY FRAME FIELD OFFSETS*
|
|
-- 4-Byte Word Offsets to Beginning of Respective Fields in the Result Request Memory Frame
|
|
constant RMF_GOAL_HANDLE_OFFSET : natural := 0;
|
|
constant RMF_REQUEST_ID_OFFSET : natural := 1;
|
|
constant RMF_NEXT_ADDR_OFFSET : natural := 7;
|
|
constant RMF_PREV_ADDR_OFFSET : natural := 8;
|
|
|
|
-- *GOAL MEMORY FRAME FIELD FLAGS*
|
|
-- Flags mapping to the respective Goal Memory Frame Fields
|
|
constant GMF_FLAG_WIDTH : natural := 7;
|
|
constant GMF_STATE_FLAG : std_logic_vector(0 to GMF_FLAG_WIDTH-1) := (0 => '1', others => '0');
|
|
constant GMF_GOAL_ID_FLAG : std_logic_vector(0 to GMF_FLAG_WIDTH-1) := (1 => '1', others => '0');
|
|
constant GMF_STAMP_FLAG : std_logic_vector(0 to GMF_FLAG_WIDTH-1) := (2 => '1', others => '0');
|
|
constant GMF_DEADLINE_FLAG : std_logic_vector(0 to GMF_FLAG_WIDTH-1) := (3 => '1', others => '0');
|
|
constant GMF_RESULT_INDEX_FLAG : std_logic_vector(0 to GMF_FLAG_WIDTH-1) := (4 => '1', others => '0');
|
|
constant GMF_NEXT_ADDR_FLAG : std_logic_vector(0 to GMF_FLAG_WIDTH-1) := (5 => '1', others => '0');
|
|
constant GMF_PREV_ADDR_FLAG : std_logic_vector(0 to GMF_FLAG_WIDTH-1) := (6 => '1', others => '0');
|
|
|
|
--*****TYPE DECLARATION*****
|
|
-- *Cancel Process Search Types*
|
|
-- SEARCH_GOAL_ID Search goal list for a specific goal id
|
|
-- SEARCH_STAMP Search goal list for first goal that was accepted at or before a provided timestamp
|
|
-- SEARCH_NONE No search criteria. All goals are valid candidates (Applies from current list position)
|
|
type SEARCH_TYPE is (SEARCH_GOAL_ID, SEARCH_STAMP, SEARCH_NONE);
|
|
-- *Instance Memory Opcodes*
|
|
-- OPCODE DESCRIPTION
|
|
-- INSERT Insert goal into memory
|
|
-- GET Get data of goal pointed by "GOAL_DATA_TYPE.addr" according to "GOAL_DATA_TYPE.field_flags".
|
|
-- Already fetched data of the goal is not modified.
|
|
-- GET_NEXT Get goal data of next goal (from the goal pointed by "GOAL_DATA_TYPE.addr") according to "GOAL_DATA_TYPE.field_flags".
|
|
-- Set "GOAL_DATA_TYPE.addr" to address of goal or GOAL_MEMORY_MAX_ADDRESS if no other goal in Memory.
|
|
-- GET_PREV Get goal data of previous goal (from the goal pointed by "GOAL_DATA_TYPE.addr") according to "GOAL_DATA_TYPE.field_flags".
|
|
-- Set "GOAL_DATA_TYPE.addr" to address of goal or GOAL_MEMORY_MAX_ADDRESS if no other goal in Memory.
|
|
-- UPDATE Update goal data pointed by "GOAL_DATA_TYPE.addr" according to "GOAL_DATA_TYPE.field_flags"
|
|
-- REMOVE Remove goal pointed by "GOAL_DATA_TYPE.addr"
|
|
type MEM_OPCODE_TYPE is (NOP, INSERT, GET, GET_NEXT, GET_PREV, UPDATE, REMOVE);
|
|
type STAGE_TYPE is (IDLE,WAIT_FOR_DATA,SEARCH_ID,CHECK_STATE,STORE_RRQ,SEND_RESPONSE,WAIT_FOR_RET,TRANSITION_STATE,GET_DATA,CHECK_REQUESTS,GET_REQUEST_ID,REMOVE_REQUEST,WAIT_FOR_MEM,RETURN_USER,CHECK_TIMEOUT,REMOVE_OLDEST,PUBLISH_FEEDBACK,RESET_MEMORY);
|
|
type STATUS_STAGE_TYPE is (IDLE,GET_FIRST,GET_NEXT,WAIT_FOR_DATA,PUSH_STATUS,PUBLISH,WAIT_FOR_PUBLISHER);
|
|
type GOAL_STAGE_TYPE is (IDLE,WAIT_FOR_DATA,WAIT_FOR_USER,ADD_GOAL,SEND_RESPONSE,WAIT_FOR_RET);
|
|
type CANCEL_STAGE_TYPE is (IDLE,WAIT_FOR_DATA,GET,GET_NEXT,CHECK,CHECK_GOAL_ID,CHECK_STAMP,CHECK_STATE,WAIT_FOR_USER,CANCEL_GOAL,ADD_CANCEL,SEND_RESPONSE,WAIT_FOR_RET);
|
|
type MEM_STAGE_TYPE is (IDLE,INSERT,GET,GET_NEXT,GET_PREV,UPDATE,REMOVE,RESET_MEMORY);
|
|
type GOAL_DATA_TYPE is record
|
|
addr : unsigned(GOAL_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
goal_id : GUID_TYPE;
|
|
stamp : ROS_TIME_TYPE;
|
|
deadline : ROS_DURATION_TYPE;
|
|
res_ind : std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
state : std_logic_vector(CDR_INT8_WIDTH-1 downto 0);
|
|
field_flags : std_logic_vector(0 to GMF_FLAG_WIDTH-1);
|
|
end record;
|
|
constant ZERO_GOAL_DATA : GOAL_DATA_TYPE := (
|
|
addr => (others => '0'),
|
|
goal_id => GUID_UNKNOWN,
|
|
stamp => ROS_TIME_ZERO,
|
|
deadline => ROS_DURATION_INFINITE,
|
|
res_ind => (others => '0'),
|
|
state => GoalStatus_package.STATUS_UNKNOWN,
|
|
field_flags => (others => '0')
|
|
);
|
|
|
|
--*****SIGNAL DECLARATION*****
|
|
-- *GOAL MEMORY CONNECTION SIGNALS*
|
|
signal mem_addr : unsigned(GOAL_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
signal mem_read : std_logic;
|
|
signal mem_read_data, mem_write_data : std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
signal mem_ready_in, mem_valid_in : std_logic;
|
|
signal mem_ready_out, mem_valid_out : std_logic;
|
|
signal mem_abort_read : std_logic;
|
|
-- *RESULT REQUEST MEMORY CONNECTION SIGNALS*
|
|
signal rrq_addr : unsigned(RRQ_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
signal rrq_read : std_logic;
|
|
signal rrq_read_data, rrq_write_data : std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
signal rrq_ready_in, rrq_valid_in : std_logic;
|
|
signal rrq_ready_out, rrq_valid_out : std_logic;
|
|
signal rrq_abort_read : std_logic;
|
|
|
|
-- *MAIN PROCESS*
|
|
-- FSM state
|
|
signal stage, stage_next : STAGE_TYPE;
|
|
-- Request memory operation
|
|
signal mem_start_r : std_logic;
|
|
-- Opcode of goal memory operation (valid only if mem_start_r is high)
|
|
signal mem_opcode_r : MEM_OPCODE_TYPE;
|
|
-- Signal used to pass data to Goal Memory Process
|
|
signal mem_r : GOAL_DATA_TYPE;
|
|
-- Goal memory data latch
|
|
signal mem_data_r, mem_data_r_next : GOAL_DATA_TYPE;
|
|
-- Head of occupied result requests list
|
|
signal rrq_occupied_head, rrq_occupied_head_next : unsigned(RRQ_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Head of empty result requests list
|
|
signal rrq_empty_head, rrq_empty_head_next : unsigned(RRQ_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- General purpose counter
|
|
signal cnt, cnt_next : natural range 0 to 11;
|
|
-- Pointer to current relevant Result Request Memory Frame
|
|
signal rrq_addr_base, rrq_addr_base_next : unsigned(RRQ_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Result Request Memory Frame pointer latch
|
|
signal rrq_addr_latch, rrq_addr_latch_next : unsigned(RRQ_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Count of stored goals that are in a terminal state
|
|
signal terminal_cnt, terminal_cnt_next : natural range 0 to MAX_GOALS;
|
|
-- User return code latch
|
|
signal return_code_latch, return_code_latch_next : std_logic_vector(ROS_RETCODE_WIDTH-1 downto 0);
|
|
-- Toggle latch used to trigger stored result request search when a goal is updated to a terminal state
|
|
signal trigger_result, trigger_result_next : std_logic;
|
|
-- Signal used to signal goal status change (Used by status process to generate new goal status list)
|
|
signal trigger_status_r : std_logic;
|
|
-- Result service Request ID latch
|
|
signal request_id_latch, request_id_latch_next : REQUEST_ID_TYPE;
|
|
-- Time of next goal expiration deadline
|
|
signal check_time, check_time_next : ROS_TIME_TYPE;
|
|
-- Temporal time latch (used in time addition calculation)
|
|
signal time_latch, time_latch_next : ROS_TIME_TYPE;
|
|
-- Signals that the main FSM has entered the atomic operation range (Used mutex lock between main and cancel FSMs)
|
|
signal atomic_op_r : std_logic;
|
|
-- Goal handle latch
|
|
signal goal_handle_latch, goal_handle_latch_next : std_logic_vector(GOAL_HANDLE_WIDTH-1 downto 0);
|
|
-- Goal state latch
|
|
signal goal_state_latch, goal_state_latch_next :std_logic_vector(CDR_INT8_WIDTH-1 downto 0);
|
|
|
|
-- *GOAL PROCESS*
|
|
-- Goal Process FSM state
|
|
signal goal_stage, goal_stage_next : GOAL_STAGE_TYPE;
|
|
-- Request memory operation
|
|
signal mem_start_g : std_logic;
|
|
-- Opcode of memory operation (valid only if mem_start_g is high)
|
|
signal mem_opcode_g : MEM_OPCODE_TYPE;
|
|
-- Goal timestamp latch
|
|
signal g_stamp, g_stamp_next : ROS_TIME_TYPE;
|
|
-- Goal accept latch
|
|
signal g_accept, g_accept_next : std_logic;
|
|
-- Signal used to signal goal status change (Used by status process to generate new goal status list)
|
|
signal trigger_status_g : std_logic;
|
|
|
|
-- *CANCEL PROCESS*
|
|
-- Cancel process FSM state
|
|
signal cancel_stage, cancel_stage_next : CANCEL_STAGE_TYPE;
|
|
-- Request memory operation
|
|
signal mem_start_c : std_logic;
|
|
-- Opcode of memory operation (valid only if mem_start_c is high)
|
|
signal mem_opcode_c : MEM_OPCODE_TYPE;
|
|
-- Signal used to pass data to Goal Memory Process
|
|
signal mem_c : GOAL_DATA_TYPE;
|
|
-- General purpose counter
|
|
signal c_cnt, c_cnt_next : natural range 0 to 3;
|
|
-- Goal memory data latch
|
|
signal mem_data_c, mem_data_c_next : GOAL_DATA_TYPE;
|
|
-- Signals the kind of search the cancel FSM is doing (see SEARCH_TYPE definition)
|
|
signal search_type_c, search_type_c_next : SEARCH_TYPE;
|
|
-- Index of goals_canceling sequence
|
|
signal goals_canceling_cnt, goals_canceling_cnt_next : natural range 0 to CancelGoal_package.RR_GOALS_CANCELING_MAX_DEPTH-1;
|
|
-- Cancel response return code latch
|
|
signal cancel_ret_code, cancel_ret_code_next : std_logic_vector(CDR_INT8_WIDTH-1 downto 0);
|
|
-- Signal used to signal goal status change (Used by status process to generate new goal status list)
|
|
signal trigger_status_c : std_logic;
|
|
-- Signals that the cancel FSM has entered the atomic operation range (Used mutex lock between main and cancel FSMs)
|
|
signal atomic_op_c: std_logic;
|
|
|
|
-- *STATUS PROCESS*
|
|
-- Status process FSM
|
|
signal status_stage, status_stage_next : STATUS_STAGE_TYPE;
|
|
-- Toggle latch that latches status update requests from other processes
|
|
signal trigger_status, trigger_status_next : std_logic;
|
|
-- Index of status list sequence
|
|
signal status_list_cnt, status_list_cnt_next : natural range 0 to MAX_GOALS-1;
|
|
-- Request memory operation
|
|
signal mem_start_s : std_logic;
|
|
-- Opcode of memory operation (valid only if mem_start_s is high)
|
|
signal mem_opcode_s : MEM_OPCODE_TYPE;
|
|
-- Signal used to pass data to Goal Memory Process
|
|
signal mem_s : GOAL_DATA_TYPE;
|
|
-- Goal memory data latch
|
|
signal mem_data_s, mem_data_s_next : GOAL_DATA_TYPE;
|
|
-- Test signal used for testbench synchronisation
|
|
signal status_idle_sig : std_logic;
|
|
|
|
-- *GOAL MEMORY PROCESS*
|
|
-- Memory process FSM state
|
|
signal mem_stage, mem_stage_next : MEM_STAGE_TYPE;
|
|
-- Acknowledge memory request from respective process
|
|
signal mem_ack_r, mem_ack_s, mem_ack_c, mem_ack_g : std_logic;
|
|
-- Head of occupied goal list
|
|
signal mem_occupied_head, mem_occupied_head_next : unsigned(GOAL_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Tail of occupied goal list
|
|
signal mem_occupied_tail, mem_occupied_tail_next : unsigned(GOAL_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Head of empty goal list
|
|
signal mem_empty_head, mem_empty_head_next : unsigned(GOAL_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Tail of empty goal list
|
|
signal mem_empty_tail, mem_empty_tail_next : unsigned(GOAL_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- General purpose counter
|
|
signal mem_cnt, mem_cnt_next : natural range 0 to 19;
|
|
-- Pointer to currently relevant goal memory frame
|
|
signal mem_addr_base, mem_addr_base_next : unsigned(GOAL_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Goal memory frame pointer latch
|
|
signal mem_addr_latch, mem_addr_latch_next : unsigned(GOAL_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Result index of current empty head goal
|
|
signal empty_head_res_ind, empty_head_res_ind_next : unsigned(WORD_WIDTH-1 downto 0);
|
|
-- Latch for data from processes
|
|
signal mem_latch_data, mem_latch_data_next : GOAL_DATA_TYPE;
|
|
-- Latch for goal memory data
|
|
signal mem_data, mem_data_next : GOAL_DATA_TYPE;
|
|
-- Signals end of memory operation (And that the memory process is in the IDLE state)
|
|
signal mem_done : std_logic;
|
|
|
|
-- *FUNCTION DECLARATION*
|
|
-- Returns true if the state is terminal
|
|
function is_terminal (state : std_logic_vector) return boolean is
|
|
begin
|
|
assert (state'length = CDR_INT8_WIDTH) severity FAILURE;
|
|
|
|
case (state) is
|
|
when GoalStatus_package.STATUS_SUCCEEDED =>
|
|
return TRUE;
|
|
when GoalStatus_package.STATUS_CANCELED =>
|
|
return TRUE;
|
|
when GoalStatus_package.STATUS_ABORTED =>
|
|
return TRUE;
|
|
when others =>
|
|
return FALSE;
|
|
end case;
|
|
end function;
|
|
|
|
begin
|
|
|
|
goal_mem_ctrl_inst : entity work.mem_ctrl(arch)
|
|
generic map (
|
|
ADDR_WIDTH => GOAL_MEMORY_ADDR_WIDTH,
|
|
DATA_WIDTH => WORD_WIDTH,
|
|
MEMORY_DEPTH => GOAL_MEMORY_SIZE,
|
|
MAX_BURST_LENGTH => GOAL_FRAME_SIZE
|
|
)
|
|
port map (
|
|
clk => clk,
|
|
reset => reset or mem_abort_read,
|
|
addr => std_logic_vector(mem_addr),
|
|
read => mem_read,
|
|
ready_in => mem_ready_in,
|
|
valid_in => mem_valid_in,
|
|
data_in => mem_write_data,
|
|
ready_out => mem_ready_out,
|
|
valid_out => mem_valid_out,
|
|
data_out => mem_read_data
|
|
);
|
|
|
|
rrq_mem_ctrl_inst : entity work.mem_ctrl(arch)
|
|
generic map (
|
|
ADDR_WIDTH => RRQ_MEMORY_ADDR_WIDTH,
|
|
DATA_WIDTH => WORD_WIDTH,
|
|
MEMORY_DEPTH => RRQ_MEMORY_SIZE,
|
|
MAX_BURST_LENGTH => RRQ_FRAME_SIZE
|
|
)
|
|
port map (
|
|
clk => clk,
|
|
reset => reset or rrq_abort_read,
|
|
addr => std_logic_vector(rrq_addr),
|
|
read => rrq_read,
|
|
ready_in => rrq_ready_in,
|
|
valid_in => rrq_valid_in,
|
|
data_in => rrq_write_data,
|
|
ready_out => rrq_ready_out,
|
|
valid_out => rrq_valid_out,
|
|
data_out => rrq_read_data
|
|
);
|
|
|
|
result_index <= mem_data_r.res_ind;
|
|
status_r <= mem_data_r.state;
|
|
request_id_r <= request_id_latch;
|
|
goal_id_fb <= std_logic_vector(to_unsigned(mem_data_r.goal_id));
|
|
goal_id <= std_logic_vector(to_unsigned(mem_data_r.goal_id));
|
|
goal_stamp <= mem_data_r.stamp;
|
|
goal_state_out <= mem_data_r.state;
|
|
goal_result_index <= mem_data_r.res_ind;
|
|
request_id_g <= service_info_g.request_id;
|
|
accepted_g <= g_accept;
|
|
stamp_g <= std_logic_vector(to_unsigned(g_stamp));
|
|
request_id_c <= service_info_c.request_id;
|
|
cancel_return_code_c <= cancel_ret_code;
|
|
goals_canceling_len_c <= std_logic_vector(to_unsigned(goals_canceling_cnt,goals_canceling_len_c'length));
|
|
status_list_len_s <= std_logic_vector(to_unsigned(status_list_cnt,status_list_len_s'length));
|
|
|
|
-- *Main State Machine*
|
|
-- STATE DESCRIPTION
|
|
-- IDLE Idle state
|
|
-- WAIT_FOR_DATA Wait for result service request
|
|
-- SEARCH_ID Search for goal with result request goal id
|
|
-- CHECK_STATE Check if found goal is in terminal state
|
|
-- STORE_RRQ Store result request in memory
|
|
-- SEND_RESPONSE Send result service response
|
|
-- WAIT_FOR_RET Wait for result service response
|
|
-- TRANSITION_STATE Update goal state
|
|
-- GET_DATA Get goal data required for result response
|
|
-- CHECK_REQUESTS Search if updated goal is in stored result requests
|
|
-- GET_REQUEST_ID Get data from stored result request
|
|
-- REMOVE_REQUEST Remove stored result request
|
|
-- WAIT_FOR_MEM Wait for goal data from memory
|
|
-- RETURN_USER User return
|
|
-- CHECK_TIMEOUT Check and remove expired goals
|
|
-- REMOVE_OLDEST Remove oldest goal in terminal state
|
|
-- PUBLISH_FEEDBACK Publish feedback
|
|
-- RESET_MEMORY Reset result request memory to empty state
|
|
main_prc : process(all)
|
|
begin
|
|
-- DEFAULT
|
|
stage_next <= stage;
|
|
cnt_next <= cnt;
|
|
mem_data_r_next <= mem_data_r;
|
|
terminal_cnt_next <= terminal_cnt;
|
|
return_code_latch_next <= return_code_latch;
|
|
trigger_result_next <= trigger_result;
|
|
rrq_addr_base_next <= rrq_addr_base;
|
|
rrq_addr_latch_next <= rrq_addr_latch;
|
|
rrq_empty_head_next <= rrq_empty_head;
|
|
rrq_occupied_head_next <= rrq_occupied_head;
|
|
request_id_latch_next <= request_id_latch;
|
|
time_latch_next <= time_latch;
|
|
check_time_next <= check_time;
|
|
goal_handle_latch_next <= goal_handle_latch;
|
|
goal_state_latch_next <= goal_state_latch;
|
|
-- DEFAULT Unregistered
|
|
ack <= '0';
|
|
done <= '0';
|
|
start_fb <= '0';
|
|
rrq_abort_read <= '0';
|
|
result_sel <= '0';
|
|
atomic_op_r <= '0';
|
|
trigger_status_r <= '0';
|
|
mem_start_r <= '0';
|
|
mem_opcode_r <= NOP;
|
|
start_r <= '0';
|
|
opcode_r <= NOP;
|
|
opcode_fb <= NOP;
|
|
mem_r <= ZERO_GOAL_DATA;
|
|
return_code <= ROS_RET_OK;
|
|
goal_handle_out <= GOAL_HANDLE_UNKNOWN;
|
|
|
|
|
|
case (stage) is
|
|
when IDLE =>
|
|
if (start = '1') then
|
|
case (opcode) is
|
|
when GET_GOAL =>
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET;
|
|
mem_r.field_flags <= GMF_GOAL_ID_FLAG or GMF_STAMP_FLAG or GMF_RESULT_INDEX_FLAG or GMF_STATE_FLAG;
|
|
mem_r.addr <= unsigned(goal_handle_in);
|
|
|
|
if (mem_ack_r = '1') then
|
|
ack <= '1';
|
|
stage_next <= WAIT_FOR_MEM;
|
|
return_code_latch_next <= ROS_RET_OK;
|
|
end if;
|
|
when GET_LAST_GOAL =>
|
|
-- No Goals Available
|
|
if (mem_occupied_head = GOAL_MEMORY_MAX_ADDRESS) then
|
|
mem_data_r_next.addr <= GOAL_MEMORY_MAX_ADDRESS;
|
|
ack <= '1';
|
|
return_code_latch_next <= ROS_RET_OK;
|
|
stage_next <= RETURN_USER;
|
|
else
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET;
|
|
mem_r.field_flags <= GMF_GOAL_ID_FLAG or GMF_STAMP_FLAG or GMF_RESULT_INDEX_FLAG or GMF_STATE_FLAG;
|
|
mem_r.addr <= mem_occupied_head;
|
|
|
|
if (mem_ack_r = '1') then
|
|
ack <= '1';
|
|
stage_next <= WAIT_FOR_MEM;
|
|
return_code_latch_next <= ROS_RET_OK;
|
|
end if;
|
|
end if;
|
|
when GET_PREVIOUS_GOAL =>
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET_NEXT;
|
|
mem_r.field_flags <= GMF_GOAL_ID_FLAG or GMF_STAMP_FLAG or GMF_RESULT_INDEX_FLAG or GMF_STATE_FLAG;
|
|
mem_r.addr <= unsigned(goal_handle_in);
|
|
|
|
if (mem_ack_r = '1') then
|
|
ack <= '1';
|
|
stage_next <= WAIT_FOR_MEM;
|
|
return_code_latch_next <= ROS_RET_OK;
|
|
end if;
|
|
when UPDATE_GOAL_STATE =>
|
|
-- Atomic Operation Guard
|
|
if (atomic_op_c = '1' and unsigned(goal_handle_in) = mem_data_c.addr) then
|
|
-- NOTE: In order to prevent a user side Deadlock, we return with INVALID_ARGUMENT if the cancel FSM is also waiting for a user input in the atomic operation zone.
|
|
if (cancel_stage = WAIT_FOR_USER) then
|
|
ack <= '1';
|
|
stage_next <= RETURN_USER;
|
|
return_code_latch_next <= ROS_RET_INVALID_ARGUMENT;
|
|
end if;
|
|
else
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET;
|
|
mem_r.field_flags <= GMF_STATE_FLAG;
|
|
mem_r.addr <= unsigned(goal_handle_in);
|
|
|
|
if (mem_ack_r = '1') then
|
|
-- Latch Input Data
|
|
goal_handle_latch_next <= goal_handle_in;
|
|
goal_state_latch_next <= goal_state_in;
|
|
|
|
ack <= '1';
|
|
stage_next <= TRANSITION_STATE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when PUBLISH_FEEDBACK =>
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET_NEXT;
|
|
mem_r.field_flags <= GMF_GOAL_ID_FLAG;
|
|
mem_r.addr <= unsigned(goal_handle_in);
|
|
|
|
if (mem_ack_r = '1') then
|
|
ack <= '1';
|
|
stage_next <= PUBLISH_FEEDBACK;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
elsif (data_available_r = '1' and rrq_empty_head /= RRQ_MEMORY_MAX_ADDRESS) then
|
|
start_r <= '1';
|
|
opcode_r <= TAKE_REQUEST;
|
|
|
|
if (ack_r = '1') then
|
|
stage_next <= WAIT_FOR_DATA;
|
|
end if;
|
|
elsif (TIMEOUT_DURATION /= ROS_TIME_INFINITE and time >= check_time) then
|
|
assert (mem_occupied_head /= GOAL_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
|
|
-- Reset
|
|
check_time_next <= ROS_TIME_INFINITE;
|
|
|
|
mem_data_r_next.addr <= mem_occupied_head;
|
|
stage_next <= CHECK_TIMEOUT;
|
|
cnt_next <= 0;
|
|
elsif (TIMEOUT_DURATION = ROS_TIME_INFINITE and mem_empty_head = GOAL_MEMORY_MAX_ADDRESS and terminal_cnt /= 0) then
|
|
assert (mem_occupied_tail /= GOAL_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
|
|
mem_data_r_next.addr <= mem_occupied_tail;
|
|
stage_next <= REMOVE_OLDEST;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when WAIT_FOR_DATA =>
|
|
if (done_r = '1') then
|
|
case (return_code_r) is
|
|
when ROS_RET_OK =>
|
|
if (taken_r = '1') then
|
|
-- Latch Request ID
|
|
request_id_latch_next <= service_info_r.request_id;
|
|
|
|
-- No Goals Available
|
|
if (mem_occupied_head = GOAL_MEMORY_MAX_ADDRESS) then
|
|
mem_data_r_next.res_ind <= std_logic_vector(to_unsigned(MAX_GOALS, WORD_WIDTH));
|
|
mem_data_r_next.state <= GoalStatus_package.STATUS_UNKNOWN;
|
|
stage_next <= SEND_RESPONSE;
|
|
else
|
|
stage_next <= SEARCH_ID;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
-- TODO: Propagate Error?
|
|
stage_next <= IDLE;
|
|
end case;
|
|
end if;
|
|
when SEARCH_ID =>
|
|
case (cnt) is
|
|
-- GET FIRST
|
|
when 0 =>
|
|
assert (mem_occupied_head /= GOAL_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET;
|
|
mem_r.field_flags <= GMF_GOAL_ID_FLAG;
|
|
mem_r.addr <= mem_occupied_head;
|
|
|
|
if (mem_ack_r = '1') then
|
|
cnt_next <= cnt + 2;
|
|
end if;
|
|
-- GET NEXT
|
|
when 1 =>
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET_NEXT;
|
|
mem_r.field_flags <= GMF_GOAL_ID_FLAG;
|
|
mem_r.addr <= mem_data_r.addr;
|
|
|
|
if (mem_ack_r = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- CHECK
|
|
when 2 =>
|
|
-- Wait for Memory
|
|
if (mem_done = '1') then
|
|
assert check_mask(mem_data.field_flags, GMF_GOAL_ID_FLAG) severity FAILURE;
|
|
|
|
-- No more Goals
|
|
if (mem_data.addr = GOAL_MEMORY_MAX_ADDRESS) then
|
|
-- Goal not found
|
|
mem_data_r_next.res_ind <= std_logic_vector(to_unsigned(MAX_GOALS, WORD_WIDTH));
|
|
mem_data_r_next.state <= GoalStatus_package.STATUS_UNKNOWN;
|
|
stage_next <= SEND_RESPONSE;
|
|
else
|
|
mem_data_r_next <= mem_data;
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- CHECK GOAL_ID 1/4
|
|
when 3 =>
|
|
if (mem_data_r.goal_id(0) = to_GUID(goal_id_r)(0)) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= 1; -- GET_NEXT
|
|
end if;
|
|
-- CHECK GOAL_ID 2/4
|
|
when 4 =>
|
|
if (mem_data_r.goal_id(1) = to_GUID(goal_id_r)(1)) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= 1; -- GET_NEXT
|
|
end if;
|
|
-- CHECK GOAL_ID 3/4
|
|
when 5 =>
|
|
if (mem_data_r.goal_id(2) = to_GUID(goal_id_r)(2)) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= 1; -- GET_NEXT
|
|
end if;
|
|
-- CHECK GOAL_ID 4/4
|
|
when 6 =>
|
|
if (mem_data_r.goal_id(3) = to_GUID(goal_id_r)(3)) then
|
|
-- Found Goal
|
|
stage_next <= CHECK_STATE;
|
|
cnt_next <= 0;
|
|
else
|
|
cnt_next <= 1; -- GET_NEXT
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when CHECK_STATE =>
|
|
case (cnt) is
|
|
-- GET STATE
|
|
when 0 =>
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET;
|
|
mem_r.field_flags <= GMF_STATE_FLAG or GMF_RESULT_INDEX_FLAG;
|
|
mem_r.addr <= mem_data_r.addr;
|
|
|
|
if (mem_ack_r = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Check State
|
|
when 1 =>
|
|
-- Wait for Memory
|
|
if (mem_done = '1') then
|
|
assert (mem_data.addr = GOAL_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
assert check_mask(mem_data.field_flags, GMF_STATE_FLAG or GMF_RESULT_INDEX_FLAG) severity FAILURE;
|
|
|
|
mem_data_r_next <= mem_data;
|
|
|
|
if (is_terminal(mem_data.state)) then
|
|
if (mem_data.state /= GoalStatus_package.STATUS_SUCCEEDED) then
|
|
-- NOTE: We are setting result index to MAX_GOALS to effectively "zero" the result.
|
|
-- This prevents sending the result of previous succeeded goals, if the current
|
|
-- goal is not succeeded.
|
|
mem_data_r_next.res_ind <= std_logic_vector(to_unsigned(MAX_GOALS, WORD_WIDTH));
|
|
end if;
|
|
stage_next <= SEND_RESPONSE;
|
|
else
|
|
stage_next <= STORE_RRQ;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when STORE_RRQ =>
|
|
assert (rrq_empty_head /= RRQ_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
|
|
case (cnt) is
|
|
-- GET Next Addr
|
|
when 0 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_empty_head + RMF_NEXT_ADDR_OFFSET;
|
|
rrq_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- SET Goal Handle
|
|
when 1 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_empty_head + RMF_GOAL_HANDLE_OFFSET;
|
|
rrq_write_data <= std_logic_vector(resize(mem_data_r.addr,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- SET Request ID 1/6
|
|
when 2 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_empty_head + RMF_REQUEST_ID_OFFSET;
|
|
rrq_write_data <= service_info_c.request_id.writer_guid(0);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- SET Request ID 2/6
|
|
when 3 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_empty_head + RMF_REQUEST_ID_OFFSET + 1;
|
|
rrq_write_data <= service_info_c.request_id.writer_guid(1);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- SET Request ID 3/6
|
|
when 4 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_empty_head + RMF_REQUEST_ID_OFFSET + 2;
|
|
rrq_write_data <= service_info_c.request_id.writer_guid(2);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- SET Request ID 4/6
|
|
when 5 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_empty_head + RMF_REQUEST_ID_OFFSET + 3;
|
|
rrq_write_data <= service_info_c.request_id.writer_guid(3);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- SET Request ID 5/6
|
|
when 6 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_empty_head + RMF_REQUEST_ID_OFFSET + 4;
|
|
rrq_write_data <= std_logic_vector(service_info_c.request_id.sequence_number(0));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- SET Request ID 6/6
|
|
when 7 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_empty_head + RMF_REQUEST_ID_OFFSET + 5;
|
|
rrq_write_data <= std_logic_vector(service_info_c.request_id.sequence_number(1));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
if (rrq_occupied_head = RRQ_MEMORY_MAX_ADDRESS) then
|
|
cnt_next <= cnt + 2;
|
|
else
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- SET Prev Addr (Old Occupied Head)
|
|
when 8 =>
|
|
assert (rrq_occupied_head /= RRQ_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_occupied_head + RMF_PREV_ADDR_OFFSET;
|
|
rrq_write_data <= std_logic_vector(resize(rrq_empty_head,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- SET Next Addr
|
|
when 9 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_empty_head + RMF_NEXT_ADDR_OFFSET;
|
|
rrq_write_data <= std_logic_vector(resize(rrq_occupied_head,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
-- Set New Occupied Head
|
|
rrq_occupied_head_next <= rrq_empty_head;
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- SET Prev Addr
|
|
when 10 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_empty_head + RMF_PREV_ADDR_OFFSET;
|
|
rrq_write_data <= std_logic_vector(resize(RRQ_MEMORY_MAX_ADDRESS,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Next Addr
|
|
when 11 =>
|
|
rrq_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_valid_out = '1') then
|
|
-- Set new Empty Head
|
|
rrq_empty_head_next <= resize(unsigned(rrq_read_data),RRQ_MEMORY_ADDR_WIDTH);
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when SEND_RESPONSE =>
|
|
assert check_mask(mem_data_r.field_flags, GMF_STATE_FLAG or GMF_RESULT_INDEX_FLAG) severity FAILURE;
|
|
result_sel <= '1';
|
|
|
|
if (result_sel_ack = '1') then
|
|
start_r <= '1';
|
|
opcode_r <= SEND_RESPONSE;
|
|
|
|
if (ack_r = '1') then
|
|
stage_next <= WAIT_FOR_RET;
|
|
end if;
|
|
end if;
|
|
when WAIT_FOR_RET =>
|
|
assert check_mask(mem_data_r.field_flags, GMF_STATE_FLAG or GMF_RESULT_INDEX_FLAG) severity FAILURE;
|
|
result_sel <= '1';
|
|
|
|
if (done_r = '1') then
|
|
-- TODO: Propagate Error?
|
|
stage_next <= IDLE;
|
|
|
|
if (trigger_result = '1') then
|
|
stage_next <= CHECK_REQUESTS;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when TRANSITION_STATE =>
|
|
assert (not (atomic_op_c = '1' and mem_data_r.addr = mem_data_c.addr)) severity FAILURE;
|
|
atomic_op_r <= '1';
|
|
|
|
case (cnt) is
|
|
-- CHECK Goal State
|
|
when 0 =>
|
|
-- Wait for Memory
|
|
if (mem_done = '1') then
|
|
assert check_mask(mem_data.field_flags, GMF_STATE_FLAG) severity FAILURE;
|
|
|
|
case (mem_data.state) is
|
|
when GoalStatus_package.STATUS_ACCEPTED =>
|
|
case (goal_state_latch) is
|
|
when GoalStatus_package.STATUS_EXECUTING =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_TIME_INFINITE and is_terminal(goal_state_in)) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= cnt + 3;
|
|
end if;
|
|
when others =>
|
|
ack <= '1';
|
|
stage_next <= RETURN_USER;
|
|
return_code_latch_next <= ROS_RET_ACTION_GOAL_EVENT_INVALID;
|
|
end case;
|
|
when GoalStatus_package.STATUS_EXECUTING =>
|
|
case (goal_state_latch) is
|
|
when GoalStatus_package.STATUS_SUCCEEDED =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_TIME_INFINITE and is_terminal(goal_state_in)) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= cnt + 3;
|
|
end if;
|
|
when GoalStatus_package.STATUS_ABORTED =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_TIME_INFINITE and is_terminal(goal_state_in)) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= cnt + 3;
|
|
end if;
|
|
when others =>
|
|
ack <= '1';
|
|
stage_next <= RETURN_USER;
|
|
return_code_latch_next <= ROS_RET_ACTION_GOAL_EVENT_INVALID;
|
|
end case;
|
|
when GoalStatus_package.STATUS_CANCELING =>
|
|
case (goal_state_latch) is
|
|
when GoalStatus_package.STATUS_SUCCEEDED =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_TIME_INFINITE and is_terminal(goal_state_in)) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= cnt + 3;
|
|
end if;
|
|
when GoalStatus_package.STATUS_ABORTED =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_TIME_INFINITE and is_terminal(goal_state_in)) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= cnt + 3;
|
|
end if;
|
|
when GoalStatus_package.STATUS_CANCELED =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_TIME_INFINITE and is_terminal(goal_state_in)) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= cnt + 3;
|
|
end if;
|
|
when others =>
|
|
ack <= '1';
|
|
stage_next <= RETURN_USER;
|
|
return_code_latch_next <= ROS_RET_ACTION_GOAL_EVENT_INVALID;
|
|
end case;
|
|
when others =>
|
|
ack <= '1';
|
|
stage_next <= RETURN_USER;
|
|
return_code_latch_next <= ROS_RET_ACTION_GOAL_EVENT_INVALID;
|
|
end case;
|
|
end if;
|
|
-- Time Addition 1/2
|
|
when 1 =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_TIME_INFINITE) then
|
|
time_latch_next.sec <= std_logic_vector(unsigned(time.sec) + unsigned(TIMEOUT_DURATION.sec));
|
|
time_latch_next.nanosec <= std_logic_vector(unsigned(time.nanosec) + unsigned(TIMEOUT_DURATION.nanosec));
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Time Addition 2/2
|
|
when 2 =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_TIME_INFINITE) then
|
|
if (unsigned(time_latch.nanosec) >= to_unsigned(10**9,time_latch.nanosec'length)) then
|
|
time_latch_next.sec <= std_logic_vector(unsigned(time_latch.sec) + 1);
|
|
time_latch_next.nanosec <= std_logic_vector(unsigned(time_latch.nanosec) - to_unsigned(10**9,time_latch.nanosec'length));
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- UPDATE Goal State
|
|
when 3 =>
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= UPDATE;
|
|
mem_r.field_flags <= GMF_STATE_FLAG;
|
|
mem_r.addr <= unsigned(goal_handle_latch);
|
|
mem_r.state <= goal_state_latch;
|
|
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_TIME_INFINITE and is_terminal(goal_state_in)) then
|
|
mem_r.field_flags <= GMF_STATE_FLAG or GMF_DEADLINE_FLAG;
|
|
mem_r.deadline <= time_latch;
|
|
|
|
-- Update Checktime
|
|
if (time_latch < check_time) then
|
|
check_time_next <= time_latch;
|
|
end if;
|
|
end if;
|
|
|
|
if (mem_ack_r = '1') then
|
|
if (is_terminal(goal_state_in)) then
|
|
trigger_result_next <= '1';
|
|
-- Update Terminal Goal Counter
|
|
terminal_cnt_next <= terminal_cnt + 1;
|
|
end if;
|
|
ack <= '1';
|
|
stage_next <= RETURN_USER;
|
|
return_code_latch_next <= ROS_RET_OK;
|
|
-- Trigger Status Update
|
|
trigger_status_r <= '1';
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when GET_DATA =>
|
|
case (cnt) is
|
|
-- GET Data
|
|
when 0 =>
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET;
|
|
mem_r.field_flags <= GMF_STATE_FLAG or GMF_RESULT_INDEX_FLAG;
|
|
mem_r.addr <= mem_data_r.addr;
|
|
|
|
if (mem_ack_r = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Data
|
|
when 1 =>
|
|
-- Wait for Memory
|
|
if (mem_done = '1') then
|
|
assert (mem_data.addr = GOAL_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
assert check_mask(mem_data.field_flags, GMF_STATE_FLAG or GMF_RESULT_INDEX_FLAG) severity FAILURE;
|
|
assert is_terminal(mem_data.state) severity FAILURE;
|
|
|
|
mem_data_r_next <= mem_data;
|
|
|
|
if (mem_data.state /= GoalStatus_package.STATUS_SUCCEEDED) then
|
|
-- NOTE: We are setting result index to MAX_GOALS to effectively "zero" the result.
|
|
-- This prevents sending the result of previous succeeded goals, if the current
|
|
-- goal is not succeeded.
|
|
mem_data_r_next.res_ind <= std_logic_vector(to_unsigned(MAX_GOALS, WORD_WIDTH));
|
|
end if;
|
|
|
|
stage_next <= CHECK_REQUESTS;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when CHECK_REQUESTS =>
|
|
case (cnt) is
|
|
-- GET Goal Handle
|
|
when 0 =>
|
|
-- NOTE: We check the base here, because a REMOVE_REQUEST operation may reset the rrq_addr_base
|
|
if (rrq_addr_base = RRQ_MEMORY_MAX_ADDRESS) then
|
|
-- Reset
|
|
trigger_result_next <= '0';
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_GOAL_HANDLE_OFFSET;
|
|
rrq_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- GET Next Addr
|
|
when 1 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_NEXT_ADDR_OFFSET;
|
|
rrq_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Goal Handle
|
|
when 2 =>
|
|
rrq_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_valid_out = '1') then
|
|
|
|
-- Found Result Request of Updated Goal
|
|
if (resize(unsigned(rrq_read_data),GOAL_MEMORY_ADDR_WIDTH) = mem_data_r.addr) then
|
|
stage_next <= GET_REQUEST_ID;
|
|
cnt_next <= 0;
|
|
rrq_abort_read <= '1';
|
|
else
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- READ Next Addr
|
|
when 3 =>
|
|
rrq_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_valid_out = '1') then
|
|
rrq_addr_base_next <= resize(unsigned(rrq_read_data),GOAL_MEMORY_ADDR_WIDTH);
|
|
|
|
-- No More Stored Requests
|
|
if (resize(unsigned(rrq_read_data),GOAL_MEMORY_ADDR_WIDTH) = RRQ_MEMORY_MAX_ADDRESS) then
|
|
-- Reset
|
|
trigger_result_next <= '0';
|
|
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Next Request
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when GET_REQUEST_ID =>
|
|
case (cnt) is
|
|
-- GET Request ID 1/6
|
|
when 0 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_REQUEST_ID_OFFSET;
|
|
rrq_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- GET Request ID 2/6
|
|
when 1 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_REQUEST_ID_OFFSET + 1;
|
|
rrq_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- GET Request ID 3/6
|
|
when 2 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_REQUEST_ID_OFFSET + 2;
|
|
rrq_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- GET Request ID 4/6
|
|
when 3 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_REQUEST_ID_OFFSET + 3;
|
|
rrq_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- GET Request ID 5/6
|
|
when 4 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_REQUEST_ID_OFFSET + 4;
|
|
rrq_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- GET Request ID 6/6
|
|
when 5 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_REQUEST_ID_OFFSET + 5;
|
|
rrq_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Request ID 1/6
|
|
when 6 =>
|
|
rrq_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_valid_out = '1') then
|
|
request_id_latch_next.writer_guid(0) <= rrq_read_data;
|
|
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Request ID 2/6
|
|
when 7 =>
|
|
rrq_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_valid_out = '1') then
|
|
request_id_latch_next.writer_guid(1) <= rrq_read_data;
|
|
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Request ID 3/6
|
|
when 8 =>
|
|
rrq_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_valid_out = '1') then
|
|
request_id_latch_next.writer_guid(2) <= rrq_read_data;
|
|
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Request ID 4/6
|
|
when 9 =>
|
|
rrq_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_valid_out = '1') then
|
|
request_id_latch_next.writer_guid(3) <= rrq_read_data;
|
|
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Request ID 5/6
|
|
when 10 =>
|
|
rrq_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_valid_out = '1') then
|
|
request_id_latch_next.sequence_number(0) <= unsigned(rrq_read_data);
|
|
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Request ID 6/6
|
|
when 11 =>
|
|
rrq_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_valid_out = '1') then
|
|
request_id_latch_next.sequence_number(1) <= unsigned(rrq_read_data);
|
|
|
|
stage_next <= REMOVE_REQUEST;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when REMOVE_REQUEST =>
|
|
-- NOTE: After this stage the rrq_addr_base is set to the Next request
|
|
case (cnt) is
|
|
-- GET Next Addr
|
|
when 0 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_NEXT_ADDR_OFFSET;
|
|
rrq_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- GET Prev Addr
|
|
when 1 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_PREV_ADDR_OFFSET;
|
|
rrq_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- SET Next Addr
|
|
when 2 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_NEXT_ADDR_OFFSET;
|
|
rrq_write_data <= std_logic_vector(resize(rrq_empty_head,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
-- Set New Empty Head
|
|
rrq_empty_head_next <= rrq_addr_base;
|
|
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Next Addr
|
|
when 3 =>
|
|
rrq_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_valid_out = '1') then
|
|
rrq_addr_latch_next <= resize(unsigned(rrq_read_data),RRQ_MEMORY_ADDR_WIDTH);
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Previous Addr
|
|
when 4 =>
|
|
rrq_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_valid_out = '1') then
|
|
if (rrq_addr_latch = RRQ_MEMORY_MAX_ADDRESS) then
|
|
if (resize(unsigned(rrq_read_data),RRQ_MEMORY_ADDR_WIDTH) = RRQ_MEMORY_MAX_ADDRESS) then
|
|
-- Reset Occupied Head
|
|
rrq_occupied_head_next <= RRQ_MEMORY_MAX_ADDRESS;
|
|
|
|
rrq_addr_base_next <= RRQ_MEMORY_MAX_ADDRESS;
|
|
stage_next <= SEND_RESPONSE;
|
|
else
|
|
rrq_addr_base_next <= resize(unsigned(rrq_read_data),RRQ_MEMORY_ADDR_WIDTH);
|
|
cnt_next <= cnt + 2;
|
|
end if;
|
|
else
|
|
rrq_addr_base_next <= rrq_addr_latch;
|
|
rrq_addr_latch_next <= resize(unsigned(rrq_read_data),RRQ_MEMORY_ADDR_WIDTH);
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- SET Previous Addr (Next Slot)
|
|
when 6 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_PREV_ADDR_OFFSET;
|
|
rrq_write_data <= std_logic_vector(rrq_addr_latch);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
if (rrq_addr_latch = RRQ_MEMORY_MAX_ADDRESS) then
|
|
-- Set New Occupied Head
|
|
rrq_occupied_head_next <= rrq_addr_base;
|
|
|
|
stage_next <= SEND_RESPONSE;
|
|
else
|
|
rrq_addr_base_next <= rrq_addr_latch;
|
|
rrq_addr_latch_next <= rrq_addr_base;
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- SET Next Addr (Previous Slot)
|
|
when 7 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_NEXT_ADDR_OFFSET;
|
|
rrq_write_data <= std_logic_vector(rrq_addr_latch);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
|
|
rrq_addr_base_next <= rrq_addr_latch;
|
|
stage_next <= SEND_RESPONSE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when WAIT_FOR_MEM =>
|
|
-- Wait for Memory
|
|
if (mem_done = '1') then
|
|
assert check_mask(mem_data.field_flags, GMF_GOAL_ID_FLAG or GMF_STAMP_FLAG or GMF_RESULT_INDEX_FLAG or GMF_STATE_FLAG) severity FAILURE;
|
|
|
|
mem_data_r_next <= mem_data;
|
|
|
|
stage_next <= RETURN_USER;
|
|
end if;
|
|
when RETURN_USER =>
|
|
-- End of Memory
|
|
if (mem_data_r.addr = GOAL_MEMORY_MAX_ADDRESS) then
|
|
goal_handle_out <= GOAL_HANDLE_UNKNOWN;
|
|
else
|
|
goal_handle_out <= std_logic_vector(resize(mem_data_r.addr, GOAL_HANDLE_WIDTH));
|
|
end if;
|
|
|
|
done <= '1';
|
|
return_code <= return_code_latch;
|
|
|
|
if (trigger_result = '1') then
|
|
stage_next <= GET_DATA;
|
|
cnt_next <= 0;
|
|
else
|
|
stage_next <= IDLE;
|
|
end if;
|
|
when CHECK_TIMEOUT =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_TIME_INFINITE) then
|
|
case (cnt) is
|
|
-- GET
|
|
when 0 =>
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET;
|
|
mem_r.field_flags <= GMF_DEADLINE_FLAG;
|
|
mem_r.addr <= mem_data_r.addr;
|
|
|
|
if (mem_ack_r = '1') then
|
|
cnt_next <= cnt + 2;
|
|
end if;
|
|
-- GET NEXT
|
|
when 1 =>
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET_NEXT;
|
|
mem_r.field_flags <= GMF_DEADLINE_FLAG;
|
|
mem_r.addr <= mem_data_r.addr;
|
|
|
|
if (mem_ack_r = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- CHECK
|
|
when 2 =>
|
|
-- Wait for Memory
|
|
if (mem_done = '1') then
|
|
assert check_mask(mem_data.field_flags, GMF_DEADLINE_FLAG) severity FAILURE;
|
|
|
|
mem_data_r_next <= mem_data;
|
|
|
|
-- No more Goals
|
|
if (mem_data.addr = GOAL_MEMORY_MAX_ADDRESS) then
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Timeout
|
|
if (mem_data.deadline <= time) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
-- Update check Time
|
|
if (mem_data.deadline < check_time) then
|
|
check_time_next <= mem_data.deadline;
|
|
end if;
|
|
cnt_next <= 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
-- REMOVE
|
|
when 3 =>
|
|
-- TODO: This needs to take into account the other FSMs (Status, Cancel, Goal)
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= REMOVE;
|
|
mem_r.addr <= mem_data_r.addr;
|
|
|
|
if (mem_ack_r = '1') then
|
|
cnt_next <= cnt + 1;
|
|
-- Trigger Status Update
|
|
trigger_status_r <= '1';
|
|
-- Update Terminal Goal Counter
|
|
terminal_cnt_next <= terminal_cnt - 1;
|
|
end if;
|
|
-- Wait for Remove
|
|
when 4 =>
|
|
-- Wait for Memory
|
|
if (mem_done = '1') then
|
|
mem_data_r_next <= mem_data;
|
|
|
|
-- No more Goals
|
|
if (mem_data.addr = GOAL_MEMORY_MAX_ADDRESS) then
|
|
if (mem_occupied_head = GOAL_MEMORY_MAX_ADDRESS) then
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
mem_data_r.addr <= mem_occupied_head;
|
|
cnt_next <= 1;
|
|
end if;
|
|
else
|
|
cnt_next <= 1;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
when REMOVE_OLDEST =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION = ROS_TIME_INFINITE) then
|
|
case (cnt) is
|
|
-- GET
|
|
when 0 =>
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET;
|
|
mem_r.field_flags <= GMF_STATE_FLAG;
|
|
mem_r.addr <= mem_data_r.addr;
|
|
|
|
if (mem_ack_r = '1') then
|
|
cnt_next <= cnt + 2;
|
|
end if;
|
|
-- GET NEXT
|
|
when 1 =>
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= GET_PREV;
|
|
mem_r.field_flags <= GMF_STATE_FLAG;
|
|
mem_r.addr <= mem_data_r.addr;
|
|
|
|
if (mem_ack_r = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- CHECK
|
|
when 2 =>
|
|
-- Wait for Memory
|
|
if (mem_done = '1') then
|
|
assert check_mask(mem_data.field_flags, GMF_STATE_FLAG) severity FAILURE;
|
|
|
|
mem_data_r_next <= mem_data;
|
|
|
|
-- No more Goals
|
|
if (mem_data.addr = GOAL_MEMORY_MAX_ADDRESS) then
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
if (is_terminal(mem_data.state)) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
-- REMOVE
|
|
when 3 =>
|
|
mem_start_r <= '1';
|
|
mem_opcode_r <= REMOVE;
|
|
mem_r.addr <= mem_data_r.addr;
|
|
|
|
if (mem_ack_r = '1') then
|
|
cnt_next <= cnt + 1;
|
|
-- Trigger Status Update
|
|
trigger_status_r <= '1';
|
|
-- Update Terminal Goal Counter
|
|
terminal_cnt_next <= terminal_cnt - 1;
|
|
end if;
|
|
-- Wait for Remove
|
|
when 4 =>
|
|
-- Wait for Memory
|
|
if (mem_done = '1') then
|
|
mem_data_r_next <= mem_data;
|
|
|
|
-- No more Goals
|
|
if (mem_data.addr = GOAL_MEMORY_MAX_ADDRESS) then
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
-- NOTE: After Removal, mem_data.addr is set to the previous goal, so we need to call GET and not GET_PREV
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
when PUBLISH_FEEDBACK =>
|
|
case (cnt) is
|
|
-- Wait for Data
|
|
when 0 =>
|
|
if (mem_done = '1') then
|
|
assert check_mask(mem_data.field_flags, GMF_GOAL_ID_FLAG) severity FAILURE;
|
|
|
|
mem_data_r_next <= mem_data_r;
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Start Publish
|
|
when 1 =>
|
|
start_fb <= '1';
|
|
opcode_fb <= PUBLISH;
|
|
|
|
if (ack_fb = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Wait for Publish
|
|
when 2 =>
|
|
-- Passthrough
|
|
done <= done_fb;
|
|
return_code <= return_code_fb;
|
|
|
|
if (done_fb = '1') then
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when RESET_MEMORY =>
|
|
case (cnt) is
|
|
-- SET Next Pointer
|
|
when 0 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_NEXT_ADDR_OFFSET;
|
|
if (rrq_addr_base = MAX_RRQ_ADDRESS) then
|
|
rrq_write_data <= std_logic_vector(resize(RRQ_MEMORY_MAX_ADDRESS,WORD_WIDTH));
|
|
else
|
|
rrq_write_data <= std_logic_vector(resize(rrq_addr_base + RRQ_FRAME_SIZE,WORD_WIDTH));
|
|
end if;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- SET Previous Pointer
|
|
when 1 =>
|
|
rrq_valid_in <= '1';
|
|
rrq_addr <= rrq_addr_base + RMF_PREV_ADDR_OFFSET;
|
|
rrq_write_data <= std_logic_vector(resize(rrq_addr_latch,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (rrq_ready_in = '1') then
|
|
if (rrq_addr_base = MAX_RRQ_ADDRESS) then
|
|
-- Initialize Empty and Occupied Heads
|
|
rrq_empty_head <= FIRST_RRQ_ADDRESS;
|
|
rrq_occupied_head <= RRQ_MEMORY_MAX_ADDRESS;
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
rrq_addr_latch_next <= rrq_addr_base;
|
|
rrq_addr_base_next <= rrq_addr_base + RRQ_FRAME_SIZE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end case;
|
|
end process;
|
|
|
|
-- *Goal State Machine*
|
|
-- STATE DESCRIPTION
|
|
-- IDLE Idle state
|
|
-- WAIT_FOR_DATA Wait goal service request
|
|
-- WAIT_FOR_USER Wait for user input
|
|
-- ADD_GOAL Add goal to memory
|
|
-- SEND_RESPONSE Send goal service response
|
|
-- WAIT_FOR_RET Wait for goal service response
|
|
goal_prc : process(all)
|
|
begin
|
|
-- DEFAULT
|
|
goal_stage_next <= goal_stage;
|
|
g_stamp_next <= g_stamp;
|
|
g_accept_next <= g_accept;
|
|
-- DEFAULT Unregistered
|
|
trigger_status_g <= '0';
|
|
mem_start_g <= '0';
|
|
mem_opcode_g <= NOP;
|
|
start_g <= '0';
|
|
opcode_g <= NOP;
|
|
new_goal_request <= '0';
|
|
new_goal_handle <= GOAL_HANDLE_UNKNOWN;
|
|
new_goal_result_index <= (others => '0');
|
|
|
|
case (goal_stage) is
|
|
when IDLE =>
|
|
if (data_available_g = '1' and mem_empty_head /= GOAL_MEMORY_MAX_ADDRESS) then
|
|
start_g <= '1';
|
|
opcode_g <= TAKE_REQUEST;
|
|
if (ack_g = '1') then
|
|
goal_stage_next <= WAIT_FOR_DATA;
|
|
end if;
|
|
end if;
|
|
when WAIT_FOR_DATA =>
|
|
if (done_g = '1') then
|
|
case (return_code_g) is
|
|
when ROS_RET_OK =>
|
|
if (taken_g = '1') then
|
|
goal_stage_next <= WAIT_FOR_USER;
|
|
else
|
|
goal_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
-- TODO: Propagate Error?
|
|
goal_stage_next <= IDLE;
|
|
end case;
|
|
end if;
|
|
when WAIT_FOR_USER =>
|
|
new_goal_request <= '1';
|
|
new_goal_handle <= std_logic_vector(resize(mem_empty_head,GOAL_HANDLE_WIDTH));
|
|
new_goal_result_index <= std_logic_vector(empty_head_res_ind);
|
|
if (new_goal_response = '1') then
|
|
g_stamp_next <= time;
|
|
if (new_goal_accepted = '1') then
|
|
goal_stage_next <= ADD_GOAL;
|
|
g_accept_next <= '1';
|
|
else
|
|
goal_stage_next <= SEND_RESPONSE;
|
|
g_accept_next <= '0';
|
|
end if;
|
|
end if;
|
|
when ADD_GOAL =>
|
|
assert (mem_empty_head /= GOAL_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
|
|
mem_start_g <= '1';
|
|
mem_opcode_g <= INSERT;
|
|
|
|
if (mem_ack_g = '1') then
|
|
goal_stage_next <= SEND_RESPONSE;
|
|
-- Trigger Status Update
|
|
trigger_status_g <= '1';
|
|
end if;
|
|
when SEND_RESPONSE =>
|
|
start_g <= '1';
|
|
opcode_g <= SEND_RESPONSE;
|
|
if (ack_g = '1') then
|
|
goal_stage_next <= WAIT_FOR_RET;
|
|
end if;
|
|
when WAIT_FOR_RET =>
|
|
if (done_g = '1') then
|
|
-- TODO: Propagate Error?
|
|
goal_stage_next <= IDLE;
|
|
end if;
|
|
end case;
|
|
end process;
|
|
|
|
-- *Cancel State Machine*
|
|
-- STATE DESCRIPTION
|
|
-- IDLE Idle state
|
|
-- WAIT_FOR_DATA Wait for cancel service request
|
|
-- GET Get goal data from memory (Pointed by mem_data_c.addr)
|
|
-- GET_NEXT Get goal data from memory (Next goal from one pointed by mem_data_c.addr)
|
|
-- CHECK Determine what data has to be checked for each stored goal
|
|
-- CHECK_GOAL_ID Check if cancel goal id is same as mem_data_c
|
|
-- CHECK_STAMP Check if cancel goal stamp is earlier than the one in mem_data_c
|
|
-- CHECK_STATE Check if mem_data_c is in terminal state
|
|
-- WAIT_FOR_USER Wait for user input
|
|
-- CANCEL_GOAL Update goal state to CANCELING
|
|
-- ADD_CANCEL Store canceling goal for later response
|
|
-- SEND_RESPONSE Send cancel service response
|
|
-- WAIT_FOR_RET Wait for cancel service response
|
|
cancel_prc : process(all)
|
|
begin
|
|
-- DEFAULT
|
|
cancel_stage_next <= cancel_stage;
|
|
c_cnt_next <= c_cnt;
|
|
mem_data_c_next <= mem_data_c;
|
|
search_type_c_next <= search_type_c;
|
|
goals_canceling_cnt_next <= goals_canceling_cnt;
|
|
cancel_ret_code_next <= cancel_ret_code;
|
|
-- DEFAULT Unregistered
|
|
atomic_op_c <= '0';
|
|
trigger_status_c <= '0';
|
|
mem_start_c <= '0';
|
|
mem_opcode_c <= NOP;
|
|
start_c <= '0';
|
|
opcode_c <= NOP;
|
|
mem_c <= ZERO_GOAL_DATA;
|
|
cancel_request <= '0';
|
|
cancel_request_handle <= GOAL_HANDLE_UNKNOWN;
|
|
goals_canceling_addr_c <= (others => '0');
|
|
goals_canceling_ren_c <= '0';
|
|
goals_canceling_wen_c <= '0';
|
|
goals_canceling_ack_c <= '0';
|
|
goals_canceling_goal_id_w_c <= (others => '0');
|
|
goals_canceling_stamp_w_c <= (others => '0');
|
|
|
|
case (cancel_stage) is
|
|
when IDLE =>
|
|
if (data_available_c = '1') then
|
|
start_c <= '1';
|
|
opcode_c <= TAKE_REQUEST;
|
|
if (ack_c = '1') then
|
|
cancel_stage_next <= WAIT_FOR_DATA;
|
|
|
|
--Reset
|
|
goals_canceling_cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when WAIT_FOR_DATA =>
|
|
if (done_c = '1') then
|
|
case (return_code_c) is
|
|
when ROS_RET_OK =>
|
|
if (taken_c = '1') then
|
|
-- No Goals Available
|
|
if (mem_occupied_head = GOAL_MEMORY_MAX_ADDRESS) then
|
|
cancel_ret_code_next <= CancelGoal_package.RR_ERROR_REJECTED;
|
|
cancel_stage_next <= SEND_RESPONSE;
|
|
else
|
|
if (to_UUID(goal_info_goal_id_c) = UUID_UNKNOWN) then
|
|
if (to_ROS_TIME(goal_info_stamp_c) = ROS_TIME_ZERO) then
|
|
search_type_c_next <= SEARCH_NONE;
|
|
else
|
|
search_type_c_next <= SEARCH_STAMP;
|
|
end if;
|
|
else
|
|
search_type_c_next <= SEARCH_GOAL_ID;
|
|
end if;
|
|
cancel_stage_next <= GET;
|
|
mem_data_c_next.addr <= mem_occupied_head;
|
|
end if;
|
|
else
|
|
cancel_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
-- TODO: Propagate Error?
|
|
cancel_stage_next <= IDLE;
|
|
end case;
|
|
end if;
|
|
when GET =>
|
|
-- Atomic Operation Guard
|
|
if (not (atomic_op_r = '1' and mem_data_c.addr = mem_data_r.addr)) then
|
|
mem_start_c <= '1';
|
|
mem_opcode_c <= GET;
|
|
mem_c.field_flags <= GMF_GOAL_ID_FLAG or GMF_STAMP_FLAG or GMF_STATE_FLAG;
|
|
mem_c.addr <= mem_data_c.addr;
|
|
|
|
if (mem_ack_c = '1') then
|
|
cancel_stage_next <= CHECK;
|
|
end if;
|
|
end if;
|
|
when GET_NEXT =>
|
|
mem_start_c <= '1';
|
|
mem_opcode_c <= GET_NEXT;
|
|
mem_c.field_flags <= GMF_GOAL_ID_FLAG or GMF_STAMP_FLAG or GMF_STATE_FLAG;
|
|
mem_c.addr <= mem_data_c.addr;
|
|
|
|
if (mem_ack_c = '1') then
|
|
cancel_stage_next <= CHECK;
|
|
end if;
|
|
when CHECK =>
|
|
atomic_op_c <= '1';
|
|
-- Wait for Memory
|
|
if (mem_done = '1') then
|
|
-- End of Memory
|
|
if (mem_data.addr = GOAL_MEMORY_MAX_ADDRESS) then
|
|
case (search_type_c) is
|
|
when SEARCH_GOAL_ID =>
|
|
cancel_ret_code_next <= CancelGoal_package.RR_ERROR_UNKNOWN_GOAL_ID;
|
|
cancel_stage_next <= SEND_RESPONSE;
|
|
when others =>
|
|
-- No Goals Canceled
|
|
if (goals_canceling_cnt = 0) then
|
|
cancel_ret_code_next <= CancelGoal_package.RR_ERROR_REJECTED;
|
|
cancel_stage_next <= SEND_RESPONSE;
|
|
else
|
|
cancel_ret_code_next <= CancelGoal_package.RR_ERROR_NONE;
|
|
cancel_stage_next <= SEND_RESPONSE;
|
|
end if;
|
|
end case;
|
|
else
|
|
assert check_mask(mem_data.field_flags, GMF_GOAL_ID_FLAG or GMF_STAMP_FLAG or GMF_STATE_FLAG) severity FAILURE;
|
|
|
|
mem_data_c_next <= mem_data;
|
|
|
|
-- NOTE: If both the Main and Cancel FSM enter the atomic operation zone at the same time, the cancel FSM gives way and waits.
|
|
if (atomic_op_r = '1' and mem_data.addr = mem_data_r.addr) then
|
|
cancel_stage_next <= GET;
|
|
else
|
|
case (search_type_c) is
|
|
when SEARCH_GOAL_ID =>
|
|
cancel_stage_next <= CHECK_GOAL_ID;
|
|
c_cnt_next <= 0;
|
|
when SEARCH_STAMP =>
|
|
cancel_stage_next <= CHECK_STAMP;
|
|
when SEARCH_NONE =>
|
|
cancel_stage_next <= CHECK_STATE;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
when CHECK_GOAL_ID =>
|
|
assert (not (atomic_op_r = '1' and mem_data_c.addr = mem_data_r.addr)) severity FAILURE;
|
|
atomic_op_c <= '1';
|
|
|
|
case (c_cnt) is
|
|
-- GOAL_ID 1/4
|
|
when 0 =>
|
|
if (mem_data_c.goal_id(0) = to_guid(goal_info_goal_id_c)(0)) then
|
|
c_cnt_next <= c_cnt + 1;
|
|
else
|
|
cancel_stage_next <= GET_NEXT;
|
|
end if;
|
|
-- GOAL_ID 2/4
|
|
when 1 =>
|
|
if (mem_data_c.goal_id(1) = to_guid(goal_info_goal_id_c)(1)) then
|
|
c_cnt_next <= c_cnt + 1;
|
|
else
|
|
cancel_stage_next <= GET_NEXT;
|
|
end if;
|
|
-- GOAL_ID 3/4
|
|
when 2 =>
|
|
if (mem_data_c.goal_id(2) = to_guid(goal_info_goal_id_c)(2)) then
|
|
c_cnt_next <= c_cnt + 1;
|
|
else
|
|
cancel_stage_next <= GET_NEXT;
|
|
end if;
|
|
-- GOAL_ID 4/4
|
|
when 3 =>
|
|
if (mem_data_c.goal_id(3) = to_guid(goal_info_goal_id_c)(3)) then
|
|
cancel_stage_next <= CHECK_STATE;
|
|
c_cnt_next <= 0;
|
|
else
|
|
cancel_stage_next <= GET_NEXT;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when CHECK_STAMP =>
|
|
assert (not (atomic_op_r = '1' and mem_data_c.addr = mem_data_r.addr)) severity FAILURE;
|
|
atomic_op_c <= '1';
|
|
|
|
if (mem_data_c.stamp < to_ROS_TIME(goal_info_stamp_c)) then
|
|
cancel_stage_next <= CHECK_STATE;
|
|
else
|
|
cancel_stage_next <= GET_NEXT;
|
|
end if;
|
|
when CHECK_STATE =>
|
|
assert (not (atomic_op_r = '1' and mem_data_c.addr = mem_data_r.addr)) severity FAILURE;
|
|
atomic_op_c <= '1';
|
|
|
|
if (is_terminal(mem_data_c.state)) then
|
|
cancel_ret_code_next <= CancelGoal_package.RR_ERROR_GOAL_TERMINATED;
|
|
cancel_stage_next <= SEND_RESPONSE;
|
|
elsif (mem_data_c.state = GoalStatus_package.STATUS_CANCELING) then
|
|
-- Skip State Change
|
|
cancel_stage_next <= ADD_CANCEL;
|
|
else
|
|
cancel_stage_next <= WAIT_FOR_USER;
|
|
end if;
|
|
when WAIT_FOR_USER =>
|
|
assert (not (atomic_op_r = '1' and mem_data_c.addr = mem_data_r.addr)) severity FAILURE;
|
|
atomic_op_c <= '1';
|
|
|
|
cancel_request <= '1';
|
|
cancel_request_handle <= std_logic_vector(mem_data_c.addr);
|
|
if (cancel_response = '1') then
|
|
if (cancel_accepted = '1') then
|
|
cancel_stage_next <= CANCEL_GOAL;
|
|
else
|
|
case (search_type_c) is
|
|
when SEARCH_GOAL_ID =>
|
|
if (to_ROS_TIME(goal_info_stamp_c) = ROS_TIME_ZERO) then
|
|
-- No Goals Canceled
|
|
cancel_ret_code_next <= CancelGoal_package.RR_ERROR_REJECTED;
|
|
cancel_stage_next <= SEND_RESPONSE;
|
|
else
|
|
-- Search for Timestamps
|
|
search_type_c_next <= SEARCH_STAMP;
|
|
cancel_stage_next <= GET;
|
|
mem_data_c_next.addr <= mem_occupied_head;
|
|
end if;
|
|
when SEARCH_STAMP =>
|
|
-- NOTE: Since the goals are added chronologically, we don't have to check the timestamps from now on
|
|
search_type_c_next <= SEARCH_NONE;
|
|
cancel_stage_next <= GET_NEXT;
|
|
when SEARCH_NONE =>
|
|
-- Continue
|
|
cancel_stage_next <= GET_NEXT;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
when CANCEL_GOAL =>
|
|
assert (not (atomic_op_r = '1' and mem_data_c.addr = mem_data_r.addr)) severity FAILURE;
|
|
atomic_op_c <= '1';
|
|
|
|
mem_start_c <= '1';
|
|
mem_opcode_c <= UPDATE;
|
|
mem_c.addr <= mem_data_c.addr;
|
|
mem_c.field_flags <= GMF_STATE_FLAG;
|
|
mem_c.state <= GoalStatus_package.STATUS_CANCELING;
|
|
|
|
if (mem_ack_c = '1') then
|
|
cancel_stage_next <= ADD_CANCEL;
|
|
-- Trigger Status Update
|
|
trigger_status_c <= '1';
|
|
end if;
|
|
when ADD_CANCEL =>
|
|
goals_canceling_addr_c <= std_logic_vector(to_unsigned(goals_canceling_cnt,CancelGoal_package.RR_GOALS_CANCELING_GOAL_ID_ADDR_WIDTH));
|
|
goals_canceling_wen_c <= '1';
|
|
goals_canceling_goal_id_w_c <= std_logic_vector(to_unsigned(mem_data_c.goal_id));
|
|
goals_canceling_stamp_w_c <= std_logic_vector(to_unsigned(mem_data_c.stamp));
|
|
if (goals_canceling_ready_c = '1') then
|
|
-- Reached maximum number of cancel goals
|
|
if (goals_canceling_cnt = CancelGoal_package.RR_GOALS_CANCELING_MAX_DEPTH) then
|
|
-- DONE
|
|
cancel_ret_code_next <= CancelGoal_package.RR_ERROR_NONE;
|
|
cancel_stage_next <= SEND_RESPONSE;
|
|
else
|
|
goals_canceling_cnt_next <= goals_canceling_cnt + 1;
|
|
|
|
case (search_type_c) is
|
|
when SEARCH_GOAL_ID =>
|
|
if (to_ROS_TIME(goal_info_stamp_c) = ROS_TIME_ZERO) then
|
|
-- DONE
|
|
cancel_ret_code_next <= CancelGoal_package.RR_ERROR_NONE;
|
|
cancel_stage_next <= SEND_RESPONSE;
|
|
else
|
|
assert (mem_occupied_head /= GOAL_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
|
|
-- Search for Timestamps
|
|
search_type_c_next <= SEARCH_STAMP;
|
|
cancel_stage_next <= GET;
|
|
mem_data_c_next.addr <= mem_occupied_head;
|
|
end if;
|
|
when SEARCH_STAMP =>
|
|
-- NOTE: Since the goals are added chronologically, we don't have to check the timestamps from now on
|
|
search_type_c_next <= SEARCH_NONE;
|
|
cancel_stage_next <= GET_NEXT;
|
|
when SEARCH_NONE =>
|
|
-- Continue
|
|
cancel_stage_next <= GET_NEXT;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
when SEND_RESPONSE =>
|
|
start_c <= '1';
|
|
opcode_c <= SEND_RESPONSE;
|
|
|
|
if (ack_c = '1') then
|
|
cancel_stage_next <= WAIT_FOR_RET;
|
|
end if;
|
|
when WAIT_FOR_RET =>
|
|
if (done_c = '1') then
|
|
-- TODO: Propagate Error?
|
|
cancel_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end process;
|
|
|
|
-- *Status State Machine*
|
|
-- STATE DESCRIPTION
|
|
-- IDLE Idle state
|
|
-- GET_FIRST Get first goal data from memory
|
|
-- GET_NEXT Get goal data from memory (Next goal from one pointed by mem_data_c.addr)
|
|
-- WAIT_FOR_DATA Wait for memory data
|
|
-- PUSH_STATUS Add goal data to status list
|
|
-- PUBLISH Publish status list
|
|
-- WAIT_FOR_PUBLISHER Wait for status list publisher
|
|
status_prc : process (all)
|
|
begin
|
|
-- DEFAULT
|
|
status_stage_next <= status_stage;
|
|
trigger_status_next <= trigger_status;
|
|
status_list_cnt_next <= status_list_cnt;
|
|
mem_data_s_next <= mem_data_s;
|
|
-- DEFAULT Unregistered
|
|
status_idle_sig <= '0';
|
|
start_s <= '0';
|
|
opcode_s <= NOP;
|
|
mem_start_s <= '0';
|
|
mem_opcode_s <= NOP;
|
|
mem_s <= ZERO_GOAL_DATA;
|
|
status_list_ren_s <= '0';
|
|
status_list_wen_s <= '0';
|
|
status_list_ack_s <= '0';
|
|
status_list_addr_s <= (others => '0');
|
|
status_list_goal_info_goal_id_w_s <= std_logic_vector(to_unsigned(UUID_UNKNOWN));
|
|
status_list_goal_info_stamp_w_s <= std_logic_vector(to_unsigned(ROS_TIME_INVALID));
|
|
status_list_status_w_s <= GoalStatus_package.STATUS_UNKNOWN;
|
|
|
|
-- Trigger Status Setter
|
|
if (trigger_status_c = '1' or trigger_status_g = '1' or trigger_status_r = '1') then
|
|
trigger_status_next <= '1';
|
|
end if;
|
|
|
|
case (status_stage) is
|
|
when IDLE =>
|
|
status_idle_sig <= '1';
|
|
if (trigger_status = '1') then
|
|
-- Trigger Status Resetter
|
|
trigger_status_next <= '0';
|
|
|
|
-- Reset
|
|
status_list_cnt_next <= 0;
|
|
|
|
if (mem_occupied_head = GOAL_MEMORY_MAX_ADDRESS) then
|
|
status_stage_next <= PUBLISH;
|
|
else
|
|
status_stage_next <= GET_FIRST;
|
|
end if;
|
|
end if;
|
|
when GET_FIRST =>
|
|
assert (mem_occupied_head /= GOAL_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
|
|
mem_start_s <= '1';
|
|
mem_opcode_s <= GET;
|
|
mem_s.addr <= mem_occupied_head;
|
|
mem_s.field_flags <= GMF_GOAL_ID_FLAG or GMF_STAMP_FLAG or GMF_STATE_FLAG;
|
|
|
|
if (mem_ack_s = '1') then
|
|
status_stage_next <= WAIT_FOR_DATA;
|
|
end if;
|
|
when GET_NEXT =>
|
|
mem_start_s <= '1';
|
|
mem_opcode_s <= GET_NEXT;
|
|
mem_s.addr <= mem_data_s.addr;
|
|
mem_s.field_flags <= GMF_GOAL_ID_FLAG or GMF_STAMP_FLAG or GMF_STATE_FLAG;
|
|
|
|
if (mem_ack_s = '1') then
|
|
status_stage_next <= WAIT_FOR_DATA;
|
|
end if;
|
|
when WAIT_FOR_DATA =>
|
|
-- Wait for DATA
|
|
if (mem_done = '1') then
|
|
mem_data_s_next <= mem_data_s;
|
|
|
|
-- No more Goals
|
|
if (mem_data.addr = GOAL_MEMORY_MAX_ADDRESS) then
|
|
status_stage_next <= PUBLISH;
|
|
else
|
|
status_stage_next <= PUSH_STATUS;
|
|
end if;
|
|
end if;
|
|
when PUSH_STATUS =>
|
|
status_list_addr_s <= std_logic_vector(to_unsigned(status_list_cnt,GoalStatusArray_package.STATUS_LIST_GOAL_INFO_GOAL_ID_ADDR_WIDTH));
|
|
status_list_wen_s <= '1';
|
|
status_list_goal_info_goal_id_w_s <= std_logic_vector(to_unsigned(mem_data_s.goal_id));
|
|
status_list_goal_info_stamp_w_s <= std_logic_vector(to_unsigned(mem_data_s.stamp));
|
|
status_list_status_w_s <= mem_data_s.state;
|
|
|
|
if (status_list_ready_s = '1') then
|
|
status_list_cnt_next <= status_list_cnt + 1;
|
|
|
|
if (status_list_cnt = GoalStatusArray_package.STATUS_LIST_MAX_DEPTH-1) then
|
|
status_stage_next <= PUBLISH;
|
|
else
|
|
status_stage_next <= GET_NEXT;
|
|
end if;
|
|
end if;
|
|
when PUBLISH =>
|
|
start_s <= '1';
|
|
opcode_s <= PUBLISH;
|
|
|
|
if (ack_s = '1') then
|
|
status_stage_next <= WAIT_FOR_PUBLISHER;
|
|
end if;
|
|
when WAIT_FOR_PUBLISHER =>
|
|
if (done_s = '1') then
|
|
-- TODO: Propagate Error?
|
|
status_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end process;
|
|
|
|
-- *Goal Memory State Machine*
|
|
-- STATE DESCRIPTION
|
|
-- IDLE Idle State. Done Signal is pulled high and Memory FSM accepts new memory operations
|
|
-- INSERT See Memory OPCODE Description
|
|
-- GET See Memory OPCODE Description
|
|
-- GET_NEXT See Memory OPCODE Description
|
|
-- GET_PREV See Memory OPCODE Description
|
|
-- UPDATE See Memory OPCODE Description
|
|
-- REMOVE See Memory OPCODE Description
|
|
-- RESET_MEMORY Reset goal memory to empty state
|
|
mem_ctrl_prc : process(all)
|
|
begin
|
|
-- DEFAULT
|
|
mem_stage_next <= mem_stage;
|
|
mem_cnt_next <= mem_cnt;
|
|
mem_occupied_head_next <= mem_occupied_head;
|
|
mem_occupied_tail_next <= mem_occupied_tail;
|
|
mem_empty_head_next <= mem_empty_head;
|
|
mem_empty_tail_next <= mem_empty_tail;
|
|
empty_head_res_ind_next <= empty_head_res_ind;
|
|
mem_latch_data_next <= mem_latch_data;
|
|
mem_data_next <= mem_data;
|
|
mem_addr_base_next <= mem_addr_base;
|
|
mem_addr_latch_next <= mem_addr_latch;
|
|
-- DEFAULT unregistered
|
|
mem_ack_g <= '0';
|
|
mem_ack_r <= '0';
|
|
mem_ack_c <= '0';
|
|
mem_ack_s <= '0';
|
|
mem_done <= '0';
|
|
mem_abort_read <= '0';
|
|
mem_ready_out <= '0';
|
|
mem_valid_in <= '0';
|
|
mem_read <= '0';
|
|
mem_done <= '0';
|
|
mem_addr <= (others => '0');
|
|
mem_write_data <= (others => '0');
|
|
|
|
|
|
case (mem_stage) is
|
|
-- NOTE: The REMOVE opcode sets mem_data.addr to the previous slot (or GOAL_MEMORY_MAX_ADDRESS if no previous goals)
|
|
-- This allows defined behaviours of GET_NEXT when removing goals.
|
|
when IDLE =>
|
|
mem_done <= '1';
|
|
if (mem_start_g = '1') then
|
|
mem_ack_g <= '1';
|
|
|
|
case (mem_opcode_g) is
|
|
when INSERT =>
|
|
assert (mem_empty_head /= GOAL_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
|
|
-- Latch DATA
|
|
mem_latch_data_next.goal_id <= to_guid(goal_id_g);
|
|
mem_latch_data_next.stamp <= g_stamp;
|
|
|
|
mem_addr_base_next <= mem_empty_head;
|
|
mem_stage_next <= INSERT;
|
|
mem_cnt_next <= 0;
|
|
when others =>
|
|
assert FALSE severity FAILURE;
|
|
end case;
|
|
elsif (mem_start_r = '1') then
|
|
mem_ack_r <= '1';
|
|
|
|
case (mem_opcode_r) is
|
|
when GET =>
|
|
-- Latch DATA
|
|
mem_latch_data_next <= mem_r;
|
|
|
|
if (mem_r.addr = mem_addr_base) then
|
|
mem_data_next.field_flags <= mem_data.field_flags or mem_r.field_flags;
|
|
else
|
|
mem_data_next <= ZERO_GOAL_DATA;
|
|
mem_data_next.field_flags <= mem_r.field_flags;
|
|
end if;
|
|
|
|
mem_addr_base_next <= mem_r.addr;
|
|
mem_stage_next <= GET;
|
|
|
|
if check_mask(mem_r.field_flags,GMF_STATE_FLAG) then
|
|
mem_cnt_next <= 0;
|
|
elsif check_mask(mem_r.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 1;
|
|
elsif check_mask(mem_r.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 5;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_r.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_r.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
-- DONE
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
when GET_NEXT =>
|
|
-- Latch DATA
|
|
mem_latch_data_next <= mem_r;
|
|
|
|
mem_data_next <= ZERO_GOAL_DATA;
|
|
mem_data_next.field_flags <= mem_r.field_flags;
|
|
|
|
mem_addr_base_next <= mem_r.addr;
|
|
mem_stage_next <= GET_NEXT;
|
|
mem_cnt_next <= 0;
|
|
when GET_PREV =>
|
|
-- Latch DATA
|
|
mem_latch_data_next <= mem_r;
|
|
|
|
mem_data_next <= ZERO_GOAL_DATA;
|
|
mem_data_next.field_flags <= mem_r.field_flags;
|
|
|
|
mem_addr_base_next <= mem_r.addr;
|
|
mem_stage_next <= GET_PREV;
|
|
mem_cnt_next <= 0;
|
|
when UPDATE =>
|
|
-- Latch DATA
|
|
mem_latch_data_next <= mem_r;
|
|
|
|
if (mem_r.addr = mem_addr_base) then
|
|
mem_data_next.field_flags <= mem_data.field_flags or mem_r.field_flags;
|
|
else
|
|
mem_data_next <= ZERO_GOAL_DATA;
|
|
mem_data_next.field_flags <= mem_r.field_flags;
|
|
end if;
|
|
|
|
mem_addr_base_next <= mem_r.addr;
|
|
mem_stage_next <= UPDATE;
|
|
|
|
if check_mask(mem_r.field_flags,GMF_STATE_FLAG) then
|
|
mem_cnt_next <= 0;
|
|
elsif check_mask(mem_r.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 1;
|
|
elsif check_mask(mem_r.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 5;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_r.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_r.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
-- DONE
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
when REMOVE =>
|
|
mem_addr_base_next <= mem_r.addr;
|
|
mem_stage_next <= REMOVE;
|
|
mem_cnt_next <= 0;
|
|
when others =>
|
|
assert FALSE severity FAILURE;
|
|
end case;
|
|
elsif (mem_start_c = '1') then
|
|
mem_ack_c <= '1';
|
|
|
|
case (mem_opcode_c) is
|
|
when GET =>
|
|
-- Latch DATA
|
|
mem_latch_data_next <= mem_c;
|
|
|
|
if (mem_c.addr = mem_addr_base) then
|
|
mem_data_next.field_flags <= mem_data.field_flags or mem_c.field_flags;
|
|
else
|
|
mem_data_next <= ZERO_GOAL_DATA;
|
|
mem_data_next.field_flags <= mem_c.field_flags;
|
|
end if;
|
|
|
|
mem_addr_base_next <= mem_c.addr;
|
|
mem_stage_next <= GET;
|
|
|
|
if check_mask(mem_c.field_flags,GMF_STATE_FLAG) then
|
|
mem_cnt_next <= 0;
|
|
elsif check_mask(mem_c.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 1;
|
|
elsif check_mask(mem_c.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 5;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_c.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_c.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
-- DONE
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
when GET_NEXT =>
|
|
-- Latch DATA
|
|
mem_latch_data_next <= mem_c;
|
|
|
|
mem_data_next <= ZERO_GOAL_DATA;
|
|
mem_data_next.field_flags <= mem_c.field_flags;
|
|
|
|
mem_addr_base_next <= mem_c.addr;
|
|
mem_stage_next <= GET_NEXT;
|
|
mem_cnt_next <= 0;
|
|
when GET_PREV =>
|
|
-- Latch DATA
|
|
mem_latch_data_next <= mem_c;
|
|
|
|
mem_data_next <= ZERO_GOAL_DATA;
|
|
mem_data_next.field_flags <= mem_c.field_flags;
|
|
|
|
mem_addr_base_next <= mem_c.addr;
|
|
mem_stage_next <= GET_PREV;
|
|
mem_cnt_next <= 0;
|
|
when UPDATE =>
|
|
-- Latch DATA
|
|
mem_latch_data_next <= mem_c;
|
|
|
|
if (mem_c.addr = mem_addr_base) then
|
|
mem_data_next.field_flags <= mem_data.field_flags or mem_c.field_flags;
|
|
else
|
|
mem_data_next <= ZERO_GOAL_DATA;
|
|
mem_data_next.field_flags <= mem_c.field_flags;
|
|
end if;
|
|
|
|
mem_addr_base_next <= mem_c.addr;
|
|
mem_stage_next <= UPDATE;
|
|
|
|
if check_mask(mem_c.field_flags,GMF_STATE_FLAG) then
|
|
mem_cnt_next <= 0;
|
|
elsif check_mask(mem_c.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 1;
|
|
elsif check_mask(mem_c.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 5;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_c.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_c.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
-- DONE
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
assert FALSE severity FAILURE;
|
|
end case;
|
|
elsif (mem_start_s = '1') then
|
|
mem_ack_s <= '1';
|
|
|
|
case (mem_opcode_s) is
|
|
when GET =>
|
|
-- Latch DATA
|
|
mem_latch_data_next <= mem_s;
|
|
|
|
if (mem_s.addr = mem_addr_base) then
|
|
mem_data_next.field_flags <= mem_data.field_flags or mem_s.field_flags;
|
|
else
|
|
mem_data_next <= ZERO_GOAL_DATA;
|
|
mem_data_next.field_flags <= mem_s.field_flags;
|
|
end if;
|
|
|
|
mem_addr_base_next <= mem_s.addr;
|
|
mem_stage_next <= GET;
|
|
|
|
if check_mask(mem_s.field_flags,GMF_STATE_FLAG) then
|
|
mem_cnt_next <= 0;
|
|
elsif check_mask(mem_s.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 1;
|
|
elsif check_mask(mem_s.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 5;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_s.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_s.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
-- DONE
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
when GET_NEXT =>
|
|
-- Latch DATA
|
|
mem_latch_data_next <= mem_s;
|
|
|
|
mem_data_next <= ZERO_GOAL_DATA;
|
|
mem_data_next.field_flags <= mem_s.field_flags;
|
|
|
|
mem_addr_base_next <= mem_s.addr;
|
|
mem_stage_next <= GET_NEXT;
|
|
mem_cnt_next <= 0;
|
|
when GET_PREV =>
|
|
-- Latch DATA
|
|
mem_latch_data_next <= mem_s;
|
|
|
|
mem_data_next <= ZERO_GOAL_DATA;
|
|
mem_data_next.field_flags <= mem_s.field_flags;
|
|
|
|
mem_addr_base_next <= mem_s.addr;
|
|
mem_stage_next <= GET_PREV;
|
|
mem_cnt_next <= 0;
|
|
when others =>
|
|
assert FALSE severity FAILURE;
|
|
end case;
|
|
end if;
|
|
when INSERT =>
|
|
case (mem_cnt) is
|
|
-- GET Next Addr
|
|
when 0 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_NEXT_ADDR_OFFSET;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- READ Next Addr
|
|
when 1 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
-- SET New Empty Head
|
|
mem_empty_head_next <= resize(unsigned(mem_read_data),GOAL_MEMORY_ADDR_WIDTH);
|
|
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- GET Result Index (New Empty Head)
|
|
when 2 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_empty_head + GMF_RESULT_INDEX_OFFSET;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- READ Result Index (New Empty Head)
|
|
when 3 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
empty_head_res_ind_next <= unsigned(mem_read_data);
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Goal State
|
|
when 4 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_STATE_OFFSET;
|
|
mem_write_data(CDR_INT8_WIDTH-1 downto 0) <= GoalStatus_package.STATUS_ACCEPTED;
|
|
mem_data_next.state <= GoalStatus_package.STATUS_ACCEPTED;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Goal ID 1/4
|
|
when 5 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_GOAL_ID_OFFSET;
|
|
mem_write_data <= mem_latch_data.goal_id(0);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Goal ID 2/4
|
|
when 6 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_GOAL_ID_OFFSET + 1;
|
|
mem_write_data <= mem_latch_data.goal_id(1);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Goal ID 3/4
|
|
when 7 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_GOAL_ID_OFFSET + 2;
|
|
mem_write_data <= mem_latch_data.goal_id(2);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Goal ID 4/4
|
|
when 8 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_GOAL_ID_OFFSET + 3;
|
|
mem_write_data <= mem_latch_data.goal_id(3);
|
|
mem_data_next.goal_id <= mem_latch_data.goal_id;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Stamp 1/2
|
|
when 9 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_STAMP_OFFSET;
|
|
mem_write_data <= mem_latch_data.stamp.sec;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Stamp 2/2
|
|
when 10 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_STAMP_OFFSET + 1;
|
|
mem_write_data <= mem_latch_data.stamp.nanosec;
|
|
mem_data_next.stamp <= mem_latch_data.stamp;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_DURATION_INFINITE) then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
else
|
|
mem_cnt_next <= mem_cnt + 3;
|
|
end if;
|
|
end if;
|
|
-- SET Deadline 1/2
|
|
when 11 =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_DURATION_INFINITE) then
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_DEADLINE_OFFSET;
|
|
mem_write_data <= ROS_TIME_INFINITE.sec;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- SET Deadline 2/2
|
|
when 12 =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_DURATION_INFINITE) then
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_DEADLINE_OFFSET + 1;
|
|
mem_write_data <= ROS_TIME_INFINITE.nanosec;
|
|
mem_data_next.deadline <= ROS_TIME_INFINITE;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- SET Prev Addr
|
|
when 13 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_PREV_ADDR_OFFSET;
|
|
mem_write_data <= std_logic_vector(resize(GOAL_MEMORY_MAX_ADDRESS,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Next Addr
|
|
when 14 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_NEXT_ADDR_OFFSET;
|
|
mem_write_data <= std_logic_vector(resize(mem_occupied_head,WORD_WIDTH));
|
|
mem_data_next.addr <= mem_addr_base;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
-- Update Occupied Head
|
|
mem_occupied_head_next <= mem_addr_base;
|
|
-- Initial Occupied Tail
|
|
if (mem_occupied_tail = GOAL_MEMORY_MAX_ADDRESS) then
|
|
mem_occupied_tail_next <= mem_addr_base;
|
|
end if;
|
|
|
|
-- DONE
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when GET =>
|
|
case (mem_cnt) is
|
|
-- GET Goal State
|
|
when 0 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_STATE_OFFSET;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
if check_mask(mem_latch_data.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 1;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 5;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_latch_data.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
mem_cnt_next <= 10;
|
|
end if;
|
|
end if;
|
|
-- GET Goal ID 1/4
|
|
when 1 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_GOAL_ID_OFFSET;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- GET Goal ID 2/4
|
|
when 2 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_GOAL_ID_OFFSET + 1;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- GET Goal ID 3/4
|
|
when 3 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_GOAL_ID_OFFSET + 2;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- GET Goal ID 4/4
|
|
when 4 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_GOAL_ID_OFFSET + 3;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
if check_mask(mem_latch_data.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 5;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_latch_data.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
if check_mask(mem_latch_data.field_flags,GMF_STATE_FLAG) then
|
|
mem_cnt_next <= 10;
|
|
else
|
|
mem_cnt_next <= 11;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
-- GET Stamp 1/2
|
|
when 5 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_STAMP_OFFSET;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- GET Stamp 2/2
|
|
when 6 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_STAMP_OFFSET + 1;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
if (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_latch_data.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
if check_mask(mem_latch_data.field_flags,GMF_STATE_FLAG) then
|
|
mem_cnt_next <= 10;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 11;
|
|
else
|
|
mem_cnt_next <= 15;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
-- GET Deadline 1/2
|
|
when 7 =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_DURATION_INFINITE) then
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_DEADLINE_OFFSET;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- GET Deadline 2/2
|
|
when 8 =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_DURATION_INFINITE) then
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_DEADLINE_OFFSET + 1;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
if check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
if check_mask(mem_latch_data.field_flags,GMF_STATE_FLAG) then
|
|
mem_cnt_next <= 10;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 11;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 15;
|
|
else
|
|
mem_cnt_next <= 17;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
-- GET Result Index
|
|
when 9 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_RESULT_INDEX_OFFSET;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
if check_mask(mem_latch_data.field_flags,GMF_STATE_FLAG) then
|
|
mem_cnt_next <= 10;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 11;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 15;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_latch_data.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 17;
|
|
else
|
|
mem_cnt_next <= 19;
|
|
end if;
|
|
end if;
|
|
-- READ Goal State
|
|
when 10 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_data_next.state <= mem_read_data(CDR_INT8_WIDTH-1 downto 0);
|
|
|
|
if check_mask(mem_latch_data.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 11;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 15;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_latch_data.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 17;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 19;
|
|
else
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
-- READ Goal ID 1/4
|
|
when 11 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_data_next.goal_id(0) <= mem_read_data;
|
|
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- READ Goal ID 2/4
|
|
when 12 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_data_next.goal_id(1) <= mem_read_data;
|
|
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- READ Goal ID 3/4
|
|
when 13 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_data_next.goal_id(2) <= mem_read_data;
|
|
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- READ Goal ID 4/4
|
|
when 14 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_data_next.goal_id(3) <= mem_read_data;
|
|
|
|
if check_mask(mem_latch_data.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 15;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_latch_data.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 17;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 19;
|
|
else
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
-- READ Stamp 1/2
|
|
when 15 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_data_next.stamp.sec <= mem_read_data;
|
|
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- READ Stamp 2/2
|
|
when 16 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_data_next.stamp.nanosec <= mem_read_data;
|
|
|
|
if (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_latch_data.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 17;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 19;
|
|
else
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
-- READ Deadline 1/2
|
|
when 17 =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_DURATION_INFINITE) then
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_data_next.deadline.sec <= mem_read_data;
|
|
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- READ Deadline 2/2
|
|
when 18 =>
|
|
-- Synthesis Guard
|
|
if (TIMEOUT_DURATION /= ROS_DURATION_INFINITE) then
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_data_next.deadline.nanosec <= mem_read_data;
|
|
|
|
if check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 19;
|
|
else
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
-- READ Result index
|
|
when 19 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_data_next.res_ind <= mem_read_data;
|
|
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when GET_NEXT =>
|
|
case (mem_cnt) is
|
|
-- GET Next Addr
|
|
when 0 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_NEXT_ADDR_OFFSET;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- READ Next Addr
|
|
when 1 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_addr_base_next <= resize(unsigned(mem_read_data),GOAL_MEMORY_ADDR_WIDTH);
|
|
mem_stage_next <= GET;
|
|
|
|
if check_mask(mem_latch_data.field_flags,GMF_STATE_FLAG) then
|
|
mem_cnt_next <= 0;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 1;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 5;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_latch_data.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
-- DONE
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when GET_PREV =>
|
|
case (mem_cnt) is
|
|
-- GET Previous Addr
|
|
when 0 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_PREV_ADDR_OFFSET;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- READ Previous Addr
|
|
when 1 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_addr_base_next <= resize(unsigned(mem_read_data),GOAL_MEMORY_ADDR_WIDTH);
|
|
mem_stage_next <= GET;
|
|
|
|
if check_mask(mem_latch_data.field_flags,GMF_STATE_FLAG) then
|
|
mem_cnt_next <= 0;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 1;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 5;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_latch_data.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
-- DONE
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when UPDATE =>
|
|
case (mem_cnt) is
|
|
-- SET Goal State
|
|
when 0 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_STATE_OFFSET;
|
|
mem_write_data <= (others => '0');
|
|
mem_write_data(CDR_INT8_WIDTH-1 downto 0) <= mem_latch_data.state;
|
|
mem_data_next.state <= mem_latch_data.state;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
if check_mask(mem_latch_data.field_flags,GMF_GOAL_ID_FLAG) then
|
|
mem_cnt_next <= 1;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 5;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_latch_data.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
-- SET Goal ID 1/4
|
|
when 1 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_GOAL_ID_OFFSET;
|
|
mem_write_data <= mem_latch_data.goal_id(0);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Goal ID 2/4
|
|
when 2 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_GOAL_ID_OFFSET + 1;
|
|
mem_write_data <= mem_latch_data.goal_id(1);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Goal ID 3/4
|
|
when 3 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_GOAL_ID_OFFSET + 2;
|
|
mem_write_data <= mem_latch_data.goal_id(3);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Goal ID 4/4
|
|
when 4 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_GOAL_ID_OFFSET + 3;
|
|
mem_write_data <= mem_latch_data.goal_id(3);
|
|
mem_data_next.goal_id <= mem_latch_data.goal_id;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
if check_mask(mem_latch_data.field_flags,GMF_STAMP_FLAG) then
|
|
mem_cnt_next <= 5;
|
|
elsif (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_latch_data.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
-- SET Stamp 1/2
|
|
when 5 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_STAMP_OFFSET;
|
|
mem_write_data <= mem_latch_data.stamp.sec;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Stamp 2/2
|
|
when 6 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_STAMP_OFFSET + 1;
|
|
mem_write_data <= mem_latch_data.stamp.nanosec;
|
|
mem_data_next.stamp <= mem_latch_data.stamp;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
if (TIMEOUT_DURATION /= ROS_DURATION_INFINITE and check_mask(mem_latch_data.field_flags,GMF_DEADLINE_FLAG)) then
|
|
mem_cnt_next <= 7;
|
|
elsif check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
-- SET Deadline 1/2
|
|
when 7 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_DEADLINE_OFFSET;
|
|
mem_write_data <= mem_latch_data.deadline.sec;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Deadline 2/2
|
|
when 8 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_DEADLINE_OFFSET + 1;
|
|
mem_write_data <= mem_latch_data.deadline.sec;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
if check_mask(mem_latch_data.field_flags,GMF_RESULT_INDEX_FLAG) then
|
|
mem_cnt_next <= 9;
|
|
else
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
-- SET Result Index
|
|
when 9 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_RESULT_INDEX_OFFSET;
|
|
mem_write_data <= mem_latch_data.res_ind;
|
|
mem_data_next.res_ind <= mem_latch_data.res_ind;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
-- DONE
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when REMOVE =>
|
|
case (mem_cnt) is
|
|
-- GET Next Addr
|
|
when 0 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_NEXT_ADDR_OFFSET;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- GET Previous Addr
|
|
when 1 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_PREV_ADDR_OFFSET;
|
|
mem_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Next Addr
|
|
when 2 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_NEXT_ADDR_OFFSET;
|
|
mem_write_data <= std_logic_vector(resize(GOAL_MEMORY_MAX_ADDRESS,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
-- Set New Empty Head
|
|
mem_empty_head_next <= mem_addr_base;
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Next Addr (Current Tail)
|
|
when 3 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_empty_tail + GMF_NEXT_ADDR_OFFSET;
|
|
mem_write_data <= std_logic_vector(resize(mem_addr_base,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
-- Set New Empty TAIL
|
|
mem_empty_tail_next <= mem_addr_base;
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- READ Next Addr
|
|
when 4 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
mem_addr_latch_next <= resize(unsigned(mem_read_data),GOAL_MEMORY_ADDR_WIDTH);
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- READ Previous Addr
|
|
when 5 =>
|
|
mem_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_valid_out = '1') then
|
|
-- Set mem_data.addr to previous slot
|
|
mem_data_next.addr <= resize(unsigned(mem_read_data),GOAL_MEMORY_ADDR_WIDTH);
|
|
|
|
if (mem_addr_latch = GOAL_MEMORY_MAX_ADDRESS) then
|
|
-- Set New Occupied Tail
|
|
mem_occupied_tail_next <= resize(unsigned(mem_read_data),GOAL_MEMORY_ADDR_WIDTH);
|
|
|
|
if (resize(unsigned(mem_read_data),GOAL_MEMORY_ADDR_WIDTH) = GOAL_MEMORY_MAX_ADDRESS) then
|
|
-- Reset Occupied Head
|
|
mem_occupied_head_next <= GOAL_MEMORY_MAX_ADDRESS;
|
|
mem_stage_next <= IDLE;
|
|
else
|
|
mem_addr_base_next <= resize(unsigned(mem_read_data),GOAL_MEMORY_ADDR_WIDTH);
|
|
mem_cnt_next <= mem_cnt + 2;
|
|
end if;
|
|
else
|
|
mem_addr_base_next <= mem_addr_latch;
|
|
mem_addr_latch_next <= resize(unsigned(mem_read_data),GOAL_MEMORY_ADDR_WIDTH);
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- SET Previous Addr (Next Slot)
|
|
when 6 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_PREV_ADDR_OFFSET;
|
|
mem_write_data <= std_logic_vector(resize(mem_addr_latch,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
if (mem_addr_latch = GOAL_MEMORY_MAX_ADDRESS) then
|
|
-- Set New Occupied Head
|
|
mem_occupied_head_next <= mem_addr_base;
|
|
-- DONE
|
|
mem_stage_next <= IDLE;
|
|
else
|
|
mem_addr_base_next <= mem_addr_latch;
|
|
mem_addr_latch_next <= mem_addr_base;
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- SET Next Addr (Previous Slot)
|
|
when 7 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_NEXT_ADDR_OFFSET;
|
|
mem_write_data <= std_logic_vector(resize(mem_addr_latch,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
-- DONE
|
|
mem_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when RESET_MEMORY =>
|
|
case (mem_cnt) is
|
|
-- SET Result Index
|
|
when 0 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_RESULT_INDEX_OFFSET;
|
|
mem_write_data <= std_logic_vector(empty_head_res_ind);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Next Pointer
|
|
when 1 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_NEXT_ADDR_OFFSET;
|
|
if (mem_addr_base = MAX_GOAL_ADDRESS) then
|
|
mem_write_data <= std_logic_vector(resize(GOAL_MEMORY_MAX_ADDRESS,WORD_WIDTH));
|
|
else
|
|
mem_write_data <= std_logic_vector(resize(mem_addr_base + GOAL_FRAME_SIZE,WORD_WIDTH));
|
|
end if;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
mem_cnt_next <= mem_cnt + 1;
|
|
end if;
|
|
-- SET Previous Pointer
|
|
when 2 =>
|
|
mem_valid_in <= '1';
|
|
mem_addr <= mem_addr_base + GMF_PREV_ADDR_OFFSET;
|
|
mem_write_data <= std_logic_vector(resize(mem_addr_latch,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (mem_ready_in = '1') then
|
|
if (mem_addr_base = MAX_GOAL_ADDRESS) then
|
|
-- Initialize Empty and Occupied Heads
|
|
mem_empty_head_next <= FIRST_GOAL_ADDRESS;
|
|
mem_empty_tail_next <= MAX_GOAL_ADDRESS;
|
|
mem_occupied_head_next <= GOAL_MEMORY_MAX_ADDRESS;
|
|
mem_occupied_tail_next <= GOAL_MEMORY_MAX_ADDRESS;
|
|
empty_head_res_ind_next <= (others => '0');
|
|
|
|
-- DONE
|
|
mem_stage_next <= IDLE;
|
|
else
|
|
empty_head_res_ind_next <= empty_head_res_ind + 1;
|
|
mem_addr_latch_next <= mem_addr_base;
|
|
mem_addr_base_next <= mem_addr_base + GOAL_FRAME_SIZE;
|
|
mem_cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end case;
|
|
end process;
|
|
|
|
sync_prc : process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
if (reset = '1') then
|
|
stage <= RESET_MEMORY;
|
|
goal_stage <= IDLE;
|
|
cancel_stage <= IDLE;
|
|
status_stage <= IDLE;
|
|
mem_stage <= RESET_MEMORY;
|
|
mem_data_r <= ZERO_GOAL_DATA;
|
|
mem_data_c <= ZERO_GOAL_DATA;
|
|
mem_data_s <= ZERO_GOAL_DATA;
|
|
mem_latch_data <= ZERO_GOAL_DATA;
|
|
mem_data <= ZERO_GOAL_DATA;
|
|
rrq_addr_base <= FIRST_RRQ_ADDRESS;
|
|
rrq_addr_latch <= RRQ_MEMORY_MAX_ADDRESS;
|
|
mem_addr_base <= FIRST_GOAL_ADDRESS;
|
|
mem_addr_latch <= GOAL_MEMORY_MAX_ADDRESS;
|
|
rrq_empty_head <= RRQ_MEMORY_MAX_ADDRESS;
|
|
rrq_occupied_head <= RRQ_MEMORY_MAX_ADDRESS;
|
|
mem_occupied_head <= GOAL_MEMORY_MAX_ADDRESS;
|
|
mem_occupied_tail <= GOAL_MEMORY_MAX_ADDRESS;
|
|
mem_empty_head <= GOAL_MEMORY_MAX_ADDRESS;
|
|
mem_empty_tail <= GOAL_MEMORY_MAX_ADDRESS;
|
|
return_code_latch <= ROS_RET_OK;
|
|
request_id_latch <= EMPTY_REQUEST_ID;
|
|
check_time <= ROS_TIME_INFINITE;
|
|
time_latch <= ROS_TIME_INVALID;
|
|
goal_handle_latch <= GOAL_HANDLE_UNKNOWN;
|
|
goal_state_latch <= GoalStatus_package.STATUS_UNKNOWN;
|
|
g_stamp <= ROS_TIME_INVALID;
|
|
search_type_c <= SEARCH_NONE;
|
|
cancel_ret_code <= CancelGoal_package.RR_ERROR_NONE;
|
|
cnt <= 0;
|
|
terminal_cnt <= 0;
|
|
c_cnt <= 0;
|
|
goals_canceling_cnt <= 0;
|
|
status_list_cnt <= 0;
|
|
mem_cnt <= 0;
|
|
trigger_result <= '0';
|
|
trigger_status <= '1'; -- Trigger Status Update immediately
|
|
g_accept <= '0';
|
|
empty_head_res_ind <= (others => '0');
|
|
else
|
|
stage <= stage_next;
|
|
goal_stage <= goal_stage_next;
|
|
cancel_stage <= cancel_stage_next;
|
|
status_stage <= status_stage_next;
|
|
mem_stage <= mem_stage_next;
|
|
mem_data_r <= mem_data_r_next;
|
|
mem_data_c <= mem_data_c_next;
|
|
mem_data_s <= mem_data_s_next;
|
|
mem_latch_data <= mem_latch_data_next;
|
|
mem_data <= mem_data_next;
|
|
rrq_addr_base <= rrq_addr_base_next;
|
|
rrq_addr_latch <= rrq_addr_latch_next;
|
|
mem_addr_base <= mem_addr_base_next;
|
|
mem_addr_latch <= mem_addr_latch_next;
|
|
rrq_empty_head <= rrq_empty_head_next;
|
|
rrq_occupied_head <= rrq_occupied_head_next;
|
|
mem_occupied_head <= mem_occupied_head_next;
|
|
mem_occupied_tail <= mem_occupied_tail_next;
|
|
mem_empty_head <= mem_empty_head_next;
|
|
mem_empty_tail <= mem_empty_tail_next;
|
|
return_code_latch <= return_code_latch_next;
|
|
request_id_latch <= request_id_latch_next;
|
|
check_time <= check_time_next;
|
|
time_latch <= time_latch_next;
|
|
goal_handle_latch <= goal_handle_latch_next;
|
|
goal_state_latch <= goal_state_latch_next;
|
|
g_stamp <= g_stamp_next;
|
|
search_type_c <= search_type_c_next;
|
|
cancel_ret_code <= cancel_ret_code_next;
|
|
cnt <= cnt_next;
|
|
terminal_cnt <= terminal_cnt_next;
|
|
c_cnt <= c_cnt_next;
|
|
goals_canceling_cnt <= goals_canceling_cnt_next;
|
|
status_list_cnt <= status_list_cnt_next;
|
|
mem_cnt <= mem_cnt_next;
|
|
trigger_result <= trigger_result_next;
|
|
trigger_status <= trigger_status_next;
|
|
g_accept <= g_accept_next;
|
|
empty_head_res_ind <= empty_head_res_ind_next;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end architecture;
|