Ich habe den folgenden Verilog-Code, der nach dem Drücken einer Taste nacheinander 8 Bytes an die serielle Schnittstelle sendet.
Das Problem ist, dass die Bytes nicht in der richtigen Reihenfolge gesendet werden, was ich erwarten würde.
Wenn ich zum Beispiel die Bytes 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF sende, erhält der PC 0xEF, 0xAD, 0xEF, 0xAD und empfängt manchmal nicht den Rest und legt auf.
Ich habe diesen Code oft angeschaut und kann anscheinend nicht herausfinden, warum dies so ist. Benutze ich die Teileauswahl falsch? Ich glaube nicht, aber ich weiß nicht, was sonst das Problem sein könnte.
Ich habe eine zweite Version dieses Codes angehängt, die funktioniert (dh alle Bytes werden empfangen und in der richtigen Reihenfolge), aber es dauert einen zusätzlichen Taktzyklus, da die Daten im Schieberegister nach jeder Übertragung aktualisiert werden. Wenn Sie einen Grund sehen können, warum die erste veröffentlichte Version nicht funktioniert, die zweite jedoch - lassen Sie es mich bitte wissen!
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
Zweite "funktionierende" Version:
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:
Dem Rat von @dwikle folgend - anstatt einen "Catch-All" -Zustand zu verwenden, der das Senden aller 8 Bytes durchläuft - habe ich für jedes zu sendende Byte einen separaten Status erstellt.
Hier ist der Code:
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
Die Ergebnisse sind jedoch immer noch dieselben - ich erhalte jedes zweite Byte. Was gibt?
Irgendwelche Ideen?
PS - Ich habe den UART-Code in meinen Google-Dokumenten veröffentlicht - wenn Sie einen Blick darauf werfen müssen. :) :)
AKTUALISIEREN:
Die ursprüngliche Frage für diesen Thread ergab sich aus dem Versuch, ein Kommunikationsproblem in einem größeren Modul zu isolieren.
Das Projekt akzeptiert einfach 64-Bit-Daten (8 Byte) vom PC - verschlüsselt die Daten mit dem DES-Algorithmus - und sendet die verschlüsselte Nachricht (wieder 64-Bit) zurück.
Die Übertragung funktioniert, legt aber (was willkürlich zu sein scheint) auf. Wenn ich versuche, 1000 Verschlüsselungen durchzuführen, kann ich durchschnittlich 250 verarbeiten - manchmal alle 1000 erfolgreich und manchmal vielleicht nur 20 oder 50.
Ich hatte gedacht, dass die Übertragung auf der Übertragungsseite der Kommunikation ein Flaschenhals war - das heißt, ich schrieb die Übertragung neu und damit den Zweck dieses Threads. Mir ist jedoch klar geworden, dass das Problem tatsächlich auf der Empfangsseite der Übertragung liegt. Was zu passieren scheint, ist, dass die Zustandsmaschine nach mehreren erfolgreichen Läufen wieder 7 Bytes sammelt und dann irgendwie das letzte Byte des 64-Bit-Blocks verfehlt und im Zustand stecken bleibt, der nach dem letzten Byte sucht.
Ich habe versucht, das Design zu simulieren - aber ich habe das Gefühl, dass der Stimulus, den ich gebe, nicht ganz koscher ist. Die Testbench sollte Daten im Wert von 8 Bytes über das Uart senden - und dann sollte die Zustandsmaschine die Nachricht tuckern, verschlüsseln und zurücksenden.
Das Bereitstellen unterschiedlicher Datenvektoren für die Empfangslinie des Uarts führt jedoch zu drastisch unterschiedlichen Ergebnissen. Abhängig von den Daten, die ich verwende, empfängt der Uart manchmal nur 7 Bytes (was das Problem ist, das ich mit echter Hardware betrachte) oder gibt sogar Fehler zurück.
Die Probleme, die ich herauszufinden versuche, sind:
1) Ich kann erfolgreich mehrere zehn bis hundert Verschlüsselungen empfangen und senden - aber die Kommunikation hängt an beliebigen Punkten ab - und es scheint, dass die Zustandsmaschine in diesem Fall 7 Bytes gesammelt hat und nach den letzten sucht.
2) Um dieses Problem zu diagnostizieren, habe ich versucht, die Simulationsergebnisse zu untersuchen. Allerdings - selbst diese scheinen unerwartetes Verhalten hervorzurufen - und ich fürchte, ich gebe möglicherweise falsche Reize.
Kommentare oder Vorschläge zur Implementierung der Testbench - oder was dazu führen kann, dass die Kommunikation unterbrochen wird - sind sehr willkommen. Wenn diese Fragen elementar erscheinen, entschuldige ich mich - ich lerne noch.
Ich habe in meinen Google-Dokumenten eine Zip-Datei mit allen relevanten Dateien, einschließlich der Testbench, angehängt.
https://docs.google.com/open?id=0B4WyEjzmIhtNN0V6a0x5U19SMUU
Ich werde hier auch das Top-Level-Modul als Referenz veröffentlichen.
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
Antworten:
Das Problem ist, dass Ihr "Transmission_Test" -Code so geschrieben ist, dass davon ausgegangen wird, dass "is_transmission" vom UART vor der Taktflanke, die auf die Behauptung von "begin_transmit" folgt, wahr wird. Dies ist nicht der Fall - es dauert einen Taktzyklus, bis der UART-Sender seinen "Leerlauf" -Zustand verlässt. Danach ist "is_transmission" wahr.
Infolgedessen rückt Ihre Zustandsmaschine "Transmission_test" zwei Zustände für jedes übertragene Byte vor, und Sie sehen nur jedes zweite Byte am Ausgang des UART.
Es gibt viele kleinere Probleme mit Ihren Codebeispielen, aber das Wichtigste, was Sie beheben müssen, ist zu überprüfen, ob "is_transmission" wahr ist, bevor Sie mit dem nächsten Byte in der Nachricht fortfahren.
Dies wäre ziemlich offensichtlich gewesen, wenn Sie sich die Zeit genommen hätten, dieses Projekt zu simulieren. Ich kann die Bedeutung der Simulation bei der Überprüfung des FPGA-Codes nicht genug betonen. Nehmen Sie sich Zeit, um sich mit Ihrem Simulator vertraut zu machen und zu lernen, wie Sie gute Modulprüfstände schreiben.
quelle
Ohne die Anforderungen des UART zu kennen, liegt das Problem vermutlich bei
begin_transmit
. In Ihrem "funktionierenden" Fallbegin_transmit
wird für jedes Byte gelöscht, da Sie sich durch den Status bewegenUPDATE_DATA
. Für den nicht funktionierenden Fall bleiben Sie jedochSEND_BYTES
für die gesamte Übertragung im Status undbegin_transmit
werden nur gelöscht, wennisTransmitting == 1
. (Beachten Sie, dass dies vor der case-Anweisungbegin_transmit
zugewiesen0
wird, wodurch eine Standardzuweisung erstellt wird.)Ich habe den nicht funktionierenden Fall simuliert und
begin_transmit
pulsiere nur jedes zweite Byte, was erklären würde, was Sie sehen, wenn der UART erwartet, dass ein Posedge angezeigt wirdbegin_transmit
. Ohne das UART-Modell habe ichisTransmitting
für die Simulation so modelliert .quelle