Dus? Wat is daar mis mee?

Mijn toepassing is geen GPL dus ik kan geen GPL onderdelen gebruiken.

En je wilt hem gaan verkopen? Inderdaad, als je dan je wijzigingen aan de pavr niet wilt vrijgeven, dan moet je die niet gebruiken.

Zelfs al zou ik het niet verkopen, ik ga de source in ieder geval niet vrijgeven. GPL is alles meteen ook GPL. Wat jij bedoelt is LGPL, daar hoef je alleen wijzigingen aan de 'library' zelf vrij te geven.

Hmmmmmm. Alles wat "afgeleid" wordt moet je de code van vrijgeven. Aan diegenen die je spul kopen (of krijgen)! Over het algemeen wordt het linken van modules aan je programma gezien als "afleiden". In het geval van een AVR core in een FPGA zou je het zo kunnen zien dat je de code van de rest van je FPGA moet vrijgegven. Anderzijds, het DOEL van de GPL is om er voor te zorgen dat kleine verbeteringen aan de reeds vrijgegeven spullen niet voor jezelf gehouden worden. Als jij de PAVR verbetert om minder cycles te gebruiken moet je dat vrijgeven. Als je naast de AVR een BLDC controller schrijft, vind ik dat niet een AFGELEIDE van de PAVR, hoewel die via Quartus in de zelfde binary verdwijnt...

Kortom, ik zou het wel durven, maar als jij het niet durft, moet je het niet doen. Ik ben ook geen advokaat....

Even voor de duidelijkheid: De GPL zegt niks over dat je je source op het internet moet zetten. Je moet OFWEL de source meeleveren aan degenen die je product (binary) ontvangen. Ofwel je moet het tegen kostprijs opsturen. Je kunt dus wel degelijk intern ergens aan werken, zonder dat dat meteen op het internet hoeft.

[Bericht gewijzigd door rew op (16%)]

Het hele probleem zit hem in inderdaad in de term 'afgeleid'. Bij software weet ik in ieder geval dat dit heel strict genomen wordt. Zodra de library in je programma opgenomen wordt, is het hele werk een 'afgeleide'. Zelfs bij dynamisch linken (zoals DLLs in windows) zijn de meningen er nog over verdeeld of dat onder afgeleid werk valt.

Bij hardware is dit misschien wat lastiger, GPL is ook meer een software licentie volgens mij. Maar ik weet wel dat het niet makkelijk is onder GPL uit te komen. Je uiteindelijk binary is toch een afgeleide van de library, het is denk ik het meest te vergelijken met statisch linken in software. Twee losse FPGA's met een AVR in de ene en je eigen spul in de andere is dan waarschijnlijk geen afgeleid werk meer, maar ja dat wil je ook niet.

Iemand hier ervaring met compileren voor niosII?

Ik heb nu de tutorial zover doorlopen dat ik wat asm kon kloppen maar nu krijg ik steeds gezever dat ie nios_macros.s niet kan vinden.
( deze zou ergens moeten zijn of gegenereert worden )

C:/test/light/lights.s:1: Can't open nios_macros.s for reading: No such file or directory
Compilation stopped.

heb al gegoogled maar daar wordt ik ook weinig wijzer van

@ stec366

C begrijp ik weer zo slecht maar die werkte wel al was dat gewoon copy paste om te testen

ik gebruik voor asm en c de altera client debugger (nieuwste van hun site )

geloof dat dit met sopc builder te maken zal hebben omdat deze dat bestand volgens mij moet genereren voor elke nios systeem dat gemaakt wordt.

edit 2008 :
oplossing voor dit probleem is belachelijk simpel gewoon de include van deze macro weglaten en hij compiled zonder problemen

Ik heb nog geen assembler voor NIOS gecompiled, enkel C. Dus daar kan ik je niet mee helpen, sorry..

gutentag,

Ik ben aan t proberen om in verilog een led te laten knipperen, aan de hand van twee drukknopjes. Mijn code nu is als volgt:


module leddelay(clk,res,delay,done,led);
	input clk, res;		// klok en reset
	input delay;			// tel signaal
	output done;
	   reg done;
	output led; reg led;
	//reg str;
	reg [31:0] q;
	reg [31:0] temp;

always @ (posedge clk or negedge res)
	begin	
		q=27000000;  // stel hier de delay in (27MHz clk)  //max. 4.294.967.295
		if (res == 0)begin
				led = 1;
				temp = 0;
				done = 0;
				str = 0;
		end
		else begin
			led = 0;
			if (delay == 0) begin//toggle switches are inverted
				str = 1;
			end
			else str = 0;
			if(str) begin
				temp = temp + 1'b1;
				if(temp == q) begin
					done = 1;
				end
				else 
				done = 0;
			end							
		end		
	end
endmodule

led is aangesloten op "LEDR1", en geeft aan dat de FPGA in de reset mode zit. Dit werkt op het bord. De reset zit op "KEY0". Nu wil ik als ik vervolgens op delay ("KEY1") druk, dat de FPGA gaat tellen, en even later een ledje ("LEDR0") laat branden. De connecties in mijn pinplanner zitten juist. Hetgeen wat niet werkt is dat mijn led0 niet wil gaan branden na +-1 sec. Heb ik nu ergens een domme fout gemaakt, of iets over het hoofd gezien?

Alvast bedankt,

Rik

Je code is erg software-achtig geschreven, vergeet niet dat je hardware aan het maken bent. Gebruik <= in plaats van =, dat is normaler in hardware. Dit betekent wel dat de waarden die je instelt pas bij de volgende kloktik beschikbaar zijn. Als led 0 was, en je doet led <= 1, dan is led nog steeds 0 daarna, en pas bij de volgende kloktik 1. Met = is dat niet zo, maar <= is beter in hardware te implementeren. <= kan namelijk parallel uitgevoerd worden, terwijl = 'achter elkaar' (als chain) uitgevoerd moet worden.

Verder, als q constant is maak daar dan een parameter van, nu zit je een register te maken met (bijna) een vaste waarde erin, dat is zonde van je elementen (kost toch weer 32 LE's).

Een probleem wat er nu in ieder geval in zit is dat je str op 1 of op 0 zet bij elke kloktik. Dus zodra je de knop los laat gaat str weer op 0 en stopt ie met tellen. Daarnaast heb je als de teller op q staat done op 1 gezet, maar de teller niet stop gezet. De volgende kloktik gaat done dus gewoon weer op 0.

Ook zou je eigenlijk moeten debouncen bij knoppen maar in dit geval met de delay maakt het niet zo veel uit.

Ik zie ook niet helemaal wat je wilt, waar zit de LED nu aan vast? Je zet de led aan (1) in de reset? Of is de LED ook geïnverteerd. En wat moet done precies doen? Moet de LED aan blijven na die seconde? Dus reset is led uit, andere knop is led na een seconde aan?

Ik kan wel een goed voorbeeld geven als je even exact aangeeft wat de in en outputs van de module precies moeten doen.

Misschien als je heeeeeel goed kijkt kun je je LED na 1 seconde precies 1/27000000ste seconde lang aan zien zien springen.

Je kunt stoppen met tellen als done = 1, of je kunt > 27000000 gebruiken i.p.v ==.

Het is ook verstandig om in een synchroon ontwerp <= te gebruiken i.p.v. =, dus led <= 1 etc.

Veel verilog-plezier!

-> Ik zie dat madwizard sneller kan typen dan ik, zijn uitleg is waarschijnlijk iets leerzamer

[Bericht gewijzigd door Mr. Brown op (13%)]

Ik heb toch alvast een eigen versie gemaakt, misschien niet helemaal wat je bedoelde maar alsnog een goed voorbeeld. Ook voor anderen.

De volledige code

module leddelay
    (
        input clk,
        input res,
        input delay,
        output reg led
    );

parameter DELAY_COUNT = 10;

reg [31:0] counter;

wire counter_en = (counter == 0) ? !delay : (counter != DELAY_COUNT);

always @(posedge clk or negedge res) begin

    if (!res) begin
        led     <= 0;
        counter <= 0;
    end else begin
        led <= (counter == DELAY_COUNT);

        if (counter_en)
            counter <= counter + 1'b1;
    end

end

endmodule

Stap voor stap even doorlopen:

module leddelay
    (
        input clk,
        input res,
        input delay,
        output reg led
    );

Een klok, reset (hier res, maar reset is eigenlijk meer standaard) en delay input. Een LED als output en die is ook direct als register gedeclareerd.

parameter DELAY_COUNT = 10;

Een constante met de delay erin. Ik heb even 10 gebruikt omdat dat beter werkt in de simulatie, voor je ontwikkelbord natuurlijk hoger zetten. Een parameter constante is gewoon een alias voor een bepaalde waarde, en kost verder zelf geen ruimte in je chip.

reg [31:0] counter;

Een 32-bits teller. Veel te veel voor tellen tot 10 maar zo kun je even vooruit.

wire counter_en = (counter == 0) ? !delay : (counter != DELAY_COUNT);

Dit is een wire, counter_en. Een wire is een los signaal binnen de logica gestuurd door een of andere ouput. Het is geen register, het onthoudt de waarde niet maar verandert mee met de logica waar het afhankelijk van is. Deze wire geeft aan of de teller op dat moment aan of uit moet zijn (en = enable).
Het tellen werkt zo:
Als counter op 0 staat blijft deze op 0 staan, dit is de stop-stand. Maar zodra de delay input laag wordt gaat de counter aan en blijft deze aan tot DELAY_COUNT bereikt is. Dan blijft de counter weer hangen op DELAY_COUNT, totdat de counter gereset wordt. Als de counter eenmaal begonnen is met tellen (counter > 0) moet delay genegeerd worden, omdat je dan de knop weer kunt loslaten en de teller mooi doorgaat.

In de code wordt eerst (counter == 0) getest, of de counter in de stop-stand staat. Zoja, dan wordt counter_en gelijk aan !delay, zoniet, dan wordt counter_en gelijk aan (counter != DELAY_COUNT). Nogmaals dezelfde condities in detail:

Wel in de stopstand (counter == 0): counter aanzetten (counter_en = 1) als delay 0 is, anders counter uitzetten. Oftewel counter_en = !delay (omgekeerde van delay).

Niet in de stopstand (counter == 0): counter aanzetten als de eindstand (DELAY_COUNT) nog niet bereikt is. oftewel: counter_en = (counter != DELAY_COUNT).

Dit kun je trouwens ook gewoon met if statements doen, maar ik heb het zo gedaan om meteen wire mee te nemen als voorbeeld. Overigens is het wire x = y; een snellere variant van de twee statements: wire x; assign x = y;

always @(posedge clk or negedge res) begin

Zelfde als in jouw code, bij de clk edge gaan we steeds iets doen (synchrone logica) en bij een reset signaal ook (asynchrone reset).


    if (!res) begin
        led     <= 0;
        counter <= 0;
    end

Reset geval lijkt me duidelijk. Bedenk dat led en counter hier tegelijk geset worden! Niet achter elkaar zoals in software. Met '=' zou dat trouwens in dit geval ook gebeuren, maar nogmaals <= is het normale gebruik.


else begin
        led <= (counter == DELAY_COUNT);

Als we niet aan het resetten zijn, stellen we de LED in. Deze gaat simpelweg op 1 als de counter in z'n eindstand zit (DELAY_COUNT). De counter blijft daar op hangen dus de LED blijft aan als dat eenmaal bereikt is.


        if (counter_en)
            counter <= counter + 1'b1;

Als de counter enabled (counter_en) aan staat, moet de counter tellen en wordt er dus 1 bij opgeteld. Hoewel counter_en continu kan veranderen en dat ook doet wordt dankzij de synchrone logica (de posedge clk) de counter netjes 1 keer per kloktik opgehoogt, tenzij de counter_en op het moment van de positieve flank van de klok laag was.

Ook hier worden counter en led gelijk geset! Je kunt de hele if boven het led-statement zetten en dan heb je exact dezelfde situatie, zels als counter opgehoogd wordt is in die 'ronde' (tijdens die kloktik) counter altijd de oude waarde. Dit is met '=' niet het geval.


    end
end
endmodule

Spreekt voor zich.

Wat altijd interessant is is hoe dit zich in hardware vertaalt. Daarvoor is de RTL viewer handig:

http://www.uploadarchief.net/files/download/quartus_delay.png
Je ziet hier erg mooi hoe het werkt. De constante waarden bij de EQUAL (comparator) en ADDER blokken zijn niet zo goed leesbaar, maar linksboven is 1, linksonder 0 en rechts is 0xA (10 decimaal, de maximale teller waarde dus). Dit zijn constante waarden (hard gewired naar VCC of GND).

Linksonder zie je de inputs, helemaal rechts een register voor de LED output en de output zelf. Het enige andere register is de counter in het midden, van 32 bits.

De adder linksboven voegt 1 (B) toe aan de output van de counter op ingang A. Dit is je ophoging. De uitkomst gaat weer in de input van counter zodat deze de volgende kloktik overgenomen wordt.

Na de counter zit een comparator (rechts) die de huidige counter output vergelijkt met 10. De uitkomst gaat direct naar het LED register, dus als de counter op 10 staat wordt er 1 in het register gezet een gaat de LED aan.

Maar het ophogen moet natuurlijk niet op elke kloktik gebeuren. Vandaar dat er nog logica aan de enable input van counter hangt. Alleen als deze op 1 staat wordt de nieuwe counter waarde (vorige + 1) in het register gezet, en anders verandert er niets. Dit signaal is natuurlijk de counter_en die in de code gemaakt is.

De enable is de output van een multiplexer (mux, het kleine blokje). Deze multiplexer stuurt of ingang 0 door, of ingang 1, afhankelijk van zijn select input (het lijntje bovenin). Beide ingangen (0 en 1) zijn ook nog eens geïnverteerd (dit geven de kleine bolletjes aan), dus eigenlijk wordt de omgekeerde waarde meegegeven.

edit: in onderstaande stond een fout, is nu gefixt!

De select ingang van de mux (lijn boven) komt uit de comparator linksonder, die de counter waarde met 0 vergelijkt. Als de counter dus op 0 staat, wordt select 1, anders wordt select 0. Als select 0 is wordt ingang 0 van de mux gebruikt, en anders ingang 1.

Als de counter 0 is, is select 1 en gaat ingang 1 geïnverteerd door. Hierop staat simpelweg de delay input. Vanwege het inverteren wordt de ouput het omgekeerde, !delay dus.

Als de counter niet 0 is, is select 0 en gaat ingang 0 geïnverteerd door. Hierop staat de output van de comparator rechts (die vergelijkt met 10). Geïnverteerd betekent dit dat de uitgang van de mux 1 wordt als counter niet gelijk is aan 10, en 0 als counter gelijk is aan 10. Oftewel (counter != 10).

Als je dit allemaal samen bekijkt zie je:
Als counter == 0 (select = 1) dan output van mux is !delay
Als counter != 0 (select = 0) dan output van mux is (counter != 10).

Wat precies overeen komt met je code regel:

wire counter_en = (counter == 0) ? !delay : (counter != DELAY_COUNT);

Als laatste test dan natuurlijk nog een simulatie, eerst een kleine reset en dan even de delay knop indrukken (active low):
http://www.uploadarchief.net/files/download/quartus_sim.png

Zodra de knop laag wordt gaat de teller starten, je ziet ook goed dat de teller steeds wijzigt bij de positieve flank van de klok, en dat de waarde 'een achter loopt', wat dus het gevolg is van synchrone logica. Zodra delay laag is ga je namelijk tijdens die kloktik counter + 1 uitrekenen, maar de uitkomst wordt pas bij de volgende kloktik in het register geklokt.

Tot slot gaat de LED ook aan bij counter == 10, eigenlijk eentje te laat ook (zelfde reden) maar daar kun je voor corrigeren natuurlijk door de teller tot eentje minder te laten tellen.

Zo dat was een heel verhaal maar wel weer een mooi voorbeeld voor de beginners erbij denk ik.

EDIT!
Toch nog iets belangrijks vergeten, de delay input moet nog gesynchroniseerd worden, want die delay is asynchroon (komt van de knop af). Maak een reg delay_reg, zet in de always op de klok een delay_reg <= delay, en gebruik overal in je code delay_reg ipv delay zelf.

bedankt madwizzard :D

ik moet nog even omschakelen van C naar verilog :P
de delay werkt nu in ieder geval, en ik kan vooruit :)

je code is exact wat ik bedoelde. done was voor als de teller klaar was, en led voor als ik reset.

ik sanp in ieder gavel wat ik fout gedaan heb.

wat me trouwens opvalt is dat dit topic "eenvoudige voorbeelden" heet. Maar ik ben nu beginnen met FPGA, en ik snap geen reet van wat jullie doen :P Nog even dooroefenen dus

Groeten Rik

[Bericht gewijzigd door Rikkepic op (19%)]


module test (input key , output reg led);

`define count = 27000000
reg [16:0] counter;
reg        keyhit;

always @(posedge clk) begin
    counter <=count;
    if (key) keyhit <=1;
    if (keyhit) counter <= counter -1;
    if (counter ==0) begin
        keyhit <= 0;
        led    <= !led;
    end
endmodule

@ free electron: hoe gaat dit werken als je op elke clockpuls de counter opnieuw laadt met zijn begin waarde ?

Het feit dat je dit soort code kunt produceren vind ik een van de nadelen van Verilog, het werkt wel maar als je van huis uit C-programmeur bent zal het je in eerste instantie als onlogisch overkomen. Voordeel is dat het in sommige gevallen iets minder LE's kost.

De actie counter <= count; wordt niet uitgevoerd als er daarna nog counter <= counter - 1; komt, er wordt dan gewoon gebruik gemaakt van de voorgaande waarde van counter.
Dit principe is geloof ik al een aantal keren (heel wat beter) door FE uitgelegd, weet niet meer precies waar.

Daarom vindt ik het ook zoveel beter om gewoon met een if-elsif-elsif-else te werken. Dan zie je vele malen beter wat er gebeurt. Nu staan er maar een paar regels, maar als het echte code wordt, snapt niemand het meer, inclusief jezelf (na een paar maanden).

njet.

Verilog is zo geschreven vanaf dag 1. alle andere manieren zijn 'verzinsels' om het meer op software te laten gelijken. Verilog (en ook VHDL) is geen C !
je schrijft of software, of je beschrijft hardware.

Software technieken toepassen om hardware te maken is fout. Hier en daar kan je een en ander doen maar voor je het weet heb je een blok wat 10.000 poorten te groot is. vooral als je asics gaat maken ( en zeker in fpga waar 'real estate' beperkt is ) is dat van belang. Voor kleine projectjes of hobby maakt dat niks uit. Maar als je moet overstappen naar een grotere fpga , of je chip een halve millimeter groter maken hangt daar een serieus prijskaartje aan vast.

de bedoeling van die manier van werken is om je combinatorisch blok voor het register te krijgen en nooit een blok combinatorisch te verlaten. door de manier van schrijven weet je EXACT hoe de synthesizer de boel gaat in elkaar zetten. geen verassingen daar.

een afteller is niets anders dan het volgende



   ________________________________________
  |  __________               __________   |
  |_|          | resultaat   |          |__|___ uit
    |  - 1     |-------------| geheugen |
    |__________|             |          |
                        clk  |>_________|

wat doet de code die ik daar neerpoot nu :


    counter <=count;
    key <= key;
    if (key) keyhit <=1;
    if (keyhit) counter <= counter -1;
    if (counter ==0) begin
        keyhit <= 0;
        led    <= !led;
    end

we hebben een register 'counter' ( das geen teller die daar staat maar een geheugehn.
de synthesizer begint en maakt eerst dit :


                       ____________
        27000000 -----|            |
                      | geheugen   |--- uit
                      |  'counter' |
                      |____________|

ik heb even een lijntje ingevoegd 9strikt gezien moet dat daar niet staan. maar het is duidelijker om te snappen.

nu heeft ie een nieuw gehegen nodig 'key'. dat behoudt altijd zijn waarde.

dus we maken een nieuw blokje
merk op ik teken geen klokken. al die geheugens krijgen dezelfde klok aangeboden.


                       ____________
        27000000 -----|            |
                      | geheugen   |--- uit
                      |  'counter' |
                      |____________|

       _______________
      |   _________   |
      ---|D       q|---
         | 'keyhit'|
         |_________|

de volgende regel zegt dat als 'key' hoog is dat dan 'keyhit' ook hoog moet worden
dus de synthesizer injecteert een mulitplexer.


                       ____________
        27000000 -----|            |
                      | geheugen   |--- uit
                      |  'counter' |
                      |____________|

       ___________________
      |                   |
      |        _________  |
      ---|0\__|D       q|_|
      1--|1/  | 'keyhit'|
          |   |_________|
        key 


als key hoog is schakelt de multiplexer een '1' door naar 'key'. als key nul is schakelt de multiplexer de waarde van 'keyhit' door naar 'keyhit'.

de volgende regel zegt :

if keyhit : counter = counter -1;

dus : een extra multiplexertje aangestuurd door 'keyhit'


     _______________________________________
    |                         ____________  |
    |   27000000 ----|0\_____|            | |
    |            ----|1/     | geheugen   |-+- uit
    |            |    |      |  'counter' |
    --------[-1]-     |      |____________|
                      |
       _______________|___
      |                   |
      |        _________  |
      ---|0\__|D       q|_|
      1--|1/  | 'keyhit'|
          |   |_________|
        key 


de volgende regel zegt nu dat :

if (counter ==0) keyhit <= 0;

dus :


     _______________________________________
    |                         ____________  |
    |   27000000 ----|0\_____|            | |
    |            ----|1/     | geheugen   |-+- uit
    |            |    |      |  'counter' | |
    --------[-1]-     |      |____________| |
                      |                     |
                      |                   __|__
       _______________|__________        [_=0__|
      |                          |          |
      |              _________   |          | 
      ---|0\__ |0\___|D       q|_|          |
      1--|1/   |  |  | 'keyhit'|            | 
          |  0-|1/   |_________|            |
        key     |___________________________|


huppekee. ook aan die conditie is al voldaan.
dus als dat blok '=0' hoog wordt : zal 'keyhit' een nul laden , die zijn uitgong wordt nul waardoor de bovenste multiplexer afvalt en terug 2700000 gaat laden ....

waardoor de ingang vand at blok '=0' terug op 2700000 komt en de uitgang dus afvalt naar nul.

nu kunnen we nog de uitgang van dat blok '=0' aan een ander geheugen knopen wat zijn eigen laadt maar dan geinverteerd.

het leijkt een eigenaardiege manier van werken maar het maakt zeer compakte kleine logica die vooral uit multiplexers bestaat. en voor een synthesizer is er niks eenvoudiger dan multiplexers herleiden naard booleaanse vergelijkingen , die te minimaliseren en ze in gates duwen.
trouwens een fpga is niks anders dan een verzameling multiplexers ( een lookup table is niets anders dan een multiplexer in een voorgedefinieerd geheugen ) en registers.

dus je slaat meerdere vliegen in 1 klap. : je produceert gegarandeerd minimalistische code op gate level
: al je signalen zijn altijd gedefinieerd.
: je hebt zeer weineig tikwerk . al die genestte if then else if else toestanden zijn veel te warrig om te snappen wat het doet.

bovenstaande codeermethode leest als een schema.

enfin. iedereen is vrij van mij om te programmeren in zijn eigen stijl en de meeste synthesizers geraken er wel aan uit. ( soms niet al even goede maar toch )
en das het grote voordeel van verilog : je bent vrij om je eigen stijl te adopteren. ik geef alleen maar de technieken mee die ik nu ook aan het leren ben in die in grote designs continue toegepast worden.

VHDL is gemaakt door een ijzervretende duitser die al 2 maanden op een plank sliep en aan chronische verstopheid leed. veeel te rigide voor mij... geef mij maar een zacht kussen.. liefst een wat ik af en toe eens kan op-'fluffen'.

-edit- en nu maar hopen dat ze gene backup moeten terugplaatsen ...

'k moet zeggen dat ik ook blij ben dat mede Fotoopa en Free me hebben geinspireerd verilog te gaan gebruiken. Zo'n wereld van verschil met schema's bouwen, zo'n verschrikkelijke tijdwinst :)

'k heb inmiddels alle projecten voor het moederbordje omgezet naar verilog en alles werkt ook helemaal naar behoren. Ook altijd even naar het geproduceerde RTL schematic kijken wat de synth er van gemaakt heeft. Naast dat het leerzaam is, kun je ook zien of en hoe je nog dingen kan optimaliserenl

Ik ben weer onder de indruk van de verhelderende uitleg van Free. Ik moet toegeven ik kom uit een softwarehoek en daardoor ook snel geneigd om iets als software te lezen.
Maar ik zal mijn leven beteren en meer als hardware man gaan denken.
Nu maar hopen dat het boek van Free snel op de markt komt zodat ik een leidraad krijg om mij te transformeren naar die boeiende hardware.

@driessens,

Die '<=' moet je eigenlijk zo zien:

CNT <= 4555;

Dit betekent dat bij de volgende klokpuls CNT 4555 gaat worden. Maar CNT is dat op het moment dat 'ie door de code heen gaat, nog niet. Met <= geef je op wat het moet worden na de eerstvolgende clock puls. Vaak zet je boven in de routine op die manier neer wat de 'default' voor de registers moet zijn na de clock puls. Dan daarna met IF statements de defaults aanpassen waar nodig :)

Het '=' teken gebruik je alleen met assignments:

assign pinnetje = a && b;

Die waarde wordt er wel direct aan toegekend, hier maakt de compiler er een combinatorische schakeling van.

het wordt nog veel straffer als je modelsim gaat erbuiken in plaats van de ingebakken simulator.

je kan dan een testbench schrijven in verilog zelf. gedaan met golfvormpjes te tekekene. je kan zelfs subroutines ( tasks heet dat ) maken.

ik heb een redelijk complexe fpga nu ( systeem is pak em beet 18.000 LE's groot. met een data en adress bus. om daar iets mee te doen in de golfvorsimulator is dat een enorme ellende.

in verilog ? kippe-eitje... je maakt een tast die een register kan schrijven en ene die kan lezen. en dan doe je calls. in modelsim kan je zelfs breakpoints zetten in je testbench en je kan exact tracen waar je logica nu zit EN je kan signalen opleggen !.

modelsim heeft een redelijke instapdrempel maar als het goed uitgelegd wordt ben je er in een half uur mee op weg.

modelsim is gratis te downloaden bij altera ( een gelockte versie voor altera alleen. modelsim is een 'grote jongen'. al wat geberutd is is dat de maximum circuitgrottte gelimiteerd is tot altera devices ( je kunt er dus geen asic mee simuleren ) en ze staan op de rem. met andere woorden de simulatie is 'traag' ( nuja die sim van mij loopt 2 minuten en spuwt enkele tientallen megabyte 'dump'... ) met traag bedoelen ze : 1 minuut tot 10 minuten voor iets wat op de 'grote modelsim' 10 seconden duurt... nuja. dat ding kost boven de 12K$ ... voor 1 licentie.... op het werk hebben we een 'farm' met een 40 tal licenties op.

enfin , ter zake.

download modelsim ( web editon ) en vraag de key aan bij altera 9 zelfde procudure als quartus key.

qooi die file ergens neer waar je hem kan vinden en geef hem een korte naam.

je moet nu een systeemvariable toevoegen. als je modelsim de eerste keer start krijg je ene licece error.
die error box geeft je de namen van de environment parameters die je moet zetten.

klik met rechtermuistoets op 'my computer' en kies properties. ga naar advanced en dan environment variables. je krijgt nieuw venstertje. bovenste deel is user onderste deel is all users. daar moet ie ( bij all users )

creat new.

de naam is wat je ziet in modelsim venstertje, tweede regel is locatie van de licece file

bijvoorbeeld :
MGLS_LICENCE_FILE
c:\licences\modelsim.dat

klik ok en sluit al die venstertjes.
modelsim zal nu starten.

een voorbeeldje met testench:



module counter (input clk,reset, output reg [7:0] out);
always @(posedge clk)
    if (reset)  out <=0;
    else        out <=out+1;
endmodule

voila . een stomme teller.
nu maken we een testbench :



module;  // niks hier 

reg  klok,reset     // alles wat draden zijn in module wordne hier registers
wire [7:0] teller // alles wat registers zijn worden hier draden.

// registers worden in de testbench gebruik om iets te 'sturen'
// draden (wire) zijn onze 'meetprobes'

// nu gaan we onze module aanroepen
counter mijn_counter (
                     .clk(klok)
                     .reset(reset)
                     .out(teller) );

de syntax bovenaan leest als volgt :
ik heb een instantie van module 'counter' nodig en zal
die 'mijn_counter' noemen.
de knoop .clk van 'counter' wordt verbonden met mijn
'klok' . de knoop .reset worde verbondne met mijn reset
en de knoop .out wordt verbonden met mijn 'teller'.

nu hebbe we ene klok nodig die loopt



always begin
    #10
    klok <= !klok;
end

// bovenstaande zegt : wacht 10 'ticks' en kip dan 'klok' 
// om ( laadt 'klok' met zijn inverse )

/ het # teken geeft een vertraging aan. die vertraging 
// moeten we definieren : ze thelemaal bovenaan de file

`timescale  1 nS / 100 pS

opgelet !!!! dat ` symbool is GEEN afkappingsteken. ik
heb mezelf daar laten aan vangen . goed kijken :
dit is afkappings teken : '
dit is 'backtick' : `

de 'backtik' zit op ene amerikaans toetsenbord helemaal
linksboven ( war de 'tilde' (~) staat
op ene europees heb ik geen flauw idee. ik weet allen dat
<ALT> 96 de juiste is ... (dus <ALT> knop inhouden en op
numeriek klavier 96 kloppen en dan alt key lossen en je
hebt em.

de tijdschaal is ingesteld als ; 1 nanoseconde per 'tick'. de simulator zoekt in een 100 picseonde vester naar veranderingen. voor een naakte simulatie maakt dat getal iks uit. als je later gaat simuleren met echte logica ( logcia die delays heeft ) maakt het wel uit. de simulaator zoekt dan in stappen van 100 picoseconde wanneer een bepaalde uitgang precies omkipt. hoe groter het verschil tussne de twee getalen hoe trager je simulatie loopt ( je drijft de timing precisie op )

nu is het tijd om de boel te inititaliseren



initial begin

   clk = 0;  // klok op nu merk op : we gebruiken = en geen <= !!!
   reset = 0; // reset op nul
   @(negedge klok)   reset = 1;  // wacht op ene daende flank en zet dan reset hoog
   @(negedge klok)    reset =0; // wacht opniew op dalende flank en maak reset laag.
   
   repeat (10) begin
      @(negedge klok)  reset = 0; // doet niks maar ik wahct op een negedge van klok
   end
  $display ("t'is gedaan")
  $stop
end
endmodule

die repeat functie voert het blok tussen begin en end 10 keer uit. ik schrijf geoon nul naar reset. maakt niks uit. reset was al nul.
en dan toon ik 'tis gedaan' en de boel stopt.

je MOET opgeven waar de boel stopt. ander blijft de simulator gewoon doorlopen. ( je hebt immers een always block wat de klok genereert. dat blijft draaien want het was als 'always' gedefinieerd. het is niet omdat jij niks meer doet dat dat ding ook moet stoppen !.

bon eenmaal je dat hebt.

maak een nieuw project aan in modelsim en laadt de twee files. je file met de module in en je testbench file.

klik bovenaan op 'compile' als alles goed is krijg je 2 checks. bij vauten kluert de boel rood. door te dubbelklikken op de rode tekst krijg je info over wat er waar mis is.
eenmaal de boel correct is heeft modelsim je systeem vertaal din ene 'programma' wat door de simulatie motor kan gelopen worden.

klik op simulate - start simulation. dit start de aansturing van de motor. ( het start nog niet de motoro , alleen de aanstring ervan.
je krijgt een nieuw venster wat uit 3 luiken bestaat.

oeps vergeten . er komt eerst een venstertje wat vraagt wat je precies wil starten. he t bovenste it em s 'work'. open dat en klik daar je testbench file aan ( niet je module , maar de testbench file ! ) en klik ok.

dan krijg je dat venster met drie luiken.

het links heb je niet nodig.
het middenste ( pruper ding ) toont al je signalen. klik daar met de rechter muistoets en kies wave - show all.
die voegt al de signalen toe aan de wave viewer.
in de waveveiwer kan je nu de radix gaan instellen en dergelijke. ( hex decimaal binair etc )

enmaal je instellingen goed zijn klik je linksboven op save. dit savet een '.do' file. later kan je die terugroepen en je simulatie motor komt exact terug zoals ie nu staat. ( dit is een TCL script .. )

rest alleen nog de motor te sarten : klik simulate - run - run all.

en huppekee de boel draait.
als de $stop bereikt wordt zal je je testench source zien met een pijl die daar staat.

onder je codevenster staat er tabs. je waveviewer zit daar verborgen. klik op dat tabje en je hebt de golfvormen.

voila. modelsim in een notedop.

ik zal proberen een dit weekend nog een module en testbench van iets complexer ( een teler die weg en weer wandelt tussen twee eindpunten. ) zodat ik tasks kan tonen. dan komt de kracht van dat ding naar boven.

en nu : eerst shoppen anders wordt het kinnekloppen ( frigo is leeg )

Jee, en ik maar denken dat iedereen dat hier al op deze manier deed! (dus met testbench). Hoe kun je in hemelsnaam iets ontwerpen zonder een goede testbench?! Da's regel 1 van het FPGA designen. Oh nee, da's regel 2, regel 1 is "Leer VHDL" :p

quartus heeft een ingebouwde simulator waar je waveforms kan opleggen. dus zo kan je simmen.

voor complexe systemen moet je modelsim loslaten en daar ene testbench schrijven.

om kleine moduletjes te simmen volstaat de simulator in quartus. voor grote systemen kan je niet anders dan ene testbench bouwen ( of het effectief in ene fpga zetten en een logic analyser eraan hangen. sommige blokken doe ik zo. zelfs met ene testbench is het soms moeilijk. je krijgt daar een enorme wavedump en dan kan je gaan zien of het werkt. bijvoorbeeld een niet lineaire pwm
generator . duw dat in de fpga en zet er de scoop op. veeeeeel sneller dan dat verifieren op modelsim.

heel vele blokken in het project waar ik nu aan werk zijn op hun eigen uitgetest met waves. grote blokken zijn doorgemeten op scope en logic analyser. andere blokken zijn met testbenches gedaan. toplevel is nooit doorgesimd. het is sneller om gewoon het stuurprograma te schrijven op de pc en de boel uit te testen op bord.

[Bericht gewijzigd door free_electron op (20%)]

Jij designed blijkbaar op een heel andere manier dan ik. Simuleren zonder testbench zie ik hooguit als een hobby oplossing. Wat als je een kleine wijziging in je blok maakt? Kun je weer opnieuw je stimuli aan gaan bieden, handmatig. En handmatig checken in de waves of het klopt. Da's toch geen professionele aanpak? Een beetje testbench hoort self-checking te zijn. Dat kan bv door een model in de testbench te hebben die checked of de output correct is. Of een model die dezelfde functie heeft dan je design. Beide outputs moeten gelijk zijn.
En ehm, hoe garandeer je dat alles ok is als je op de LSA kijkt naar je pwm? Beetje op het oog? In je simulator kun je _exact_ controlleren of het klopt.
Kortom, ik doe niks zonder testbench. Zou ik ook iedereen adviseren om gelijk bij je design een tb te maken. Dat levert als snel veel tijd op.