Lab 2 - Schedulers and State Machines

Basic Pulse Controller

Below is an example of a state machine in Verilog for scheduling pulses at different times. This state machine generates a pulse for a duration of 5 clock cycles, then stays low for 10 clock cycles, and then repeats. It uses a counter to keep track of the number of clock cycles that have passed.

module PulseGenerator (
    input wire clk,
    input wire rst_n,
    output reg pulse
);

    parameter IDLE = 2'b00, PULSE_HIGH = 2'b01, PULSE_LOW = 2'b10;
    reg [1:0] state, next_state;
    reg [4:0] counter;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state <= IDLE;
            counter <= 5'b00000;
            pulse <= 1'b0;
        end else begin
            state <= next_state;
            if (state == PULSE_HIGH)
                pulse <= 1'b1;
            else
                pulse <= 1'b0;

            if (counter == 5'b00000)
                counter <= 5'b11111;
            else
                counter <= counter - 1'b1;
        end
    end

    always @(*) begin
        next_state = state;
        case (state)
            IDLE: begin
                if (counter == 5'b00000)
                    next_state = PULSE_HIGH;
            end

            PULSE_HIGH: begin
                if (counter == 5'b00000)
                    next_state = PULSE_LOW;
            end

            PULSE_LOW: begin
                if (counter == 5'b00000)
                    next_state = PULSE_HIGH;
            end
        endcase
    end

endmodule

Multiple PRI Controller

This state machine has three states: IDLE, PULSE_HIGH and PULSE_LOW. It starts in the IDLE state and moves to PULSE_HIGH after 5 clock cycles, where it stays for 5 clock cycles before moving to PULSE_LOW. It stays in PULSE_LOW for 10 clock cycles before returning to PULSE_HIGH, and so on. This is a basic example, and your specific requirements might need different adjustments, such as changing the number of clock cycles for each pulse or low period, or adding more states. Next is a state machine with 8 different states for 8 different pulse repetition intervals. All pulses have the same width, which is 5 cycles in this case.

This state machine will transition from one state to another after each pulse repetition interval. For example, in the first state, it will generate a pulse, wait for 5 cycles, then generate another pulse. In the second state, it will generate a pulse, wait for 10 cycles, then generate another pulse, and so forth.

Here’s an example of how you might code this:

module PulseGenerator (
    input wire clk,
    input wire rst_n,
    output reg pulse
);

    // Define state IDs
    parameter [2:0]
        STATE_5  = 3'b000,
        STATE_10 = 3'b001,
        STATE_15 = 3'b010,
        STATE_20 = 3'b011,
        STATE_25 = 3'b100,
        STATE_30 = 3'b101,
        STATE_35 = 3'b110,
        STATE_40 = 3'b111;

    // Current state
    reg [2:0] state;

    // Pulse width counter and interval counter
    reg [4:0] pulse_width_counter;
    reg [5:0] interval_counter;

    // FSM Logic
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state <= STATE_5;
            pulse <= 1'b0;
            pulse_width_counter <= 5'd5;  // Pulse width is 5 cycles
            interval_counter <= 6'd5;  // First interval is 5 cycles
        end else begin
            // Handle pulse width counter
            if (pulse_width_counter > 1) begin
                pulse <= 1'b1;
                pulse_width_counter <= pulse_width_counter - 1'b1;
            end else begin
                pulse <= 1'b0;
                if (interval_counter > 1)
                    interval_counter <= interval_counter - 1'b1;
                else
                    // Move to the next state
                    case (state)
                        STATE_5:  begin state <= STATE_10; interval_counter <= 6'd10; end
                        STATE_10: begin state <= STATE_15; interval_counter <= 6'd15; end
                        STATE_15: begin state <= STATE_20; interval_counter <= 6'd20; end
                        STATE_20: begin state <= STATE_25; interval_counter <= 6'd25; end
                        STATE_25: begin state <= STATE_30; interval_counter <= 6'd30; end
                        STATE_30: begin state <= STATE_35; interval_counter <= 6'd35; end
                        STATE_35: begin state <= STATE_40; interval_counter <= 6'd40; end
                        STATE_40: begin state <= STATE_5;  interval_counter <= 6'd5;  end
                    endcase
            end
        end
    end
endmodule

This is a reduced state machine, and in a real-world situation, you might need to add more features to handle corner cases, errors, or specific application requirements. Please remember to test this code in your environment as different applications may need different adjustments. The scheduler generally has built in processing states (that may be done in parallel), here’s an example of a state machine which goes through 8 pulse repetition intervals, moves to a data processing state, and repeats the entire sequence 4 times. After four complete sequences, it stays in the IDLE state until a reset signal is received.

module PulseGenerator (
    input wire clk,
    input wire rst_n,
    output reg pulse,
    output reg processing
);

    // Define state IDs
    parameter [3:0]
        IDLE     = 4'b0000,
        STATE_5  = 4'b0001,
        STATE_10 = 4'b0010,
        STATE_15 = 4'b0011,
        STATE_20 = 4'b0100,
        STATE_25 = 4'b0101,
        STATE_30 = 4'b0110,
        STATE_35 = 4'b0111,
        STATE_40 = 4'b1000,
        PROCESS  = 4'b1001;

    // Current state
    reg [3:0] state;

    // Pulse width counter and interval counter
    reg [4:0] pulse_width_counter;
    reg [6:0] interval_counter;

    // Repeat counter
    reg [2:0] repeat_counter;

    // FSM Logic
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state <= IDLE;
            pulse <= 1'b0;
            processing <= 1'b0;
            pulse_width_counter <= 5'd5;  // Pulse width is 5 cycles
            interval_counter <= 7'd5;  // First interval is 5 cycles
            repeat_counter <= 3'd4;  // Repeat 4 times
        end else begin
            // Handle pulse width counter
            if (pulse_width_counter > 1) begin
                pulse <= 1'b1;
                pulse_width_counter <= pulse_width_counter - 1'b1;
            end else begin
                pulse <= 1'b0;
                if (interval_counter > 1)
                    interval_counter <= interval_counter - 1'b1;
                else
                    // Move to the next state
                    case (state)
                        IDLE:     begin state <= STATE_5; interval_counter <= 7'd5; end
                        STATE_5:  begin state <= STATE_10; interval_counter <= 7'd10; end
                        STATE_10: begin state <= STATE_15; interval_counter <= 7'd15; end
                        STATE_15: begin state <= STATE_20; interval_counter <= 7'd20; end
                        STATE_20: begin state <= STATE_25; interval_counter <= 7'd25; end
                        STATE_25: begin state <= STATE_30; interval_counter <= 7'd30; end
                        STATE_30: begin state <= STATE_35; interval_counter <= 7'd35; end
                        STATE_35: begin state <= STATE_40; interval_counter <= 7'd40; end
                        STATE_40: begin state <= PROCESS; end
                        PROCESS:  begin
                            if (repeat_counter > 1) begin
                                state <= STATE_5;
                                interval_counter <= 7'd5;
                                repeat_counter <= repeat_counter - 1'b1;
                            end else begin
                                state <= IDLE;
                            end
                        end
                    endcase
            end
            processing <= (state == PROCESS);
        end
    end
endmodule

In this example, a new PROCESS state is added to the state machine. After going through the 8 pulse states, the state machine moves to the PROCESS state. After staying in the PROCESS state for one cycle, it checks the repeat_counter. If the repeat_counter is greater than 1, it repeats the whole process by moving back to the first pulse state. Otherwise, it moves to the IDLE state. The processing output signal is high when the state machine is in the PROCESS state and low otherwise.

Nested Scheduling

The main takeaway here is that there are timed intervals within timed intervals for scheduling, here’s an example of what several processing intervals inside a SUBFRAME_A state that performs a processing operation 5 times. After the fifth time, it transitions to the SUBFRAME_B state:

module SubframeStateMachine (
    input wire clk,
    input wire rst_n,
    output reg processing
);

    // Define state IDs
    parameter [2:0]
        IDLE      = 3'b000,
        SUBFRAME_A = 3'b001,
        SUBFRAME_B = 3'b010;

    // Current state
    reg [2:0] state;

    // Processing counter
    reg [3:0] processing_counter;

    // FSM Logic
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state <= IDLE;
            processing <= 1'b0;
            processing_counter <= 4'd0;
        end else begin
            // Move to the next state
            case (state)
                IDLE: begin
                    state <= SUBFRAME_A;
                    processing_counter <= 4'd5;
                end

                SUBFRAME_A: begin
                    processing <= 1'b1;  // Perform processing
                    if (processing_counter > 1)
                        processing_counter <= processing_counter - 1'b1;
                    else
                        state <= SUBFRAME_B;
                end

                SUBFRAME_B: begin
                    processing <= 1'b0;  // No processing
                    // More logic can be added here for what needs to be done in SUBFRAME_B
                end
            endcase
        end
    end
endmodule

In this code, the state machine starts in an IDLE state. When it transitions to the SUBFRAME_A state, it performs some processing operation (represented by the processing output signal being set to 1) five times. After the fifth processing operation, the state machine transitions to the SUBFRAME_B state.

Note

Much of this lab was autogenerated, but the code should reflect what type of logic needs to be implemented.