๐Ÿš€ SystemVerilog ํ…Œ์ŠคํŠธ๋ฒค์น˜ ์™„๋ฒฝ ๊ฐ€์ด๋“œ

SystemVerilog ํ…Œ์ŠคํŠธ๋ฒค์น˜ ์™„๋ฒฝ ๊ฐ€์ด๋“œ: Verilog๋ฅผ ๋„˜์–ด์„œ

๐Ÿš€ SystemVerilog ํ…Œ์ŠคํŠธ๋ฒค์น˜ ์™„๋ฒฝ ๊ฐ€์ด๋“œ

Verilog๋ฅผ ๋„˜์–ด์„œ — ํ˜„๋Œ€์  ๊ฒ€์ฆ ํ™˜๊ฒฝ ๊ตฌ์ถ•์„ ์œ„ํ•œ ํ•„์ˆ˜ ๊ธฐ๋Šฅ ์ด์ •๋ฆฌ

Verilog๋งŒ์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฒค์น˜๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ๊ณ„์‹ ๊ฐ€์š”? SystemVerilog๋Š” OOP, ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ, ๋žœ๋ค ๊ฒ€์ฆ, Assertion ๋“ฑ ํ˜„๋Œ€์  ๊ฒ€์ฆ์— ํ•„์ˆ˜์ ์ธ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” ๊ฐ ๊ธฐ๋Šฅ์˜ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹ค์ „ ์ฝ”๋“œ ์˜ˆ์ œ๊นŒ์ง€, ํ…Œ์ŠคํŠธ๋ฒค์น˜ ์ž‘์„ฑ์— ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ์„ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

⚡ 1. Verilog vs SystemVerilog

๋จผ์ € Verilog์™€ SystemVerilog์˜ ์ฃผ์š” ์ฐจ์ด์ ์„ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋Šฅ Verilog SystemVerilog
๋ณ‘๋ ฌ ์‹คํ–‰ ์ œํ•œ์  (always๋งŒ) fork-join, join_any, join_none
OOP ❌ ์—†์Œ ✅ class, ์ƒ์†, ๋‹คํ˜•์„ฑ
๋žœ๋คํ™” $random๋งŒ rand, constraint, randomize()
๋ฐ์ดํ„ฐ ํƒ€์ž… reg, wire, integer logic, bit, enum, struct, queue
Assertion ❌ ์—†์Œ ✅ SVA (property, assert)
Coverage ❌ ์—†์Œ ✅ covergroup, coverpoint
IPC ❌ ์—†์Œ ✅ mailbox, semaphore
Interface ❌ ์—†์Œ ✅ interface, modport

๐Ÿ”€ 2. fork-join ๋ณ‘๋ ฌ ์‹คํ–‰

๐Ÿ”€ Concurrent Execution

fork-join์€ ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋™์‹œ์— ์‹คํ–‰ํ•˜๊ณ  ๋™๊ธฐํ™”ํ•˜๋Š” ๊ตฌ๋ฌธ์ž…๋‹ˆ๋‹ค.

์„ธ ๊ฐ€์ง€ ๋ณ€ํ˜•

๊ตฌ๋ฌธ ๋™์ž‘ ์‚ฌ์šฉ ์‹œ์ 
join ๋ชจ๋“  ํ”„๋กœ์„ธ์Šค ์™„๋ฃŒ ๋Œ€๊ธฐ ๋ชจ๋“  ์ž‘์—… ์™„๋ฃŒ ํ•„์š”
join_any ํ•˜๋‚˜๋ผ๋„ ์™„๋ฃŒ๋˜๋ฉด ์ง„ํ–‰ ํƒ€์ž„์•„์›ƒ, ๊ฒฝ์Ÿ ์กฐ๊ฑด
join_none ๋Œ€๊ธฐ ์—†์ด ์ฆ‰์‹œ ์ง„ํ–‰ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ชจ๋‹ˆํ„ฐ๋ง
๐Ÿ“Š fork-join ์‹คํ–‰ ๋‹ค์ด์–ด๊ทธ๋žจ Time → 0 10 20 30 40 50 60 │ │ │ │ │ │ │ Main ●━━━━━fork━━━━━━━━━━━━━━━━━━━━━━join━━━━● │ │ Thread 1 ├─────████████████████──────┤ (30 units) Thread 2 ├─────████████────────────────┤ (15 units) Thread 3 ├─────████████████████████──┤ (40 units) │ │ └──────────────────────────────┘ join: ๋ชจ๋“  ์™„๋ฃŒ ๋Œ€๊ธฐ join_any: Thread 2 ์™„๋ฃŒ(15) ์‹œ์ ์— ์ง„ํ–‰ join_none: fork ์งํ›„ ์ฆ‰์‹œ ์ง„ํ–‰
๐Ÿ“„ SystemVerilog: fork-join ์˜ˆ์ œ
initial begin $display("[%0t] Start", $time); fork // Thread 1: ๋“œ๋ผ์ด๋ฒ„ begin #20; $display("[%0t] Driver done", $time); end // Thread 2: ๋ชจ๋‹ˆํ„ฐ begin #10; $display("[%0t] Monitor done", $time); end // Thread 3: ํƒ€์ž„์•„์›ƒ begin #100; $display("[%0t] Timeout!", $time); end join_any // ์ฒซ ๋ฒˆ์งธ ์™„๋ฃŒ ์‹œ ์ง„ํ–‰ (Monitor @ 10) disable fork; // ๋‚˜๋จธ์ง€ ์Šค๋ ˆ๋“œ ์ข…๋ฃŒ! $display("[%0t] All threads terminated", $time); end
⚠️ disable fork ์ฃผ์˜

disable fork๋Š” ํ˜„์žฌ ์Šค์ฝ”ํ”„์˜ ๋ชจ๋“  ์ž์‹ ์Šค๋ ˆ๋“œ๋ฅผ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.
์˜๋„์น˜ ์•Š์€ ์ข…๋ฃŒ๋ฅผ ํ”ผํ•˜๋ ค๋ฉด fork...join์„ ๋ณ„๋„ task๋กœ ๊ฐ์‹ธ์„ธ์š”.

๐ŸŽฏ 3. OOP (ํด๋ž˜์Šค์™€ ๊ฐ์ฒด)

๐ŸŽฏ Object-Oriented Programming

SystemVerilog์˜ ํด๋ž˜์Šค๋Š” ๊ฒ€์ฆ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌ์กฐํ™”ํ•˜๋Š” ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค.

๐Ÿ“Œ OOP ํ•ต์‹ฌ ๊ฐœ๋…

• ์บก์Аํ™”: ๋ฐ์ดํ„ฐ์™€ ๋ฉ”์†Œ๋“œ๋ฅผ ํ•˜๋‚˜์˜ ๋‹จ์œ„๋กœ ๋ฌถ์Œ
• ์ƒ์†: ๊ธฐ์กด ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•˜์—ฌ ์ƒˆ ํด๋ž˜์Šค ์ƒ์„ฑ
• ๋‹คํ˜•์„ฑ: virtual ํ•จ์ˆ˜๋กœ ๋Ÿฐํƒ€์ž„ ๋™์ž‘ ๊ฒฐ์ •
• ์žฌ์‚ฌ์šฉ: ํ•œ๋ฒˆ ์ž‘์„ฑํ•œ ํด๋ž˜์Šค๋ฅผ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์‚ฌ์šฉ

๐Ÿ“„ SystemVerilog: Transaction ํด๋ž˜์Šค
class Transaction; // ํ”„๋กœํผํ‹ฐ (๋ฐ์ดํ„ฐ ๋ฉค๋ฒ„) typedef enum { READ, WRITE, IDLE } op_type; rand op_type opcode; rand bit [7:0] addr; rand bit [31:0] data; // ์ œ์•ฝ์กฐ๊ฑด constraint c_addr { addr inside {[8'h00:8'h7F]}; // ์œ ํšจ ์ฃผ์†Œ ๋ฒ”์œ„ } // ์ƒ์„ฑ์ž function new(string name = "Transaction"); this.name = name; endfunction // ๋ฉ”์†Œ๋“œ virtual function void print(); $display("[%s] op=%s addr=0x%h data=0x%h", name, opcode.name(), addr, data); endfunction // ๋ณต์‚ฌ ๋ฉ”์†Œ๋“œ virtual function Transaction copy(); Transaction t = new(); t.opcode = this.opcode; t.addr = this.addr; t.data = this.data; return t; endfunction local string name; endclass

์ƒ์† ์˜ˆ์ œ

๐Ÿ“„ SystemVerilog: ํด๋ž˜์Šค ์ƒ์†
// ๊ธฐ๋ณธ ํด๋ž˜์Šค ์ƒ์† class BurstTransaction extends Transaction; rand int burst_len; constraint c_burst { burst_len inside {[1:16]}; } // ๋ถ€๋ชจ ๋ฉ”์†Œ๋“œ ์˜ค๋ฒ„๋ผ์ด๋“œ virtual function void print(); super.print(); // ๋ถ€๋ชจ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ $display(" burst_len=%0d", burst_len); endfunction endclass // ์‚ฌ์šฉ ์˜ˆ initial begin Transaction tr; BurstTransaction btr = new(); btr.randomize(); btr.print(); // ๋‹คํ˜•์„ฑ: ๋ถ€๋ชจ ํƒ€์ž… ๋ณ€์ˆ˜์— ์ž์‹ ๊ฐ์ฒด ํ• ๋‹น tr = btr; tr.print(); // BurstTransaction์˜ print() ํ˜ธ์ถœ! end

๐Ÿ“Š 4. ๊ณ ๊ธ‰ ๋ฐ์ดํ„ฐ ํƒ€์ž…

๐Ÿ“Š Advanced Data Types

์ฃผ์š” ๋ฐ์ดํ„ฐ ํƒ€์ž…

ํƒ€์ž… ์„ค๋ช… ์˜ˆ์‹œ
logic 4-state (0,1,X,Z), reg/wire ๋Œ€์ฒด logic [7:0] data;
bit 2-state (0,1), ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๋น ๋ฆ„ bit [31:0] addr;
enum ์—ด๊ฑฐํ˜•, ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ enum {IDLE, RUN} state;
struct ๊ตฌ์กฐ์ฒด, ๊ด€๋ จ ๋ฐ์ดํ„ฐ ๊ทธ๋ฃนํ™” struct {bit[7:0] a,b;} pkt;
queue [$] ๋™์  ๋ฐฐ์—ด, FIFO ์šฉ๋„ int q[$];
[key] ์—ฐ๊ด€ ๋ฐฐ์—ด, ํ•ด์‹œ๋งต int mem[string];
๐Ÿ“„ SystemVerilog: Queue ํ™œ์šฉ
// Queue: ๋™์  FIFO int q[$]; // ๋นˆ ํ ์„ ์–ธ initial begin // ์‚ฝ์ž… q.push_back(10); // ๋’ค์— ์ถ”๊ฐ€: [10] q.push_back(20); // [10, 20] q.push_front(5); // ์•ž์— ์ถ”๊ฐ€: [5, 10, 20] // ์กฐํšŒ $display("Size: %0d", q.size()); // 3 $display("First: %0d", q[0]); // 5 // ์ถ”์ถœ int val = q.pop_front(); // val=5, q=[10, 20] // ๊ฒ€์ƒ‰/์‚ญ์ œ q.delete(0); // ์ธ๋ฑ์Šค 0 ์‚ญ์ œ: [20] end
๐Ÿ“„ SystemVerilog: ์—ฐ๊ด€ ๋ฐฐ์—ด (Associative Array)
// ์—ฐ๊ด€ ๋ฐฐ์—ด: ํ‚ค-๊ฐ’ ๋งคํ•‘ (ํ•ด์‹œ๋งต) int score[string]; // string ํ‚ค, int ๊ฐ’ initial begin // ์‚ฝ์ž… score["Alice"] = 95; score["Bob"] = 87; score["Carol"] = 92; // ์กฐํšŒ $display("Bob's score: %0d", score["Bob"]); // ์กด์žฌ ํ™•์ธ if (score.exists("Dave")) $display("Dave exists"); else $display("Dave not found"); // ์ „์ฒด ์ˆœํšŒ foreach (score[name]) $display("%s: %0d", name, score[name]); // ์‚ญ์ œ score.delete("Bob"); end

๐ŸŽฒ 5. ๋žœ๋คํ™”์™€ ์ œ์•ฝ์กฐ๊ฑด

๐ŸŽฒ Constrained Random Verification

CRV(Constrained Random Verification)๋Š” ํ˜„๋Œ€ ๊ฒ€์ฆ์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ์ˆ˜๋™ ํ…Œ์ŠคํŠธ ๋Œ€์‹  ์ œ์•ฝ์กฐ๊ฑด ๋‚ด์—์„œ ๋žœ๋ค ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ž๋™ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“„ SystemVerilog: ๋žœ๋คํ™” ์˜ˆ์ œ
class Packet; rand bit [7:0] header; rand bit [15:0] length; rand bit [3:0] priority; randc bit [1:0] channel; // ์ˆœํ™˜ ๋žœ๋ค (0,1,2,3 ๊ฐ๊ฐ ํ•œ๋ฒˆ์”ฉ) // ์ œ์•ฝ์กฐ๊ฑด 1: ๋ฒ”์œ„ constraint c_length { length inside {[64:1518]}; // Ethernet ํ”„๋ ˆ์ž„ ํฌ๊ธฐ } // ์ œ์•ฝ์กฐ๊ฑด 2: ํŠน์ • ๊ฐ’ constraint c_header { header inside {8'h01, 8'h02, 8'h04, 8'h08}; } // ์ œ์•ฝ์กฐ๊ฑด 3: ๊ฐ€์ค‘์น˜ ๋ถ„ํฌ constraint c_priority { priority dist { 0 :/ 10, // 10% ํ™•๋ฅ  [1:3] :/ 20, // 1,2,3 ๊ฐ๊ฐ 20/3% [4:7] :/ 30, // 4~7 ๊ฐ๊ฐ 30/4% [8:15] :/ 40 // 8~15 ๊ฐ๊ฐ 40/8% }; } // ์ œ์•ฝ์กฐ๊ฑด 4: ์กฐ๊ฑด๋ถ€ (implication) constraint c_small_high_priority { (length < 128) -> (priority > 8); // ์ž‘์€ ํŒจํ‚ท์€ ๋†’์€ ์šฐ์„ ์ˆœ์œ„ } endclass // ์‚ฌ์šฉ initial begin Packet pkt = new(); repeat (10) begin if (!pkt.randomize()) $error("Randomization failed!"); $display("hdr=%h len=%0d pri=%0d ch=%0d", pkt.header, pkt.length, pkt.priority, pkt.channel); end // ์ธ๋ผ์ธ ์ œ์•ฝ์กฐ๊ฑด ์ถ”๊ฐ€ pkt.randomize() with { length == 1024; // ์ด๋ฒˆ๋งŒ length ๊ณ ์ • }; end
๐Ÿ’ก ๋žœ๋คํ™” ํŒ

rand vs randc: rand๋Š” ๋งค๋ฒˆ ๋…๋ฆฝ์ , randc๋Š” ๋ชจ๋“  ๊ฐ’์„ ํ•œ๋ฒˆ์”ฉ ์ˆœํ™˜
soft constraint: soft ํ‚ค์›Œ๋“œ๋กœ ์šฐ์„ ์ˆœ์œ„ ๋‚ฎ์€ ์ œ์•ฝ ์„ค์ •
constraint mode: constraint_name.constraint_mode(0)์œผ๋กœ ๋น„ํ™œ์„ฑํ™”

๐Ÿ“ฌ 6. ํ”„๋กœ์„ธ์Šค ๊ฐ„ ํ†ต์‹ 

๐Ÿ“ฌ Inter-Process Communication

๋ณ‘๋ ฌ ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์„ ์œ„ํ•œ Mailbox์™€ Semaphore๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ฌ Mailbox

FIFO ํ ๊ธฐ๋ฐ˜ ๋ฉ”์‹œ์ง€ ์ „๋‹ฌ
put(): ๋ฐ์ดํ„ฐ ์‚ฝ์ž…
get(): ๋ฐ์ดํ„ฐ ์ถ”์ถœ (๋ธ”๋กœํ‚น)
try_get(): ๋…ผ๋ธ”๋กœํ‚น

๐Ÿ” Semaphore

๊ณต์œ  ์ž์› ์ ‘๊ทผ ์ œ์–ด
get(): ํ‚ค ํš๋“ (๋ธ”๋กœํ‚น)
put(): ํ‚ค ๋ฐ˜ํ™˜
try_get(): ๋…ผ๋ธ”๋กœํ‚น

๐Ÿ“„ SystemVerilog: Mailbox ์˜ˆ์ œ (Generator-Driver)
class Generator; mailbox #(Transaction) mbx; function new(mailbox #(Transaction) m); this.mbx = m; endfunction task run(int count); repeat (count) begin Transaction tr = new(); tr.randomize(); mbx.put(tr); // ๋ฉ”์ผ๋ฐ•์Šค์— ์ „์†ก $display("[GEN] Sent transaction"); end endtask endclass class Driver; mailbox #(Transaction) mbx; virtual my_if vif; task run(); Transaction tr; forever begin mbx.get(tr); // ๋ฉ”์ผ๋ฐ•์Šค์—์„œ ์ˆ˜์‹  (๋ธ”๋กœํ‚น) drive_transaction(tr); end endtask task drive_transaction(Transaction tr); @(posedge vif.clk); vif.addr <= tr.addr; vif.data <= tr.data; $display("[DRV] Driving addr=%h", tr.addr); endtask endclass // ํ…Œ์ŠคํŠธ๋ฒค์น˜์—์„œ ์—ฐ๊ฒฐ initial begin mailbox #(Transaction) mbx = new(); // ๊ณต์œ  ๋ฉ”์ผ๋ฐ•์Šค Generator gen = new(mbx); Driver drv = new(mbx); fork gen.run(10); // 10๊ฐœ ํŠธ๋žœ์žญ์…˜ ์ƒ์„ฑ drv.run(); // ๋“œ๋ผ์ด๋ฒ„ ์‹คํ–‰ join_any end

๐Ÿ”Œ 7. Interface

๐Ÿ”Œ Interface & Modport

Interface๋Š” ๊ด€๋ จ ์‹œ๊ทธ๋„๋“ค์„ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด ์—ฐ๊ฒฐ์„ ๋‹จ์ˆœํ™”ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“„ SystemVerilog: Interface ์ •์˜ ๋ฐ ์‚ฌ์šฉ
// Interface ์ •์˜ interface axi_lite_if (input logic clk, rst_n); // Write Address Channel logic [31:0] awaddr; logic awvalid; logic awready; // Write Data Channel logic [31:0] wdata; logic wvalid; logic wready; // Modport: DUT (Slave) ๊ด€์  modport SLAVE ( input clk, rst_n, input awaddr, awvalid, wdata, wvalid, output awready, wready ); // Modport: Testbench (Master) ๊ด€์  modport MASTER ( input clk, rst_n, output awaddr, awvalid, wdata, wvalid, input awready, wready ); endinterface // DUT ์—ฐ๊ฒฐ module my_slave (axi_lite_if.SLAVE bus); always_ff @(posedge bus.clk) begin bus.awready <= bus.awvalid; end endmodule // Testbench module tb; logic clk = 0, rst_n = 0; always #5 clk = ~clk; // Interface ์ธ์Šคํ„ด์Šค axi_lite_if axi_if (.clk(clk), .rst_n(rst_n)); // DUT ์—ฐ๊ฒฐ my_slave dut (.bus(axi_if)); initial begin #10 rst_n = 1; @(posedge clk); axi_if.awaddr <= 32'h1000; axi_if.awvalid <= 1; end endmodule

⏱️ 8. Clocking Block

⏱️ Clocking Block

Clocking Block์€ ํ…Œ์ŠคํŠธ๋ฒค์น˜์™€ DUT ๊ฐ„ ํƒ€์ด๋ฐ ๊ฒฝ์Ÿ ์กฐ๊ฑด์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“„ SystemVerilog: Clocking Block
interface my_if (input logic clk); logic [7:0] data; logic valid; logic ready; // Clocking Block ์ •์˜ clocking cb @(posedge clk); default input #1step output #1ns; // ์ƒ˜ํ”Œ/๋“œ๋ผ์ด๋ธŒ ์Šคํ output data, valid; // TB๊ฐ€ ๋“œ๋ผ์ด๋ธŒ input ready; // TB๊ฐ€ ์ƒ˜ํ”Œ endclocking modport TB (clocking cb); // TB๋Š” clocking ํ†ตํ•ด์„œ๋งŒ ์ ‘๊ทผ endinterface // Driver์—์„œ ์‚ฌ์šฉ class Driver; virtual my_if.TB vif; task drive(bit [7:0] d); vif.cb.data <= d; // clocking block ํ†ตํ•ด ๋“œ๋ผ์ด๋ธŒ vif.cb.valid <= 1; @(vif.cb); // ๋‹ค์Œ ํด๋Ÿญ ๋Œ€๊ธฐ wait (vif.cb.ready == 1); // ready ์ƒ˜ํ”Œ vif.cb.valid <= 0; endtask endclass
๐Ÿ’ก Clocking Block ์žฅ์ 

• Race Condition ๋ฐฉ์ง€: ์ž…๋ ฅ ์ƒ˜ํ”Œ๊ณผ ์ถœ๋ ฅ ๋“œ๋ผ์ด๋ธŒ ํƒ€์ด๋ฐ ๋ถ„๋ฆฌ
• ์ฝ”๋“œ ๊ฐ€๋…์„ฑ: ํƒ€์ด๋ฐ ์˜๋„๊ฐ€ ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚จ
• ์žฌ์‚ฌ์šฉ์„ฑ: ์ธํ„ฐํŽ˜์ด์Šค์— ์ •์˜ํ•˜๋ฉด ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ณต์œ 

✅ 9. SystemVerilog Assertions (SVA)

Assertions

SVA๋Š” ์„ค๊ณ„ ์†์„ฑ์„ ์„ ์–ธ์ ์œผ๋กœ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœํ† ์ฝœ ์œ„๋ฐ˜์„ ์ž๋™ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“„ SystemVerilog: Assertion ์˜ˆ์ œ
// Immediate Assertion (์ฆ‰์‹œ ๊ฒ€์‚ฌ) always @(posedge clk) begin assert (data !== 'x) else $error("Data is X!"); end // Concurrent Assertion (์‹œํ€€์Šค ๊ธฐ๋ฐ˜) // Property ์ •์˜: req ํ›„ 1~3 ์‚ฌ์ดํด ๋‚ด ack property p_req_ack; @(posedge clk) disable iff (!rst_n) req |-> ##[1:3] ack; // req๊ฐ€ 1์ด๋ฉด, 1~3 ์‚ฌ์ดํด ํ›„ ack endproperty // Assertion ์ธ์Šคํ„ด์Šค assert property (p_req_ack) else $error("ACK timeout!"); // Cover: ํ•ด๋‹น ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ํ™•์ธ cover property (p_req_ack); // ๋ณต์žกํ•œ ์‹œํ€€์Šค sequence s_write_burst; wr_en ##1 data_valid[*4] ##1 !wr_en; // wr_en, 4๋ฒˆ data, wr_en ํ•ด์ œ endsequence property p_burst_complete; @(posedge clk) s_write_burst |-> ##1 done; // burst ํ›„ done ์‹ ํ˜ธ endproperty
๐Ÿ’ก SVA ์—ฐ์‚ฐ์ž ์ •๋ฆฌ

##N: N ์‚ฌ์ดํด ํ›„
##[M:N]: M~N ์‚ฌ์ดํด ์‚ฌ์ด
|->: Overlapping implication (๊ฐ™์€ ์‚ฌ์ดํด)
|=>: Non-overlapping implication (๋‹ค์Œ ์‚ฌ์ดํด)
[*N]: N๋ฒˆ ์—ฐ์† ๋ฐ˜๋ณต
[*M:N]: M~N๋ฒˆ ๋ฐ˜๋ณต

๐Ÿ“Š 10. Functional Coverage

๐Ÿ“Š Functional Coverage

Covergroup์€ ํ…Œ์ŠคํŠธ๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ปค๋ฒ„ํ–ˆ๋Š”์ง€ ์ธก์ •ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“„ SystemVerilog: Covergroup ์˜ˆ์ œ
class Coverage; bit [7:0] addr; bit [1:0] cmd; bit [31:0] data; covergroup cg @(posedge clk); // Coverpoint 1: ์ฃผ์†Œ ๋ฒ”์œ„ cp_addr: coverpoint addr { bins low = {[0:63]}; bins mid = {[64:191]}; bins high = {[192:255]}; illegal_bins reserved = {8'hFF}; // ๊ธˆ์ง€ ์˜์—ญ } // Coverpoint 2: ๋ช…๋ น ํƒ€์ž… cp_cmd: coverpoint cmd { bins read = {2'b00}; bins write = {2'b01}; bins rmw = {2'b10}; // Read-Modify-Write } // Cross Coverage: addr × cmd ์กฐํ•ฉ cx_addr_cmd: cross cp_addr, cp_cmd; // Coverpoint 3: ๋ฐ์ดํ„ฐ ํŠน์ˆ˜๊ฐ’ cp_data: coverpoint data { bins zero = {32'h0}; bins all_ones = {32'hFFFF_FFFF}; bins others = default; } endgroup function new(); cg = new(); endfunction function void sample(bit[7:0] a, bit[1:0] c, bit[31:0] d); addr = a; cmd = c; data = d; cg.sample(); // ์ˆ˜๋™ ์ƒ˜ํ”Œ๋ง endfunction function void report(); $display("Coverage: %.2f%%", cg.get_coverage()); endfunction endclass

๐Ÿ“ฆ 11. Program Block

program ๋ธ”๋ก์€ ํ…Œ์ŠคํŠธ๋ฒค์น˜์™€ DUT๋ฅผ ํƒ€์ด๋ฐ์ ์œผ๋กœ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ Program vs Module

Module: ํ•˜๋“œ์›จ์–ด ๋ชจ๋ธ๋ง, Delta Cycle์—์„œ ๋จผ์ € ์‹คํ–‰
Program: ํ…Œ์ŠคํŠธ๋ฒค์น˜ ์ „์šฉ, Reactive Region์—์„œ ์‹คํ–‰

๐Ÿ’ก Program ๋‚ด ์‹œ๊ทธ๋„ ๋ณ€๊ฒฝ์€ ํ•ด๋‹น ํƒ€์ž„์Šคํ…์—์„œ DUT์— ์˜ํ–ฅ ์—†์Œ
→ Race Condition ๋ฐฉ์ง€

๐Ÿ“„ SystemVerilog: Program Block ์˜ˆ์ œ
program test (my_if.TB vif); initial begin $display("[PROGRAM] Test starting..."); // ๋ฆฌ์…‹ ์‹œํ€€์Šค vif.cb.valid <= 0; repeat (5) @(vif.cb); // ํ…Œ์ŠคํŠธ ์‹œํ€€์Šค for (int i = 0; i < 10; i++) begin vif.cb.data <= i; vif.cb.valid <= 1; @(vif.cb); end $display("[PROGRAM] Test complete!"); end endprogram

๐ŸŽฏ 12. ์‹ค์ „ ํŒ

✅ ๋ชจ๋ฒ” ์‚ฌ๋ก€

1. ๊ณ„์ธต์  ๊ตฌ์กฐ: Generator → Driver → Monitor → Scoreboard
2. Interface ์‚ฌ์šฉ: ํฌํŠธ ์—ฐ๊ฒฐ ๋‹จ์ˆœํ™”, ์žฌ์‚ฌ์šฉ์„ฑ ํ–ฅ์ƒ
3. Clocking Block: ํƒ€์ด๋ฐ ๋ฌธ์ œ ์‚ฌ์ „ ๋ฐฉ์ง€
4. Constrained Random: ์ˆ˜๋™ ํ…Œ์ŠคํŠธ → CRV ์ „ํ™˜
5. Coverage Driven: ์ปค๋ฒ„๋ฆฌ์ง€ ๋ชฉํ‘œ ์„ค์ • ํ›„ ํ…Œ์ŠคํŠธ
6. Assertion: ํ”„๋กœํ† ์ฝœ ๊ฒ€์ฆ์€ SVA๋กœ

❌ ์•ˆํ‹ฐํŒจํ„ด

1. #delay ๋‚จ๋ฐœ: ์ ˆ๋Œ€ ์‹œ๊ฐ„ ๋Œ€์‹  ํด๋Ÿญ ์ด๋ฒคํŠธ ์‚ฌ์šฉ
2. ๊ธ€๋กœ๋ฒŒ ๋ณ€์ˆ˜: ํด๋ž˜์Šค๋กœ ์บก์Аํ™”
3. ํ•˜๋“œ์ฝ”๋”ฉ: ํŒŒ๋ผ๋ฏธํ„ฐ/๋žœ๋คํ™” ํ™œ์šฉ
4. fork ํ›„ release ๋ˆ„๋ฝ: disable fork ํ•„์ˆ˜
5. Coverage ์—†์ด ์ง„ํ–‰: ๋ชฉํ‘œ ์—†๋Š” ํ…Œ์ŠคํŠธ

๐Ÿ“Œ ํ•ต์‹ฌ ์š”์•ฝ

๊ธฐ๋Šฅ ํ‚ค์›Œ๋“œ ์šฉ๋„
๋ณ‘๋ ฌ ์‹คํ–‰ fork-join Driver, Monitor ๋™์‹œ ์‹คํ–‰
OOP class Transaction, Component ๊ตฌ์กฐํ™”
๋žœ๋คํ™” rand, constraint CRV ํ…Œ์ŠคํŠธ ์ž๋™ํ™”
IPC mailbox ์ปดํฌ๋„ŒํŠธ ๊ฐ„ ํ†ต์‹ 
Assertion property, assert ํ”„๋กœํ† ์ฝœ ์ž๋™ ๊ฒ€์ฆ
Coverage covergroup ํ…Œ์ŠคํŠธ ์™„๋ฃŒ๋„ ์ธก์ •

๋‹ค์Œ ๋‹จ๊ณ„: ์ด ๊ธฐ๋Šฅ๋“ค์„ ์ฒด๊ณ„ํ™”ํ•œ ๊ฒƒ์ด UVM (Universal Verification Methodology)์ž…๋‹ˆ๋‹ค. SystemVerilog ๊ธฐ๋ณธ๊ธฐ๋ฅผ ์ตํžŒ ํ›„ UVM์œผ๋กœ ๋ฐœ์ „์‹œํ‚ค์„ธ์š”!

๐Ÿ“š ์ฐธ๊ณ  ์ž๋ฃŒ

SystemVerilog LRM: IEEE 1800-2017
์ถ”์ฒœ ์„œ์ : "SystemVerilog for Verification" - Chris Spear
์˜จ๋ผ์ธ: Verification Academy, ASIC World

๋Œ“๊ธ€

์ด ๋ธ”๋กœ๊ทธ์˜ ์ธ๊ธฐ ๊ฒŒ์‹œ๋ฌผ

๐Ÿ“š SDC ๋งˆ์Šคํ„ฐ ํด๋ž˜์Šค ์‹œ๋ฆฌ์ฆˆ | Chapter 1

๐Ÿ“š SDC ๋งˆ์Šคํ„ฐ ํด๋ž˜์Šค ์‹œ๋ฆฌ์ฆˆ | Chapter 2

๐Ÿ“š SDC ๋งˆ์Šคํ„ฐ ํด๋ž˜์Šค ์‹œ๋ฆฌ์ฆˆ | Chapter 3