1// Literatur:
2// Vorlesungsunterlagen AMV von Rainer Findenig (FH-Hagenberg)
3// Doulos - http://www.doulos.com/knowhow/sysverilog/
4// ASIC World - http://www.asic-world.com/systemverilog/tutorial.html
5// ElectroSofts - http://electrosofts.com/systemverilog/
6
7// HDVL - Hardware Description and Verification Language
8// Erweiterung zu Verilog
9
10
11// Definition von Packages
12// -> globale bzw. Projektspezifische Definitionen und Parameter
13 package global;
14 parameter DATA_WIDTH = 8;
15 parameter ADDR_WIDTH = 8;
16 parameter END_ADDRESS = (2**ADDR_WIDTH) - 1;
17
18 parameter DEAKTIVATED = 0;
19 parameter AKTIVATED = 1;
20
21 parameter CLOCK_PERIOD = 10ns;
22 endpackage
23
24
25// den Namensraum verfuegbar machen
26 import global::*;
27// Datei includieren
28 `include "ram-bh.sv"
29
30
31// verschiedene Module (Architekturen)
32 module RAM # (
33 // Paramter Liste
34 parameter int gDataWidth = 32;
35 parameter int gAddrWidth = 8
36 )
37 (
38 // Port Liste
39 input logic clk_i;
40 input logic rst_i;
41 input logic [gDataWidth-1 : 0] dat_i;
42 input logic [gAddrWidth-1 : 0] adr_i;
43 input logic we_i;
44 output logic [gDataWidth-1 : 0] dat_o
45 );
46 logic [gDataWidth-1 : 0] storage [2**gAddrWidth-1 : 0];
47
48 // Prozess wird zu Begin einmal aufgerufen
49 initial begin
50 storage[0] = '0;
51 storage[1] = '0;
52 ...
53 end
54
55 // Prozess existiert immer und wird bei den Events aufgerufen
56 always @(posedge clk_i or rst_i)
57 begin
58 ...
59 end
60 endmodule
61
62 module top ();
63 logic clk = 0;
64 logic rst = AKTIVATED;
65 ...
66
67 initial begin
68 #0ns rst = AKTIVATED;
69 #1ns rst = DEAKTIVATED;
70 end
71
72 always #CLOCK_PERIOD clk = ~clk;
73
74 // Ram Instantiieren
75 RAM # (.gDataWidth (DATA_WIDTH),
76 .gAddrWidth (ADDR_WIDTH)
77 )
78 duv(.clk_i (clk),
79 .rst_i (rst),
80 .dat_i (datM),
81 .adr_i (adr),
82 .we_i (we),
83 .dat_o (datS)
84 );
85 endmodule
86
87 // eigenes Modul-Konstrukt fuer die Testbench
88 program ram_tb ();
89 // nur initial begin Bloecke
90 initial begin : stimuli
91 // koennen aber endlos Schleifen haben
92 end : stimuli
93 endprogram
94
95
96// Basisdatentypen
97 // 4-state-logic (0, 1, X, Z)
98 reg clk = 0; // user-defined size
99 logic // identical to reg in every way
100 // logic [7:0] a_byte;
101 integer // 32 bits, signed
102
103 // 2-state-logic (0, 1) -> Simulationszeit verringert sich
104 bit // user-defined size
105 byte // 8 bits, signed
106 shortint // 16 bits, signed
107 int // 32 bits, signed
108 longint // 64 bits, signed
109
110 time // 64-bit, unsigned
111 shortreal // like float in C
112 real // like double in C
113 realtime //identical to real
114
115
116// Typdefinitionen und Enumerationen
117 typedef bit [7 : 0] data_v;
118 data_v data;
119
120 enum { circle, ellipse, freeform } c;
121 enum bit [3:0] {bronze=0, silver, gold} newMedal;
122
123 typedef enum {Idel = 0, StartBit, Data, Parity, StopBit} aState;
124 aState s = Idle;
125 case(s)
126 Idle:
127 ...
128 endcase
129
130
131// Arraydefinitionen
132 // packed arrays, festgelegte Darstellung als Bitstrom
133 bit [7 : 0] data;
134
135 // unpacked arrays, Werkzeug kann Abbildung frei waehlen
136 bit data [7 : 0];
137
138 bit [7 : 0] data_list [4] // [0:3]
139 // z.B. data_list[0] xxxxxxxx 76543210
140 // data_list[1] xxxxxxxx 76543210
141 // data_list[2] xxxxxxxx 76543210
142 // data_list[3] xxxxxxxx 76543210
143
144 // dynamische Arrays (nur unpacked, aufsteigend Indiziert)
145 bit a1[], a2[]; // zwei leere Arrays
146 a1 = new[10]; // Array anlegen
147 a2 = a1; // Array kopieren
148 a2 = new[a2.size*2](a2); // a2 Groesse verdoppeln
149 a1 = new[5]; // neues Array anlegen
150 // (-> Garbage Collector)
151 a1.delete; // Array loeschen
152
153 // packed <-> unpacked (Bit-stream cast)
154 typedef bit [0 : 7] data_v;
155 data_v packed;
156 bit unpacked [8];
157 packed = data_v'(unpacked); // unpacked -> packed
158
159 // packed <-> unpacked (Streaming operators)
160 int a[2], b1, b2;
161 bit [64:1] x = { >> {a}}; // pack a left-to-right
162 bit [63:0] x = { << {a}}; // pack a bit reverse
163 bit [0:63] x = { >> {b1, b2}}; // pack b1, b2
164
165 { << { 8'b0011_0101 }} // bit reverse -> 1010_1100
166 { << 4 { 6'b11_0101 }} // 0101_11
167 { >> 4 { 6'b11_0101 }} // 1101_01
168
169 // linke Seite kuerzer als rechte: Fehler
170 // rechte Seite kuerzer als linke: linksbuendig, mit 0 gefuellt
171
172 // Streams nicht direkt als Wert verwendbar -> Cast notwendig
173 typedef bit [0 : 7] data_v;
174 data_v data;
175 bit ret[8];
176 assert (data == data_v'({ >> {ret}}))
177
178 // Array durchlaufen
179 int a[] = new[100];
180 foreach (a[i])
181 a[i] = i;
182
183 a = '0; // Array mit 0 fuellen
184 a = '1;
185 a = 'z;
186 a = 'x;
187
188
189// Strukturen und Unions (aehnlich zu C)
190 struct {
191 int x, y;
192 } p;
193 p.x = 1;
194 p = { 1,2 };
195
196 typedef struct packed {
197 int x, y;
198 } Point;
199 Point p;
200
201
202// Zuweisungen
203 // non-blocking Assignment: Zuweisung im naechsten "Delta-Cycle"
204 always @(posedge clk) begin
205 A <= A + 1;
206 B <= A; // B bekommt alten Zustand von A
207 end
208
209 // blocking Assignment: Zuweisung sofort
210 always @(posedge clk) begin
211 A = A + 1;
212 B = A; // B bekommt neuen Zustand von A
213 end
214
215
216// Operatoren
217 //Type Symbol Operation
218 // Arithmetik * Multiplizieren
219 // / Dividieren
220 // + Addieren
221 // - Subtrahieren
222 // % Modulo
223 // + unaer Plus
224 // - unaer minus
225 // Logik ! logische Negation
226 // && logisches Und
227 // || logisches Oder
228 // Vergleich > groeser
229 // < kleiner
230 // >= groeser gleich
231 // <= kleiner gleich
232 // Gleichheit == gleich
233 // != ungleich
234 // Bit ~ bitweise Negation
235 // ~& nand
236 // | or
237 // ~| nor
238 // ^ xor
239 // ^~ xnor
240 // ~^ xnor
241 // Shift >> right shift
242 // << left shift
243 // Verkettung { } Concatenation
244 // Bedingung ? Conditional
245
246
247// Schleifen und Bedingungen
248 // IF
249 if (Cond1)
250 doSomething1();
251 else if (Cond2)
252 doSomething2();
253 else
254 doSomething3();
255
256 if (Cond)
257 begin
258 doSomething1(); // werden mehrere Zeilen benoetigt,
259 doSomething2(); // so braucht man einen begin-end-Block
260 end
261
262 // DO-WHILE
263 do
264 ...
265 while(Cond);
266
267 // WHILE
268 while (Cond) begin
269 ...
270 end
271
272 // FOR
273 for (int i=15, logic j=0; i>0; i--,j=~j)
274 ...
275
276 // CASE
277 case(address)
278 0 : $display ("Adresse = 0");
279 1 :
280 begin
281 $display ("Adresse = 1");
282 $display ("weitere Zeile");
283 end
284 default : $display ("default Zweig");
285 endcase
286
287 // REPEAT
288 repeat (16) begin
289 ...
290 end
291
292
293// Ueberschriften
294 begin : label
295 end : label
296
297 module myModule ...
298 ...
299 endmodule : myModule
300
301 loop : for (...)
302
303
304// Ausgaben
305 // Syntax aehnlich zu "printf"
306 $display("@%t: data = %0d", $time, data);
307 $write();
308 $time // aktuelle Simulationszeit
309 $finish // Simulation beenden
310
311 string sv = "SystemVerilog";
312 string s;
313 s = {sv, " ", "ist echt einfach."};
314 $display ("%s\n", s); // Bildschirmausgabe:
315 // "SystemVerilog ist echt einfach."
316
317
318
319// Assertions
320 assert (A == B); // wenn A!=B wird ein Fehler ausgegeben
321 assert (A == B) $display ("OK. A gleich B");
322 assert (A == B) $display ("OK. A gleich B");
323 else $error("Fehler: A ungleich B");
324 assert (A == B) else $error("Fehler: A ungleich B");
325
326
327// Timing-Kontrolle
328 wait (cond); // level-sensitive
329 // -> warte, bis cond wahr ist
330 @(posedge clk); // warte auf steigende Flanke von clk
331 repeat (2) @(negedge clk); // warte 2x auf negative Flanke von clk
332 @(sig); // warte, bis sich sig aendert
333 @(posedge clk, rst) == @(posedge clk or rst)
334 #1ns rst = 0; // 1e ns warten, danach rst auf 0 setzen
335 ##1 rst = 0; // 1en Clock Zyklus warten
336 wait(0); // endlos Warten
337
338
339// Function vs. Task
340 // fuer Berechnungen (passieren in Nullzeit)
341 function int calcCrc(input int data0 = '0, data1);
342 ...
343 calcCrc = 0;
344 ...
345 return crc; // return ueberschreibt calcCrc Wert
346 endfunction
347 res = calcCrc(.data0(d0), .data1(d1));
348 res = calcCrc(d0, d1); // Reihenfolge wird beachtet
349
350 // koennen Zeit verbrauchen
351 task waitForClk(input int data_i, output int data_o);
352 ...
353 @(posedge clk);
354 endtask
355
356
357// Clocking Block - beschreibt wie die Eingaenge und Ausgaenge
358// gesampled und synchronisiert werden
359 clocking clock1 @(posedge clk1);
360 default input #2ns // default input skew
361 output #3ns; // default output skew
362 input a1, a2;
363 input #1 a3; // eigens spezifizierte input skew
364 output b1;
365 output #1 b2; // eigens spezifizierte output skew
366 endclocking
367
368
369
370
371// Interfaces - fuer gemeinsame Schnittstellen
372 interface wishboneBusIf(input logic clk, rst);
373 logic ack, stb, cyc, we;
374 logic [DATA_WIDTH-1 : 0] datM, datS;
375 logic [ADDR_WIDTH-1 : 0] adr;
376 logic [DATA_WIDTH/8-1 : 0] sel;
377
378 clocking cb @(posedge clk, rst);
379 input ack, datS;
380 output stb, cyc, we, datM, adr, sel;
381 endclocking
382
383 modport master(clocking cb);
384 modport slave(
385 input stb,
386 input cyc,
387 input we,
388 input datM,
389 input adr,
390 input sel,
391 output ack,
392 output datS
393 );
394 endinterface
395
396 program wishbone_tb (
397 wishboneBus_if wishboneBus
398 );
399 wishboneBus.clk;
400 wishboneBus.master.cb.ack;
401 endprogram
402
403 RAM duv (
404 .clk_i (wishboneBus.clk),
405 .rst_i (wishboneBus.rst),
406 .adr_i (wishboneBus.slave.adr),
407 .dat_i (wishboneBus.slave.datM),
408 ...
409 .ack_o (wishboneBus.slave.ack)
410 );
411
412
413// OOP - Klassen
414 class wishboneBFM_c;
415 // Interfaces muessen in Klassen immer virtuell sein,
416 // damit die Aenderungen nach aussen sichtbar werden
417 virtual wishboneBus_if wishboneBus;
418 logic [ADDR_WIDTH-1 : 0] actAddr;
419 local logic mem1; // private Members
420 protected logic mem2; // protected Members
421
422 // CTor, nur einer erlaubt
423 function new(virtual wishboneBus_if wishboneBus);
424 this.wishboneBus = wishboneBus;
425 endfunction
426
427 task busWrite(input logic [ADDR_WIDTH-1 : 0] addr,
428 input logic [DATA_WIDTH-1 : 0] data);
429 wishboneBus.cpM.stb <= 0;
430 wishboneBus.cpM.cyc <= 0;
431
432 @(posedge wishboneBus.clk)
433 wishboneBus.cpM.adr <= addr;
434 wishboneBus.cpM.datM <= data;
435 wishboneBus.cpM.we <= 1;
436 wishboneBus.cpM.sel <= '0;
437 wishboneBus.cpM.stb <= 1;
438 wishboneBus.cpM.cyc <= 1;
439 do
440 @(posedge wishboneBus.clk);
441 while(!wishboneBus.cpM.ack);
442 wishboneBus.cpM.stb <= 0;
443 wishboneBus.cpM.cyc <= 0;
444 endtask : busWrite
445
446 function bit [15 : 0] calcCrc;
447 ...
448 return crc;
449 endfunction
450 endclass
451
452 wishboneBFM_c bfm = new(...);
453 bfm.busWrite(...);
454 int crc = bfm.calcCrc();
455
456
457 // Parametrisierte Klasse
458 class #(parameter int N = 1) Register;
459 bit [N-1:0] data;
460 ...
461 endclass
462
463 Register #(4) R4; // data ist bit [3:0]
464 Register #(.N(8)) R8 // data ist bit [7:0]
465 Register R; // data ist bit [0:0]
466
467
468 // Ableiten
469 class ShiftRegister extends Register;
470 task shiftleft; data = data << 1; endtask
471 task shiftright; data = data >> 1; endtask
472 endclass
473
474
475 // virtuelle Klassen
476 virtual class Register;
477 ...
478 endclass
479
480
481// Automatic Storage
482 // wird eine Funktion bzw. ein Task mehrmals aufgerufen,
483 // so muss die Wiedereintrittsfaehigkeit gegeben sein
484
485 // in Verilog wurden Parameter statisch allokiert
486 // -> mittels automatic Starge auf Stack legen
487 program automatic Test(...);
488 task automatic doIt();
489 ...
490 endtask
491 ...
492 endprogram
493
494 // Methoden in Klassen sind immer automatic
495
496
497// gleichzeiteige Prozesse
498 type_of_block @(sensitivity_list)
499 fork
500 statement1; // zwei parallele Statements
501 statement2;
502 ...
503 join
504
505 fork
506 begin
507 statement1; // 1 Prozess mit zwei Statements
508 statement2;
509 ...
510 end
511 join
512
513 // join ... der Eltern-Prozess blockiert solange
514 // bis alle fork-Prozesse fertig sind
515 // join_any ... der Eltern-Prozess blockiert solange
516 // bis ein fork-Prozess fertig ist
517 // join_none ... der Eltern-Prozess setzt seine
518 // Abarbeitung ohne Warten fort
519
520
521// Events
522 program tb (...);
523 event e;
524
525 initial begin : doIt
526 #1ns -> e;
527 #2ns -> e;
528 end : doIt
529
530 initial begin : waitForEvent
531 do
532 begin
533 wait( executeModellEvent.triggered );
534
535 $display ("@%0t -> executeModellEvent (cmd: %0d)",
536 $time, opcodeCnt+1);
537 #1ns;
538 end
539 while(1);
540 end : waitForEvent
541 endprogram
542
543 // -> ... triggert ein Event
544 // ->> ... triggert ein Event non-blocking
545 @(event); // wartet auf ein Event
546 wait(event.triggered); // -,,-
547 wait_order(a, b, c); // wartet auf Events nach bestimmten
548 // Reihenfolge: zuerst a, dann b, dann c