Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
11 years ago

Looking for state machine in verilog

Hello there,

I'm running into the problem that I don't know how to do this. I want to write state machine to run 2 conditions on my project. When I turn on machine, I want it runs 1st condition for sometimes ns, then kick in the 2nd condition to take over.

Thanks,

Sean

9 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    You can achieve this by creating two processes (I don't know how this is called in verilog, I'm more into VHDL).

    The first process sets a pre-initialized signal from "State1" to "State2" if it gets a special signal from the second process.

    In the second process you put an if-statement like:

    
    State-Signal = State1
    Switch-Signal = 0
    Process1:
    if (Switch-Signal = 1)
    {
        Set State-Signal to "State2"
    }
    Process2:
    if (State-Signal = State1) then
    {
        Your code for State1
        if (time is up)
        {
            Switch-Signal = 1
        }
    }
    else
    {
        Your code for State2
    }
    

    this is a very raw example, how it is done normally. You can also use a switch-case-statement instead.

    You can also check if the time is up in process1 and then set state2 there.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    You can achieve this by creating two processes (I don't know how this is called in verilog, I'm more into VHDL).

    The first process sets a pre-initialized signal from "State1" to "State2" if it gets a special signal from the second process.

    In the second process you put an if-statement like:

    --- Quote End ---

    I really dont know what you're on about (your post does not make a lot of sense). A lot of old text books teams the two process method, but the apparent prefered method now is a single process.

    to the OP: there are plenty of examples out there - did you try google yet?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    yup, you're right. I'm a bit old-fashioned ;-)

    But you must admit, this works too.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    yup, you're right. I'm a bit old-fashioned ;-)

    But you must admit, this works too.

    --- Quote End ---

    Yes it does, and Im sure its how many started, but you can easily fall into the latch trap.

    As I understand the 2 process state machine is a throwback to very old compilers that could only cope with registers and logic in separate processes. But this hasnt been the case for a long time.

    For anyone starting, I would always recommend a single process (it reads better in my mind too - more like software!)

    To the OP - AFAIK, the same problems can also happen in verilog. So get googling.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Yes it does, and Im sure its how many started, but you can easily fall into the latch trap.

    As I understand the 2 process state machine is a throwback to very old compilers that could only cope with registers and logic in separate processes. But this hasnt been the case for a long time.

    For anyone starting, I would always recommend a single process (it reads better in my mind too - more like software!)

    To the OP - AFAIK, the same problems can also happen in verilog. So get googling.

    --- Quote End ---

    Thank you folks.

    Could you point me to the sample? So I want to know the idea how this works.

    Best,

    Sean
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Ok. I can explain more detail about how to solve.

    When I turn on machine at very first time, I want to output pwms out with fix duty cycle and runs over period time, then I want to switch to real pwm (calculate from loop feedback). My co-worker thinks to use Mux 2 to 1 with timer (counter).

    Hope you guys have some good news.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    I. A lot of old text books teams the two process method, but the apparent prefered method now is a single process.

    --- Quote End ---

    --- Quote Start ---

    Yes it does, and Im sure its how many started, but you can easily fall into the latch trap.

    As I understand the 2 process state machine is a throwback to very old compilers that could only cope with registers and logic in separate processes. But this hasnt been the case for a long time.

    For anyone starting, I would always recommend a single process (it reads better in my mind too - more like software!)

    To the OP - AFAIK, the same problems can also happen in verilog. So get googling.

    --- Quote End ---

    One-process state machines may seem to be the preferred method and will handle a lot of tasks but not all. Often you need combinatorial (non-registered) outputs and then the two-process is a lot easier to write and maintain than the 'one-process' where you have to anyway add that second process where you have to repeat most of the work to fabricate these combinatorial outputs. Most of my modules are ST-components for use in Qsys, and to handle the backpressure graciously you need combinatorial outputs. So Steffen, don't apologize. Two-process state machines are fine and certainly not out of fashion!

    Regards,

    Josy
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Does your logic state machine is working?

    I have my code here and hope you could find error in my code...

    localparam State1 = 0;

    localparam State2 = 1;

    reg [31:0] rCntr;

    reg [15:0] rTmCntr1, rTmCntr2;

    reg wPwm, StateSignal, SwitchSignal;

    initial begin

    rTmCntr1 = 0;

    rTmCntr2 = 0;

    rCntr = 2000000;

    wPwm = 0;

    StateSignal = State1;

    SwitchSignal = 0;

    end

    always @(posedge c0) begin

    if (SwitchSignal == 1)

    StateSignal = State2;

    end

    always @(posedge c0) begin

    if (StateSignal == State1) begin

    // code for State1

    if (Enable == 1'b1) begin

    rTmCntr1 <= rTmCntr1 + 1'b1;

    if (rTmCntr1 < 2500)

    wPwm <= 1;

    else if (rTmCntr1 > 2500)

    wPwm <= 0;

    if (rTmCntr1 == 5000)

    rTmCntr1 <= 1'b0;

    end

    if (rCntr > 0)

    rCntr <= rCntr - 1'b1;

    else if (rCntr == 10)

    SwitchSignal = 1;

    end

    else begin

    // code for State2

    if (Enable == 1'b1) begin

    rTmCntr2 <= rTmCntr2 + 1'b1;

    if (rTmCntr2 < 1250)

    wPwm <= 1;

    else if (rTmCntr2 > 5000)

    wPwm <= 0;

    if (rTmCntr2 == 5000)

    rTmCntr2 <= 1'b0;

    end

    end

    end

    Thanks,

    Sean
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    As I said, i'm mor into VHDL than Verilog.

    Please use CODE-Tags if you want to write Code in your Post. It makes debugging easier.

    What is your Error-Message?

    I think you have forgotten to close some of your if statements. This is how I read your code:

    localparam State1 = 0;
    localparam State2 = 1;
    reg  rCntr;
    reg  rTmCntr1, rTmCntr2;
    reg wPwm, StateSignal, SwitchSignal;
    initial begin
    rTmCntr1 = 0;
    rTmCntr2 = 0;
    rCntr = 2000000;
    wPwm = 0;
    StateSignal = State1;
    SwitchSignal = 0;
    end
    always @(posedge c0) begin
    if (SwitchSignal == 1)
    	StateSignal = State2;
    end
    always @(posedge c0) begin
    if (StateSignal == State1) begin
    	// code for State1
    	if (Enable == 1'b1) begin
    		rTmCntr1 <= rTmCntr1 + 1'b1;
    		if (rTmCntr1 < 2500)
    			wPwm <= 1;
    		else if (rTmCntr1 > 2500)
    			wPwm <= 0;
    			if (rTmCntr1 == 5000)
    				rTmCntr1 <= 1'b0;
    			end
    			if (rCntr > 0)
    				rCntr <= rCntr - 1'b1;
    			else if (rCntr == 10)
    				SwitchSignal = 1;
    			end
    else begin
    // code for State2
    if (Enable == 1'b1) begin
    	rTmCntr2 <= rTmCntr2 + 1'b1;
    	if (rTmCntr2 < 1250)
    		wPwm <= 1;
    	else if (rTmCntr2 > 5000)
    		wPwm <= 0;
    		if (rTmCntr2 == 5000)
    		rTmCntr2 <= 1'b0;
    		end
    	end
    end

    And this is how I think it should work (better):

    localparam State1 = 0;
    localparam State2 = 1;
    reg  rCntr;
    reg  rTmCntr1, rTmCntr2;
    reg wPwm, StateSignal, SwitchSignal;
    initial begin
    rTmCntr1 = 0;
    rTmCntr2 = 0;
    rCntr = 2000000;
    wPwm = 0;
    StateSignal = State1;
    SwitchSignal = 0;
    end
    always @(posedge c0) begin
    if (SwitchSignal == 1)
    	StateSignal = State2;
    end
    always @(posedge c0) begin
    if (StateSignal == State1) begin
    	// code for State1
    	if (Enable == 1'b1) begin
    		rTmCntr1 <= rTmCntr1 + 1'b1;
    		if (rTmCntr1 < 2500)
    			wPwm <= 1;
    		else if (rTmCntr1 > 2500)
    			wPwm <= 0;
    			if (rTmCntr1 == 5000)
    				rTmCntr1 <= 1'b0;
    			end
    			if (rCntr > 0)
    				rCntr <= rCntr - 1'b1;
    			else if (rCntr == 10)
    				SwitchSignal = 1;
    			end
    		end
    	end
    else begin
    // code for State2
    if (Enable == 1'b1) begin
    	rTmCntr2 <= rTmCntr2 + 1'b1;
    	if (rTmCntr2 < 1250)
    		wPwm <= 1;
    	else if (rTmCntr2 > 5000)
    		wPwm <= 0;
    		if (rTmCntr2 == 5000)
    		rTmCntr2 <= 1'b0;
    		end
    	end
    end