Scheduler TX Module ================================= Overview -------- **Scheduler_tx** is a transmit scheduler that prepares address and payload pairs for the HotRIO master transmit datapath. The module supports two normal transmit modes: * **Per-slave payload mode**, where each slave has its own payload and valid input. * **Single shared payload mode**, where the same payload is transmitted to each slave address in a round-robin sequence. The scheduler also supports a priority broadcast transaction. A broadcast request is latched on a rising edge and is transmitted before the next normal round-robin item when the downstream HotRIO master Tx Module requests new data. The output interface is request driven. The scheduler only changes ``tx_addr_o``, ``tx_payload_o``, ``tx_valid_o``, and ``tx_is_broadcast_o`` when ``next_data_req_i`` is asserted while the internal FSM is in the ``RUN`` state. This module provides address and payload to the HotRIO master Tx Module which periodically sends payloads to a configurable set of slave devices. The scheduler hides the address sequencing and payload selection logic from the transmit datapath. It does the following functionalities : * Polling and addressing multiple slave devices using sequential addresses. * Sending the same command or payload to all slaves in a round-robin manner. * Sending slave-specific payloads after all slave payloads have been captured. * Inserting a broadcast message with priority over normal scheduled traffic. The module is intended to sit between payload-producing logic and HotRIO Master Tx Module. The later consumes the current output transaction and then pulses ``next_data_req_i`` to request the next transaction. Detailed portlist ----------------- .. vhdlentity:: :file: ../Firmware/Source/modules/scheduler_tx/hdl/scheduler_tx.vhd :entity: scheduler_tx Source Dependencies ------------------- The design uses the following special packages: .. list-table:: :header-rows: 1 :widths: 25 75 * - Package - Purpose * - ``work.globals`` - Provides project-specific constants and types such as ``HOTRIO_ADDR_WIDTH_C``, ``HOTRIO_PAYLOAD_WIDTH_C``, ``payload_array_t``, and ``array_slv8`` and other shared constants and types. Generics -------- .. list-table:: :header-rows: 1 :widths: 22 18 20 40 * - Generic - Type / Range - Default - Description * - ``NUM_SLAVES_G`` - ``POSITIVE RANGE 1 TO 64`` - ``16`` - Defines the number of slave entries handled by the scheduler. This generic sizes the address table, per-slave payload array, valid vector, and round-robin index range. * - ``SINGLE_PAYLOAD_G`` - ``BOOLEAN`` - ``FALSE`` - Selects the normal payload scheduling mode. When ``TRUE``, the same shared payload is used for every slave address. When ``FALSE``, each slave uses its own payload captured from ``tx_payload_arr_i``. Generic Use Cases ~~~~~~~~~~~~~~~~~ ``NUM_SLAVES_G`` Use this generic to scale the scheduler to the number of addressed slave endpoints in the system. For example, if the master must address eight slaves, set ``NUM_SLAVES_G => 8``. The module then generates eight sequential addresses starting from ``first_slave_addr_i``. The generated address for slave index ``i`` is: .. code-block:: text slave_addrs_s(i) = first_slave_addr_i + i ``SINGLE_PAYLOAD_G`` Use this generic to choose between two scheduling styles: * ``FALSE``: each slave has a dedicated payload. This is suitable when every slave must receive different data. * ``TRUE``: all slaves receive the same payload. This is suitable for common commands, common configuration values, or repeated writes to a contiguous slave range. Internal Architecture --------------------- Reset Behavior ~~~~~~~~~~~~~~ When ``rstn_i = '0'`` on a rising clock edge: * ``fsm_s`` is set to ``IDLE``. * ``idx_s`` is reset to ``0``. * Per-slave payload registers are cleared. * ``valid_seen_s`` is cleared. * ``broadcast_pending_s`` is cleared. * Output registers are cleared and marked invalid. * Edge-detection history registers are cleared. Enable Behavior ~~~~~~~~~~~~~~~ When ``en_i`` is not asserted: * The FSM is forced to ``IDLE``. * ``tx_valid_s`` is deasserted. * ``tx_is_broadcast_s`` is deasserted. The design continues to sample edge-detection history at the end of the clocked process when not in reset. Broadcast latching and per-slave payload capture are evaluated before the enable check. Address Table Generation ~~~~~~~~~~~~~~~~~~~~~~~~ The address table is generated in the ``LOAD_ADDR`` state: .. code-block:: vhdl FOR i IN 0 TO NUM_SLAVES_G - 1 LOOP slave_addrs_s(i) <= STD_LOGIC_VECTOR( unsigned(first_slave_addr_i) + to_unsigned(i, HOTRIO_ADDR_WIDTH_C) ); END LOOP; After the table is loaded: * ``idx_s`` is reset to ``0``. * Outputs are marked invalid. * The FSM advances to ``RUN``. Payload Capture ~~~~~~~~~~~~~~~ In per-slave payload mode, valid payloads are captured continuously whenever ``SINGLE_PAYLOAD_G = FALSE``: .. code-block:: vhdl IF tx_payload_valid_arr_i(i) = '1' THEN payload_reg_s(i) <= tx_payload_arr_i(i); valid_seen_s(i) <= '1'; END IF; Once a payload has been seen for a slave, its corresponding ``valid_seen_s`` bit remains asserted until reset. The module therefore waits for initial payload availability from all slaves before transmitting normal per-slave traffic. Finite State Machine -------------------- ``IDLE`` State ~~~~~~~~~~~~~~ The ``IDLE`` state is the inactive entry point of the scheduler. Actions performed: * Deasserts ``tx_valid_s``. * Deasserts ``tx_is_broadcast_s``. * Advances to ``LOAD_ADDR`` when the module is enabled. This state ensures that the scheduler does not emit a valid transaction before the address table has been initialized. ``LOAD_ADDR`` State ~~~~~~~~~~~~~~~~~~~ The ``LOAD_ADDR`` state generates the internal address table. Each slave address is derived from ``first_slave_addr_i`` plus the slave index. Actions performed: * Generates ``slave_addrs_s(0)`` through ``slave_addrs_s(NUM_SLAVES_G - 1)``. * Resets ``idx_s`` to ``0``. * Deasserts ``tx_valid_s``. * Deasserts ``tx_is_broadcast_s``. * Advances to ``RUN``. This state is entered after ``IDLE`` and whenever ``addr_update_i`` has a rising edge while the FSM is in ``RUN``. ``RUN`` State ~~~~~~~~~~~~~ The ``RUN`` state is the active scheduling state. In this state, the scheduler responds to address updates, transmit requests, broadcast requests, and normal payload availability. Priority order inside ``RUN``: 1. Rising edge of ``addr_update_i``. 2. ``next_data_req_i`` from the HotRIO Master Tx. 3. Pending broadcast transaction. 4. Normal round-robin transaction. Address Update Priority ^^^^^^^^^^^^^^^^^^^^^^^ If ``addr_update_i`` has a rising edge, the scheduler: * Moves to ``LOAD_ADDR``. * Deasserts ``tx_valid_s``. * Deasserts ``tx_is_broadcast_s``. Address update has priority over both broadcast and normal traffic. Broadcast Scheduling ^^^^^^^^^^^^^^^^^^^^ A rising edge on ``broadcast_trigger_i`` sets ``broadcast_pending_s``. The pending broadcast is emitted on the next ``next_data_req_i`` request while the FSM is in ``RUN`` and no address update is taking priority. Broadcast output actions: * ``tx_addr_s`` is loaded from ``broadcast_addr_i``. * ``tx_payload_s`` is loaded from ``broadcast_payload_i``. * ``tx_valid_s`` is asserted. * ``tx_is_broadcast_s`` is asserted. * ``broadcast_pending_s`` is cleared. Broadcast traffic does not advance the normal round-robin index. Single Shared Payload Scheduling ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When ``SINGLE_PAYLOAD_G = TRUE``, normal scheduling uses ``shared_payload_i`` for every slave address. On ``next_data_req_i = '1'``: * If ``shared_payload_valid_i = '1'``: * ``tx_addr_s`` is loaded with ``slave_addrs_s(idx_s)``. * ``tx_payload_s`` is loaded with ``shared_payload_i``. * ``tx_valid_s`` is asserted. * ``tx_is_broadcast_s`` is deasserted. * ``idx_s`` advances to the next slave, wrapping to ``0`` after the last slave. * If ``shared_payload_valid_i = '0'``: * ``tx_valid_s`` is deasserted. * ``tx_is_broadcast_s`` is deasserted. * ``idx_s`` does not advance. Per-Slave Payload Scheduling ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When ``SINGLE_PAYLOAD_G = FALSE``, normal scheduling uses the internal ``payload_reg_s`` array. On ``next_data_req_i = '1'``: * If ``all_valid_s = '1'``: * ``tx_addr_s`` is loaded with ``slave_addrs_s(idx_s)``. * ``tx_payload_s`` is loaded with ``payload_reg_s(idx_s)``. * ``tx_valid_s`` is asserted. * ``tx_is_broadcast_s`` is deasserted. * ``idx_s`` advances to the next slave, wrapping to ``0`` after the last slave. * If ``all_valid_s = '0'``: * ``tx_valid_s`` is deasserted. * ``tx_is_broadcast_s`` is deasserted. * ``idx_s`` does not advance. Round-Robin Index Operation ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The round-robin index selects the current slave for normal traffic. It advances only after a normal transaction is emitted. .. code-block:: text 0 -> 1 -> 2 -> ... -> NUM_SLAVES_G - 1 -> 0 The index is reset to ``0``: * During reset. * When the address table is loaded in ``LOAD_ADDR``. The index is not advanced by: * Broadcast transactions. * Invalid shared payload cycles. * Per-slave mode cycles where not all payloads have been seen. * Address update cycles.