Well the first problem I see is that you are using unsynchronized inputs. Whenever you start seeing weird, unexplainable behavior, that's the place to start looking.
Here I have synchronized them and converted your blocking assingments to non-blocking. It introduces at least 2 FF stages to prevent metastability from infecting the design.
///////// ps2keyboard.v file /////////
`timescale 1ns / 1ps
// this module currently just outputs the scancode, ignoring key-up codes.
module ps2keyboard(clock, ps2clock, ps2data, scanCode);
input clock;
input ps2clock;
input ps2data;
reg ps2clock_1, ps2clock_2, ps2clock_3;
reg ps2data_1, ps2data_2, ps2data_3;
output reg [7:0] scanCode;
reg [7:0] buffer;
reg [3:0] currentBit;
always @(posedge clock)
begin
{ps2clock_3, ps2clock_2, ps2clock_1} <= {ps2clock_2, ps2clock_1, ps2clock};
{ps2data_3, ps2data_2, ps2data_1} <= {ps2data_2, ps2data_1, ps2data};
// wait for a falling edge on the ps2 clock line
if(ps2clock_3 & ~ps2clock_2)
begin
// shift scan code (bits 1-8) into the buffer
if(currentBit >= 1 && currentBit <= 8)
buffer[currentBit - 1] <= ps2data_3;
// wrap around to bit 0 when reaching the end of the 11-bit word and output the scan code byte
currentBit <= currentBit + 1;
if(currentBit == 11)
begin
currentBit <= 0;
if(buffer != 8'hF0 && buffer != 8'hE0) // don't display key-up F0 events, or E0 prefixes
scanCode <= buffer;
end
end
end
endmodule
As I explained to you before, ISE is using the checksum of your verilog source files to determine a fitter seed. So basically due to various randomness of the fitting process (determined exactly by the seed) is affecting the way the metastability is manifesting in your design.
I had a similar bug go unnoticed for 3 years when I clocked both ports of a BRAM with the same clock, but the signals on one port were in another clock domain. It worked most of the time except for some unrelated changes causing differences in fitting so that it broke due to marginal internal setup/hold times.