Tengo el siguiente código Verilog que envía 8 bytes al puerto serial 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 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, a veces, no recibe el resto y cuelga.
He mirado este código muchas veces y parece que no puedo entender por qué podría ser. ¿Estoy usando la selección parcial incorrectamente? No lo creo, pero no sé qué más puede ser el problema.
Adjunté una segunda versión de este código que funciona (lo que significa que se reciben todos los bytes y 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
REVISIÓN:
Siguiendo el consejo de @dwikle, en lugar de usar un estado "catch-all" que recorre el envío de los 8 bytes, creé un estado separado para cada byte que debía enviarse.
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 cada dos bytes. ¿Lo que da?
¿Algunas ideas?
PD: publiqué el código UART en mis documentos de Google, si necesita echar un vistazo. :)
ACTUALIZAR:
La pregunta original de este hilo provino de intentar aislar un problema de comunicación en un módulo más grande.
El proyecto simplemente acepta 64 bits (8 bytes) de datos de la PC, encripta los datos con el algoritmo DES, y envía el mensaje encriptado (64 bits, nuevamente).
La transferencia funciona, pero (lo que parece ser arbitrario) cuelga. Cuando intento hacer 1000 encriptaciones, en promedio puedo manejar alrededor de 250, a veces haciendo las 1000 con éxito y, a veces, tal vez solo haciendo 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 que 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 en realidad radica 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 recopila 7 bytes nuevamente y luego, de alguna manera, pierde el último byte del fragmento de 64 bits y se atasca en el estado buscando el último byte.
Intenté simular el diseño, pero siento que el estímulo que estoy proporcionando no es del todo kosher. El banco de pruebas debe enviar 8 bytes de datos a través del uart, y luego la máquina de estado debe continuar, encriptando y devolviendo el mensaje.
Sin embargo, proporcionar diferentes vectores de datos a la línea rx del 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 el hardware real) o incluso devuelve errores.
Entonces, 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 el último.
2) Para diagnosticar este problema, intenté investigar los resultados de la simulación. Sin embargo, incluso estos parecen dar un comportamiento inesperado, y me temo que tal vez estoy dando estímulos incorrectamente.
Cualquier comentario o sugerencia para la implementación del banco de pruebas, o lo que puede estar causando el cese de la comunicación, sería muy apreciado. Si estas preguntas parecen elementales, pido disculpas, todavía estoy aprendiendo.
Adjunté un zip en mis documentos de Google con todos los archivos relevantes, incluido el banco de pruebas.
https://docs.google.com/open?id=0B4WyEjzmIhtNN0V6a0x5U19SMUU
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
El problema es que su código "transmission_test" está escrito de tal manera que asume que "is_transmitting" del UART se cumple antes del borde del reloj que sigue a la afirmación de "begin_transmit". No es así: se necesita un ciclo de reloj antes de que el transmisor UART salga de su estado "inactivo", después de lo cual "is_transmitting" es verdadero.
Como resultado, su máquina de estado "transmission_test" avanza dos estados por cada byte transmitido, y solo ve uno de cada dos bytes en la salida del UART.
Hay muchos problemas menores con sus ejemplos de código, pero lo principal que debe solucionar es verificar que "is_transmitting" se haya cumplido antes de avanzar al siguiente byte en el mensaje.
Esto habría sido bastante obvio si se hubiera tomado el tiempo de simular este proyecto. No puedo dejar de enfatizar la importancia de la simulación en la verificación del código FPGA. Tómese el tiempo para familiarizarse con su simulador y aprender a escribir buenos bancos de pruebas de módulos.
Sin conocer los requisitos de la UART, supongo que el problema radica en begin_transmit
. En su caso de "trabajo" begin_transmit
, se borrará para cada byte ya que se está moviendo a través del estado UPDATE_DATA
. Sin embargo, en el caso de que no funcione, permanecerá en el estado SEND_BYTES
durante toda la transmisión y begin_transmit
solo se borrará si isTransmitting == 1
. (Tenga en cuenta que begin_transmit
se asigna 0
antes de la declaración del caso, lo que crea una asignación predeterminada).
Simulé el caso que no funciona y begin_transmit
solo pulsa cada dos bytes, lo que explicaría lo que está viendo si el UART espera ver un posedge en begin_transmit
. Sin el modelo UART, modelé isTransmitting
así para la simulación.
always @(posedge sysclk) begin
isTransmitting <= begin_transmit;
end
stevenvh
david tweed
barbero
barbero