Skocz do zawartości

Czy w układach FPGA niezbędny jest reset?


Elvis

Pomocna odpowiedź

Pytanie jak w tytule - czyli, czy w przypadku FPGA niezbędny jest przycisk reset?

Mam płytkę Icestick (https://www.latticesemi.com/icestick), która niestety nie posiada ani jednego przycisku. Z tego co czytałem, reset jest niezbędny w przypadku układów ASIC, bo ich stan po załączeniu zasilania jest losowy. Natomiast FPGA i tak są konfigurowane z pamięci Flash, więc teoretycznie bez resetu ich działanie powinno być poprawne.

Staram się uruchomić prosty procesor na podstawie przykładów z książki: https://wydawnictwo.btc.pl/informatyka/102935-wprowadzenie-do-jezyka-verilog.html. Jednak po uruchomieniu kodu, program wydaje się "zawieszać" na pewien czas i dopiero później działać poprawnie. Dodanie przycisku reset wydaje się rozwiązywać problem, ale to niezbyt wygodne rozwiązanie w przypadku płytki icestick. Może coś innego jest przyczyną dziwnego działania, ale jak szukać przyczyny? W symulacji wyniki prezentują się poprawnie.

Kod, który staram się uruchomić wygląda następująco:

module top #(
    parameter SIM = 0
)(
    input clk, rst,
    output [3:0] led
);

localparam OP_NOP = 4'b0000;
localparam OP_LDA = 4'b0001;
localparam OP_STA = 4'b0010;
localparam OP_ALU = 4'b0011;
localparam OP_JMP = 4'b0100;
localparam OP_JNZ = 4'b0101;
localparam OP_OUT = 4'b0110;

localparam ALU_MOV = 4'b0000;
localparam ALU_ADD = 4'b0001;
localparam ALU_SUB = 4'b0010;
localparam ALU_AND = 4'b0011;
localparam ALU_OR  = 4'b0100;
localparam ALU_XOR = 4'b0101;
localparam ALU_SHL = 4'b0110;
localparam ALU_SHR = 4'b0111;

reg [7:0] RAM[0:31];
reg [15:0] ROM[0:255];

reg [11:0] PC = 12'hfff, next_PC;
reg [15:0] IR = {OP_JMP, 12'h000};
reg [7:0] ACC, next_ACC;
reg [7:0] tmp_mem;
reg [7:0] output_port;

wire [11:0] PAR = IR[11:0];
wire [3:0] OPCODE = IR[15:12];
wire [3:0] ALU_OP = IR[11:8];
wire [7:0] ALU_PAR = IR[7:0];

wire [7:0] test_dly1 = RAM[1];
wire [7:0] test_dly2 = RAM[2];
wire [7:0] test_cnt = RAM[7];

assign led = (rst) ? 4'b1111 : output_port;

initial
    if (SIM)
        $readmemh("blink_sim.mem", ROM);
    else
        $readmemh("blink.mem", ROM);

always @(*)
case (ALU_OP)
    ALU_MOV: next_ACC = ALU_PAR;
    ALU_ADD: next_ACC = ACC + ALU_PAR;
    ALU_SUB: next_ACC = ACC - ALU_PAR;
    ALU_AND: next_ACC = ACC & ALU_PAR;
    ALU_OR:  next_ACC = ACC | ALU_PAR;
    ALU_XOR: next_ACC = ACC ^ ALU_PAR;
    ALU_SHL: next_ACC = ACC << 1;
    ALU_SHR: next_ACC = ACC >> 1;
    default: next_ACC = ACC;
endcase

always @(posedge clk, posedge rst)
if (rst)
begin
    PC <= 12'hfff;
    IR <= { OP_JMP, 12'h000 };
end
else
begin        
    PC <= next_PC;
    IR <= ROM[next_PC];
end

always @(*)
    case (OPCODE)
        OP_JMP: next_PC = PAR;
        OP_JNZ: next_PC = (ACC != 8'h00) ? PAR : PC + 1'b1;
        default: next_PC = PC + 1'b1;
    endcase

always @(posedge clk)
    case (OPCODE)
        OP_ALU: ACC <= next_ACC;
        OP_LDA: ACC <= tmp_mem;
        OP_STA: RAM[PAR] <= ACC;
        OP_OUT: output_port <= ACC;
    endcase

always @(negedge clk)
    case (OPCODE)
        OP_LDA: tmp_mem <= RAM[PAR];
    endcase

endmodule

A program dla "procesora":

3000 // 00: MOV #0
2007 // 01: STA 7
6000 // 02: OUT #0
3000 // 03: MOV #0
2001 // 04: STA 1
3020 // 05: MOV #20h
2002 // 06: STA 2
3000 // 07: MOV #0
3201 // 08: SUB #1
5008 // 09: JNZ #08h
1001 // 0a: LDA 1
3201 // 0b: SUB #1
2001 // 0c: STA 1
5007 // 0d: JNZ #07h
3000 // 0e: MOV #0
2001 // 0f: STA 1
1002 // 10: LDA 2
3201 // 11: SUB #1
2002 // 12: STA 2
5007 // 13: JNZ #07h
3020 // 14: MOV #20h
2002 // 15: STA 2
1007 // 16: LDA 7
3701 // 17: SHR #1
501a // 18: JNZ #1ah
3008 // 19: MOV #08h
2007 // 1a: STA 7
6000 // 1b: OUT #0
4007 // 1c: JMP #07h

Skończyły mi się już pomysły na poszukiwanie błędu, więc wszelkie sugestie mile widziane 🙂

Edytowano przez Elvis
Link do komentarza
Share on other sites

Pytanie jest postawione dość ogólnie, dlatego odpowiedź również jest ogólna – to zależy od układu.
 

Na githubie można znaleźć wymianę wiadomości na ten temat w przypadku układów iCE40 – według tego, co zrozumiałem z pobieżnego przeczytania, narzędzie do syntezy ignoruje początkowe wartości, zawsze rejestry są inicjalizowane zerami.

 

Nie jest to regułą w przypadku innych układów. Mam doświadczenie tylko z Xilinxem i tam w przypadku „stosunkowo" nowych układów (od chyba serii Spartan 3) można inicjalizować rejestry własnymi wartościami. To działało, pomijając fakt, że te układy mogły mieć co najwyżej zewnętrzną pamięć nieulotną FLASH (tak, jak jest w przypadku płytki do kursu Forbota) – w każdym razie przy programowaniu układu przerzutniki automatycznie otrzymywały żądaną wartość początkową.


Reset jest raczej dobrą praktyką i nie zawsze musi być to fizyczny przycisk na płytce.
W jednym projekcie korzystałem z sygnału LOCKED prymitywu obudowującego pętlę PLL (chyba nawet jest to opisane w zalinkowanej wyżej podstronie githuba). Wówczas reset jest niejako automatycznie generowany po włączeniu zasilania (a w zasadzie konfiguracji układu).
W Xilinxie (odnoszę się tutaj do układów obsługiwanych przez Vivado, nie wiem, czy dotyczy to również wcześniejszych) są również bloczki, które umożliwiają stworzenie wirtualnych wejść/wyjść – VIO, może to zastąpić fizyczny przycisk. Istnieje również bloczek do podglądu zmiennych – ILA (Integrated Logic Analyzer). Nie mam pojęcia, czy w przypadku Lattice'a są również podobne narzędzia, ale myślę, że warto to sprawdzić.

  • Lubię! 1
  • Pomogłeś! 1
Link do komentarza
Share on other sites

@piotr96 Dziękuję za odpowiedź. Jak chodzi o układ Lattice, to jak napisałem używam płytki Icestick, więc jest na niej układ ice40hx-1k. Jest to bardzo prosty układ, ale do nauki bardzo fajny. "Procesor", który staram się uruchomić wykorzystuje mniej niż 10% zasobów, więc w tej chwili to idealnie wystarcza. Korzystam z narzędzi open-source, głównie yosys - to działa o wiele szybciej niż narzędzia Lattice, o Vivado nawet nie wspominając. W każdym razie synteza zajmuje kilka sekund, a że nie jestem zbyt cierpliwy więc to dla mnie duża zaleta. Nie używam PLL, bo na razie nie było mi potrzebne, staram się uruchomić możliwie prosty i ogólny układ. Tylko nie wiem skąd te różnice między symulacją (gdzie wszystko jest ok), a rzeczywistością, gdzie układ jakby się zawieszał przed rozpoczęciem działania.

Lattice dostarcza coś w rodzaju ILA, ale to chyba nie zadziała z narzędziami open-source, więc na razie wolałbym tę opcję pominąć. Spróbuję za to przetestować ten sam projekt na płytce z układem Xilinx-a. Synteza jest koszmarnie wolna, ale może będzie łatwiej zrozumieć gdzie jest błąd. Dziękuję za podpowiedź jak chodzi o użycie innych układów - może za bardzo się skoncentrowałem na tym ice40.

Link do komentarza
Share on other sites

Update: W przypadku Xilinx-a jest jeszcze ciekawiej. Wszystko działa pięknie przy programowaniu przez JTAG. Układ startuje natychmiast, nie ma problemów ze stanem początkowym. Ale po zaprogramowaniu QSPI flash, układ nie działa wcale 😞 Używam płytki Basys3 i postępowałem według instrukcji na stronie producenta: https://digilent.com/reference/learn/programmable-logic/tutorials/basys-3-programming-guide/start

Jak chodzi o układy Xilinxa to mam trochę doświadczenia z układami SoC, czyli z rdzeniem ARM, natomiast FPGA programuję raczej hobbistycznie i zawsze przez JTAG... A teraz już sam nie wiem co z tym począć 😕

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Update 2: Chyba faktycznie jestem mało cierpliwy. Konfiguracja układów Xilinx-a zajmuje jednak sporo czasu, ale jak się cierpliwie poczeka, to wszystko działa idealnie. Czyli ten projekt na Basys3 działa zgodnie z oczekiwaniami, a na Icestick nie bardzo 😞 Tylko dlaczego?

Link do komentarza
Share on other sites

2 godziny temu, piotr96 napisał:

Pytanie jest postawione dość ogólnie, dlatego odpowiedź również jest ogólna – to zależy od układu.
..
Reset jest raczej dobrą praktyką i nie zawsze musi być to fizyczny przycisk na płytce.
W jednym projekcie korzystałem z sygnału LOCKED prymitywu obudowującego pętlę PLL (chyba nawet jest to opisane w zalinkowanej wyżej podstronie githuba). Wówczas reset jest niejako automatycznie generowany po włączeniu zasilania (a w zasadzie konfiguracji układu).
 

Cześć @piotr96

w kilku projektach robiłem podobnie - używałem sygnału LOCKED z petli PLL. Uważam to za dość dobre rozwiązanie.

Pozdrawiam

Link do komentarza
Share on other sites

 

50 minut temu, Elvis napisał:

Update 2: Chyba faktycznie jestem mało cierpliwy. Konfiguracja układów Xilinx-a zajmuje jednak sporo czasu, ale jak się cierpliwie poczeka, to wszystko działa idealnie. Czyli ten projekt na Basys3 działa zgodnie z oczekiwaniami, a na Icestick nie bardzo 😞 Tylko dlaczego?

Na moje oko, to układy iCE40 po prostu nie wspierają funkcjonalności ustawiania dowolnej wartości rejestrów podczas inicjalizacji (cytat ze strony, w dokumentacji jest podobny) :

Cytat

Global Reset Control The global reset control signal connects to all PLB and PIO flip-flops on the iCE40 device. The global reset signal is automatically asserted throughout the configuration process, forcing all flip-flops to their defined wake-up state. For PLB flip-flops, the wake-up state is always reset, regardless of the PLB flip-flop primitive used in the application.

 

  • Lubię! 1
Link do komentarza
Share on other sites

56 minut temu, Elvis napisał:

Update 2: Chyba faktycznie jestem mało cierpliwy. Konfiguracja układów Xilinx-a zajmuje jednak sporo czasu, ale jak się cierpliwie poczeka, to wszystko działa idealnie. Czyli ten projekt na Basys3 działa zgodnie z oczekiwaniami, a na Icestick nie bardzo 😞 Tylko dlaczego?

Cześc @Elvis,

dopiero teraz zauważyłem wątek. Narzędzia open-source dla FPGA (także wspomnieny Yosys) nie mają jednej ważnej opcji - mianowicie analizy "time-constraints" - choć to już bardziej zadanie next-prn. Osobiście nie mam żadnego problemu z używaniem narzędzi open-source, ale oglądałem wypowiedzi ludzi, którzy zajmują się układami programowalnymi zawodowo i dla nich narzędzia open-source są po prostu nieużywalne. Analiza czasowa ukłądu jest bardzo ważna - bez jej przeprowadzenia nie można mieć żadnej pewności, że projektowany układ zadziała z pożądaną częstotliwościa. Może własnie twój przypadek zalicza się do tej kategorii. Próbowałes obniżyć zegar dla układu? Sprawdź też, czy sygnały zegarowe sa podawane na "clock capable" pins. Możesz też mieć  niestabilne zasilanie układu FPGA.

Pozdrawiam

Edytowano przez FlyingDutch
Link do komentarza
Share on other sites

(edytowany)

@FlyingDutch Wydaje mi się, że narzędzia open-source dbają o wymagania czasowe, w każdym razie wśród komunikatów jest coś takiego:

Info: Max frequency for clock 'clk$SB_IO_IN_$glb_clk': 97.71 MHz (PASS at 12.00 MHz)

Info: Max delay <async>                       -> <async>                      : 3.19 ns
Info: Max delay <async>                       -> posedge clk$SB_IO_IN_$glb_clk: 1.96 ns
Info: Max delay posedge clk$SB_IO_IN_$glb_clk -> <async>                      : 2.78 ns

Jak dla mnie ice40 + narzędzia open-source to idealne rozwiązanie do nauki. Działają bardzo szybko, są o wiele prostsze do użycia niż wielkie i skomplikowane kombajny dostarczane przez producentów krzemu. Do tego czas syntezy tego projektu to:

make  1.67s user 0.05s system 99% cpu 1.729 total

Vivado nawet trywialne błędy w kodzie wyświetla po minucie lub dwóch... A synteza na basys3 trwała kilka minut.

Oczywiście wszystko zależy co i po co robimy - bardzo lubię narzędzia Xilinxa dla Zynq albo MPSoC. Jak mamy skomplikowany projekt to czas syntezy liczony w godzinach nie jest zaskakujący, jednak do nauki podstaw to jak dla mnie nieporozumienie.

W każdym razie to co staram się uruchomić działa raptem na 12MHz, nie używam PLL, chciałem tylko poznać podstawy. Ale może w przypadku ICE40 trzeba dodać reset i nie wnikać 😕 Tylko nie wiem, czy to taki urok ice40, czy ja czegoś nie rozumiem i stąd błędy 😞

Edytowano przez Elvis
Link do komentarza
Share on other sites

Edit: Jak chodzi o zależności czasowe, to dla ice40 dostępne jest otwarte narzędzie icetime. Jego uruchomienie daje następujący efekt:

 % icetime -p icestick.pcf -P tq144 -r cpu01.timings -d hx1k -t top.asc 
// Reading input .pcf file..
// Reading input .asc file..
// Reading 1k chipdb file..
// Creating timing netlist..
// Timing estimate: 9.11 ns (109.83 MHz)

Więc dla 12MHz to raczej nie problem 🙂 Jak chodzi o zasilanie, to używam płytki ewaluacyjnej od Lattice, czyli producenta układu FPGA. Wydaje mi się, że to dobrze przetestowany projekt, gdyby pojawiały się problemy, ktoś już by je zauważył.

  • Lubię! 1
Link do komentarza
Share on other sites

Nie wiem, czy udało mi się rozwiązać problem, czy tylko go ukryć, ale czytając podlinkowane rozwiązania znalazłem coś co wydaje się działać poprawnie:

    reg [7:0] resetn_counter = 0;
    assign resetn = &resetn_counter;

    always @(posedge clk) begin
            if (!resetn)
                    resetn_counter <= resetn_counter + 1;
    end

Użycie rejestru ustawianego na zero do resetowania nie spełniło swojego zadania. Czyli coś jak poniżej nie działało:

reg rst = 1'b0;

always @(posedge clk)
if (~rst)
begin
    PC <= 12'hfff;
    IR <= { OP_JMP, 12'h000 };
    rst <= 1'b1;
end

Jeśli jednak zamiast jednego rejestru, użyjemy tablicy i przez to wydłużymy czas resetowania, układ zaczyna działać w pełni poprawnie. Eksperymentalnie dobrałem minimalny "czas" resetu i kod wygląda następująco:

reg [2:0] rst = 3'b0;

always @(posedge clk)
if (~&rst)
begin
    PC <= 12'hfff;
    IR <= { OP_JMP, 12'h000 };
    rst <= rst + 1'b1;
end

Nie wpadłbym na pomysł resetowania przez więcej niż jeden cykl zegara, ale jak widać ktoś już miał podobne problemy, skoro używał 8-bitowego rejestru w takim celu. Jeszcze raz dziękuję za podpowiedzi.

  • Lubię! 2
Link do komentarza
Share on other sites

11 godzin temu, Elvis napisał:

Edit: Jak chodzi o zależności czasowe, to dla ice40 dostępne jest otwarte narzędzie icetime. Jego uruchomienie daje następujący efekt:


 % icetime -p icestick.pcf -P tq144 -r cpu01.timings -d hx1k -t top.asc 
// Reading input .pcf file..
// Reading input .asc file..
// Reading 1k chipdb file..
// Creating timing netlist..
// Timing estimate: 9.11 ns (109.83 MHz)

Więc dla 12MHz to raczej nie problem 🙂 Jak chodzi o zasilanie, to używam płytki ewaluacyjnej od Lattice, czyli producenta układu FPGA. Wydaje mi się, że to dobrze przetestowany projekt, gdyby pojawiały się problemy, ktoś już by je zauważył.

Hej @Elvis,

dobrze wiedzieć, że dla ice40 jest takie narzędzie, bo dla projektu X-Ray (dla układów Xylinx'a) nic podobnego nie mogłem znaleźć.

Pozdrawiam

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.