0
\$\begingroup\$

I'm trying to get a Verilog design for interfacing with a PS/2 keyboard to work but I'm having very strange issues. I have a fairly simple always block which controls everything:

always@(negedge PS2_CLOCK) begin

    if(rst == 0) begin
        state <= READY;
        index <= 0;
        keycode <= 0;
        data <= 0;
        is_pressed <= 0;
    end
    else begin
        case (state)
            READY: begin
                state <= GRAB;
                is_pressed <= 0;
            end
            GRAB: begin
                if(index == 7) begin
                    data <= (data >> 1) | (PS2_DATA << 7);
                    index <= 0;
                    state <= PARITY;
                end
                else begin
                    data <= (data >> 1) | (PS2_DATA << 7);
                    index <= index + 3'b1;
                end
            end
            PARITY: begin
                state <= DONE;
            end
            DONE: begin
                is_pressed <= 1;
                state <= READY;
                keycode <= data;
                data <= 0;
                index <= 0;
            end
        endcase
    end
end

As you can see, this executes based on the negedge of the PS/2 clock but I'm not sure if that's a good idea. Every once in a while when I push a button on the keyboard, I fail to receive the data correctly and I think it's because of uncertainty in the clock signal. Here are two executions of the code when a button is pressed:

Working

Non-Working

The first is of a correct execution of the state machine while the second has a clear disruption in the clock signal. In this case, it wasn't very damaging but if it occurs near the end of the data transmission, it often causes my machine to skip a state and get out of sync. Any advice would be greatly appreciated.

\$\endgroup\$
  • 1
    \$\begingroup\$ Signal PS2_CLOCK is an input to this always block (circuit). If you see issues with this signal, you should look into this clock generation circuit - the circuit which has PS2_CLOCK as output. \$\endgroup\$ – Anonymous Dec 14 '16 at 7:52
1
\$\begingroup\$

It's not always advisable to block on a relatively slow clock in a relatively fast logic chip. Depending on how the synthesis tool worked, it may use one of a few dedicated clocking trees in the chip or just a regular IO line. A dedicated clock tree may not support a low frequency and the regular IO may skew improperly. I suspect one of the following:

Timing issue across domains

If you are connecting with faster logic you'll need some FIFO to cross the clock domains or you may lose data in the transfer. Typically this happens when going from faster to slower (eg. FIFO overflow) but in real silicone crossing a clock domain is tricky

setup and hold times

if your LUT or slice is running on a slow clock it's possible the button pressing that causes the miss sync is due to propagation delay. Unlikely but it may be worth putting the frequency of the PS/2 clock in your timing closure tool to see.

my solution

I'd block on the clock used in the rest of your system. Use a 2 bit register and bit shift in the PS/2 clock to make an edge detector. Then you control your state machine on the falling edge (2'b10). Using the fast clock even if you have a 1 cycle delay before reading the data bit you still have hundreds of cycles to take a sample.

\$\endgroup\$
  • \$\begingroup\$ I would concur about using an internal clock to sample the external slow logic clock, but you will need to put the usual flipflop chain for an async signal between the input and the internal clock domain. \$\endgroup\$ – Dan Mills Feb 13 '17 at 11:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.