Tengo el siguiente código Verilog que envía 8 bytes al puerto serie sucesivamente después de presionar un botón.
El problema es que los bytes se envían fuera de orden en cuanto a lo que yo esperaría.
Por ejemplo, si envío los bytes 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF - la PC obtiene 0xEF, 0xAD, 0xEF, 0xAD y algunas veces no recibe el resto y se cuelga .
He mirado este código muchas veces y parece que no puedo entender por qué esto podría ser. ¿Estoy usando la selección de parte incorrectamente? No lo creo, pero no sé qué otra cosa podría ser el problema.
He adjuntado una segunda versión de este código que funciona (lo que significa que todos los bytes se reciben y están en el orden correcto), pero requiere un ciclo de reloj adicional porque actualiza los datos en el registro de desplazamiento después de cada transmisión. Si puede ver alguna razón por la cual la primera versión publicada no funciona, pero la segunda sí, hágamelo saber.
module transmission_test_2(sysclk, rxd, txd, LED, button);
input sysclk, rxd, button;
output txd;
output reg LED;
wire receiving_complete, isReceiving, isTransmitting, isError;
reg begin_transmit;
reg [7:0] tbyte;
wire [7:0] rbyte;
reg [2:0] state;
reg [63:0] plain_text;
integer byteN;
parameter IDLE = 0, BEGIN_TRANSMISSION = 1, UPDATE_DATA = 2, SEND_BYTES = 3;
uart uart1(
.clk(sysclk),
.rx(rxd),
.tx(txd),
.transmit(begin_transmit),
.tx_byte(tbyte),
.received(receiving_complete),
.rx_byte(rbyte),
.is_receiving(isReceiving),
.is_transmitting(isTransmitting),
.recv_error(isError)
);
always @(posedge sysclk)
begin
begin_transmit = 1'b0;
case(state)
IDLE: begin
if(button==1'b0) begin
LED = 1'b1;
plain_text = 64'hDEADBEEFDEADBEEF;
state = BEGIN_TRANSMISSION;
end else begin
LED <= 1'b0;
end
end
BEGIN_TRANSMISSION: begin
tbyte = plain_text[7:0];
begin_transmit = 1'b1;
byteN = 1;
state = SEND_BYTES;
end
SEND_BYTES: begin
if(!isTransmitting) begin
tbyte = plain_text[byteN*8 +: 8];
begin_transmit = 1'b1;
byteN = byteN + 1;
if(byteN == 8) begin
state = IDLE;
end
end
end
endcase
end
endmodule
Segunda versión "de trabajo":
module transmission_test(sysclk, rxd, txd, LED, button);
input sysclk, rxd, button;
output txd;
output reg LED;
wire receiving_complete, isReceiving, isTransmitting, isError;
reg begin_transmit;
reg [7:0] tbyte;
wire [7:0] rbyte;
reg [2:0] state;
reg [63:0] plain_text;
integer bytes_remaining;
parameter IDLE = 0, BEGIN_TRANSMISSION = 1, UPDATE_DATA = 2, SEND_BYTES = 3, DONE = 4;
uart uart1(
.clk(sysclk),
.rx(rxd),
.tx(txd),
.transmit(begin_transmit),
.tx_byte(tbyte),
.received(receiving_complete),
.rx_byte(rbyte),
.is_receiving(isReceiving),
.is_transmitting(isTransmitting),
.recv_error(isError)
);
always @(posedge sysclk)
begin
begin_transmit = 1'b0;
case(state)
IDLE: begin
if(button==1'b0) begin
LED = 1'b1;
plain_text = 64'hDEADBEEFDEADBEEF;
state = BEGIN_TRANSMISSION;
end else begin
LED <= 1'b0;
end
end
BEGIN_TRANSMISSION: begin
tbyte = plain_text[7:0];
begin_transmit = 1'b1;
bytes_remaining = 7;
state = UPDATE_DATA;
end
UPDATE_DATA: begin
plain_text = plain_text >> 8;
state = SEND_BYTES;
end
SEND_BYTES: begin
if(!isTransmitting) begin
tbyte = plain_text[7:0];
begin_transmit = 1'b1;
bytes_remaining = bytes_remaining - 1;
if(bytes_remaining == 0) begin
state = IDLE;
end else begin
state = UPDATE_DATA;
end
end
end
endcase
end
endmodule
REVISION:
Siguiendo los consejos de @dwikle, en lugar de usar un estado "catch-all" que alterna el envío de los 8 bytes, creé un estado separado para cada byte que se debía enviar.
Aquí está el código:
module transmission_test_3(sysclk, rxd, txd, LED, button);
input sysclk, rxd, button;
output txd;
output reg LED;
wire receiving_complete, isReceiving, isTransmitting, isError, reset;
reg begin_transmit;
reg [7:0] tbyte;
wire [7:0] rbyte;
reg [2:0] state = 4'b0;
reg [63:0] plain_text = 64'h0;
uart uart1(
.clk(sysclk),
.rst(reset),
.rx(rxd),
.tx(txd),
.transmit(begin_transmit),
.tx_byte(tbyte),
.received(receiving_complete),
.rx_byte(rbyte),
.is_receiving(isReceiving),
.is_transmitting(isTransmitting),
.recv_error(isError)
);
always @(posedge sysclk)
begin
begin_transmit = 1'b0;
case(state)
4'b0000: begin
if(button==1'b0) begin
LED = 1'b1;
plain_text = 64'hDEADBEEFAAABACAD;
state = 4'b0001;
end else begin
LED = 1'b0;
end
end
4'b0001: begin
tbyte = plain_text[7:0];
begin_transmit = 1'b1;
state = 4'b0010;
end
4'b0010: begin
if(!isTransmitting) begin
tbyte = plain_text[15:8];
begin_transmit = 1'b1;
state = 4'b0011;
end
end
4'b0011: begin
if(!isTransmitting) begin
tbyte = plain_text[23:16];
begin_transmit = 1'b1;
state = 4'b0100;
end
end
4'b0100: begin
if(!isTransmitting) begin
tbyte = plain_text[31:24];
begin_transmit = 1'b1;
state = 4'b0101;
end
end
4'b0101: begin
if(!isTransmitting) begin
tbyte = plain_text[39:32];
begin_transmit = 1'b1;
state = 4'b0110;
end
end
4'b0110: begin
if(!isTransmitting) begin
tbyte = plain_text[47:40];
begin_transmit = 1'b1;
state = 4'b0111;
end
end
4'b0111: begin
if(!isTransmitting) begin
tbyte = plain_text[55:48];
begin_transmit = 1'b1;
state = 4'b1000;
end
end
4'b1000: begin
if(!isTransmitting) begin
tbyte = plain_text[63:56];
begin_transmit = 1'b1;
state = 4'b0000;
end
end
endcase
end
endmodule
Sin embargo, los resultados siguen siendo los mismos: recibo todos los demás bytes. ¿Qué da?
¿Alguna idea?
P.S. - He publicado el código UART en mis documentos de Google - si necesita echar un vistazo. :)
ACTUALIZAR :
La pregunta original para este hilo provino de intentar aislar un problema de comunicación en un módulo más grande.
El proyecto simplemente acepta datos de 64 bits (8 bytes) de la PC (cifra los datos con el algoritmo DES) y envía el mensaje cifrado (de nuevo, 64 bits) nuevamente.
La transferencia funciona, pero (lo que parece ser arbitrariamente) cuelga. Al intentar hacer 1000 encriptaciones, en promedio puedo manejar alrededor de 250, a veces haciendo las 1000 correctamente, y otras veces solo 20 o 50.
Pensé que la transferencia era un cuello de botella en el lado de la transmisión de la comunicación, que era cuando estaba reescribiendo la transmisión y, por lo tanto, el propósito de este hilo. Sin embargo, me he dado cuenta de que el problema reside en el lado de la recepción de la transferencia. Lo que parece estar sucediendo es que después de realizar varias ejecuciones exitosas, la máquina de estado recolecta 7 bytes nuevamente y de alguna manera pierde el último byte del fragmento de 64 bits y se queda atascado en el estado buscando el último byte.
He intentado simular el diseño, pero siento que el estímulo que ofrezco no es muy kosher. El banco de pruebas debe enviar datos por valor de 8 bytes a través de la uart, y luego la máquina de estado debe seguir adelante, cifrando y enviando el mensaje.
Sin embargo, proporcionar diferentes vectores de datos a la línea de rx de la uart da resultados drásticamente diferentes. Dependiendo de los datos que estoy usando, el uart a veces recibe solo 7 bytes (que es el problema que estoy viendo con hardware real) o incluso devuelve errores.
Por lo tanto, los problemas que estoy tratando de resolver son:
1) Puedo recibir y transmitir con éxito varias decenas a cientos de cifrados, pero la comunicación se cuelga en puntos arbitrarios, y parece ser que cuando esto sucede, la máquina de estado ha recopilado 7 bytes y está buscando lo último. .
2) Para diagnosticar este problema, intenté ver los resultados de la simulación. Sin embargo, incluso estos parecen dar un comportamiento inesperado, y me temo que quizás esté dando estímulos incorrectamente.
Cualquier comentario o sugerencia para la implementación del banco de pruebas, o lo que pueda estar causando el cese de la comunicación sería muy apreciado. Si estas preguntas parecen elementales, me disculpo, todavía estoy aprendiendo.
He adjuntado un archivo zip en mis documentos de Google con todos los archivos relevantes, incluido el banco de pruebas.
También publicaré el módulo de nivel superior aquí como referencia.
module rs232_neek(sysclk, rxd, txd, reset, LED);
input sysclk, rxd, reset;
output txd;
wire receiving_complete, isTransmitting, isReceiving, isError;
output reg [3:0] LED; //The LEDs are used simply as debug - to determine which state the machine gets held-up in.
reg begin_transmit;
reg [7:0] tbyte;
wire [7:0] rbyte;
parameter FIRST_BYTE = 0, GET_BYTES = 1, BEGIN_ENC = 2, CHECK_ENC_STATUS = 3, BEGIN_TRANSMISSION = 4, SEND_BYTES = 5;
reg [2:0] state = 3'b0;
integer byteN = 0;
reg [3:0] sel = 4'b0;
reg [63:0] plain_text;
reg [63:0] cipher_text;
wire [63:0] cipher_net;
uart uart1(
.clk(sysclk),
.rst(~reset),
.rx(rxd),
.tx(txd),
.transmit(begin_transmit),
.tx_byte(tbyte),
.received(receiving_complete),
.rx_byte(rbyte),
.is_transmitting(isTransmitting),
.is_receiving(isReceiving),
.recv_error(isError)
);
des des1(
.clk(sysclk),
.key(56'h0),
.roundSel(sel),
.decrypt(1'b0),
.desIn(plain_text),
.desOut(cipher_net)
);
always @(posedge sysclk)
begin
if(~reset) begin
state = FIRST_BYTE;
end
LED = 4'b1111;
case(state)
FIRST_BYTE: begin
LED[0] = 1'b0;
begin_transmit = 1'b0;
if(receiving_complete) begin
plain_text[7:0] = rbyte;
byteN = 1;
state = GET_BYTES;
end
end
GET_BYTES: begin
LED[1] = 1'b0;
if(receiving_complete) begin
plain_text[byteN*8 +: 8] = rbyte;
byteN = byteN + 1;
if(byteN == 8) begin
state = BEGIN_ENC;
end
end
end
BEGIN_ENC: begin
sel = 4'b0;
state = CHECK_ENC_STATUS;
end
CHECK_ENC_STATUS: begin
LED[2] = 1'b0;
sel = sel + 1;
if(sel == 15) begin
state = BEGIN_TRANSMISSION;
end
end
BEGIN_TRANSMISSION: begin
cipher_text = cipher_net;
tbyte = cipher_text[7:0];
begin_transmit = 1'b1;
byteN = 1;
state = SEND_BYTES;
end
SEND_BYTES: begin
LED[3] = 1'b0;
if(!isTransmitting && !begin_transmit) begin
tbyte = cipher_text[byteN*8 +: 8];
begin_transmit = 1'b1;
byteN = byteN + 1;
if(byteN == 8) begin
state = FIRST_BYTE;
end
end else begin
begin_transmit = 1'b0;
end
end
endcase
end
endmodule