Ich habe den folgenden Verilog-Code, der nacheinander 8 Bytes an die serielle Schnittstelle sendet, nachdem eine Taste gedrückt wurde.
Das Problem ist, dass die Bytes nicht in der von mir erwarteten Reihenfolge gesendet werden.
Wenn ich zum Beispiel die Bytes 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF aussende, bekommt der PC 0xEF, 0xAD, 0xEF, 0xAD und bekommt manchmal den Rest nicht und legt auf.
Ich habe mir diesen Code viele Male angesehen und kann nicht herausfinden, warum das so sein könnte. Verwende ich die Teileauswahl falsch? Ich glaube nicht, aber ich wüsste nicht, woran es sonst noch liegen könnte.
Ich habe eine zweite Version dieses Codes angehängt, die funktioniert (was bedeutet, dass alle Bytes empfangen werden und in der richtigen Reihenfolge), aber es dauert einen zusätzlichen Taktzyklus, weil es die Daten im Schieberegister nach jeder Übertragung aktualisiert. Wenn Sie einen Grund sehen, warum die erste gepostete 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:
Nach dem Rat von @dwikle - anstatt einen "Catch-All" -Zustand zu verwenden, der alle 8 Bytes sendet - habe ich einen separaten Zustand für jedes Byte erstellt, das gesendet werden musste.
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 gepostet - wenn Sie einen Blick darauf werfen müssen. :)
AKTUALISIEREN:
Die ursprüngliche Frage für diesen Thread entstand aus dem Versuch, ein Kommunikationsproblem in einem größeren Modul zu isolieren.
Das Projekt akzeptiert einfach 64-Bit (8 Bytes) Daten vom PC – verschlüsselt die Daten mit dem DES-Algorithmus – und sendet die verschlüsselte Nachricht (wieder 64-Bit) zurück.
Die Übertragung funktioniert, aber (was scheinbar willkürlich ist) wird aufgelegt. Wenn ich versuche, 1000 Verschlüsselungen durchzuführen, kann ich im Durchschnitt etwa 250 bewältigen - manchmal mache ich alle 1000 erfolgreich und manchmal vielleicht nur 20 oder 50.
Ich hatte gedacht, dass die Übertragung auf der Übertragungsseite der Kommunikation einen Engpass darstellt – das heißt, ich habe die Übertragung umgeschrieben und daher den Zweck dieses Threads. Ich habe jedoch festgestellt, dass das Problem tatsächlich auf der Empfangsseite der Übertragung liegt. Was zu passieren scheint, ist, dass die Zustandsmaschine nach mehreren erfolgreichen Läufen erneut 7 Bytes sammelt und dann irgendwie das letzte Byte des 64-Bit-Chunks verfehlt und im Zustand hängen 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 die uart senden - und dann sollte die Zustandsmaschine mittuckern, die Nachricht verschlüsseln und zurücksenden.
Das Bereitstellen unterschiedlicher Datenvektoren für die rx-Leitung des uart 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.
Also, die Probleme, die ich versuche herauszufinden, sind:
1) Ich kann mehrere zehn bis hundert Verschlüsselungen erfolgreich empfangen und übertragen - aber die Kommunikation hängt an beliebigen Stellen - und es scheint so zu sein, dass die Zustandsmaschine in diesem Fall 7 Bytes gesammelt hat und nach den letzten sucht.
2) Um dieses Problem zu diagnostizieren, habe ich versucht, mir die Simulationsergebnisse anzusehen. Allerdings - selbst diese scheinen unerwartetes Verhalten zu zeigen - und ich fürchte, vielleicht gebe ich die Stimuli falsch.
Jegliche Kommentare oder Vorschläge zur Implementierung der Testbench – oder was möglicherweise dazu führt, dass die Kommunikation unterbrochen wird – würden wir sehr begrüßen. Wenn diese Fragen elementar erscheinen, entschuldige ich mich - ich lerne noch.
Ich habe eine ZIP-Datei in meinen Google-Dokumenten mit allen relevanten Dateien, einschließlich der Testbench, angehängt.
https://docs.google.com/open?id=0B4WyEjzmIhtNN0V6a0x5U19SMUU
Ich werde auch das Top-Level-Modul hier als Referenz posten.
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
Das Problem ist, dass Ihr "transmission_test"-Code so geschrieben ist, dass er davon ausgeht, dass "is_transmitting" vom UART vor der Taktflanke wahr wird, die der Behauptung von "begin_transmit" folgt. Dies ist nicht der Fall - es dauert einen Taktzyklus, bis der UART-Sender seinen "Leerlauf" -Zustand verlässt, wonach "is_transmitting" wahr ist.
Infolgedessen erhöht Ihre "transmission_test" -Zustandsmaschine zwei Zustände für jedes übertragene Byte, 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_transmitting" wahr geworden ist, bevor Sie zum 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 Verifizierung von FPGA-Code gar nicht genug betonen. Nehmen Sie sich die Zeit, sich mit Ihrem Simulator vertraut zu machen und lernen Sie, wie man gute Modul-Testbenches schreibt.
Ohne die Anforderungen des UART zu kennen, vermute ich, dass das Problem bei begin_transmit
. In Ihrem "Arbeitsfall" begin_transmit
wird jedes Byte gelöscht, da Sie sich durch state bewegen UPDATE_DATA
. Im nicht funktionierenden Fall bleiben Sie jedoch SEND_BYTES
während der gesamten Übertragung im Status und begin_transmit
werden nur freigegeben, wenn isTransmitting == 1
. (Beachten Sie, dass vor der case-Anweisung begin_transmit
zugewiesen 0
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, ein Posedge on zu sehen begin_transmit
. isTransmitting
Ohne das UART-Modell habe ich so für die Simulation modelliert .
always @(posedge sysclk) begin
isTransmitting <= begin_transmit;
end
stevenvh
David Tweed
kfriseur
kfriseur