Session 1: Introduction & Development Pipeline¶
Homework¶
Homework
- Install the course toolchain (Docker container)
- Run a “hello world” synthesis
- Verify your tools work before Thursday!
Words¶
AI-generated summary
This section was summarized using NotebookLM (Source: lecture page)
Verilog is a Hardware Description Language (HDL) used to design and verify digital circuits.
- Role: It is used during the “RTL Design” phase of the chip development pipeline. Designers use it to describe digital logic, including combinational and sequential logic, as well as state machines.
- Realization: Code written as “Synthesizable Verilog” can be converted into actual logic gate netlists using synthesis tools like Yosys.
- Process: It serves as the starting point (Verilog Code) of the development flow. It goes through simulation (e.g., Icarus Verilog) and is eventually transformed into a physical layout (GDS file) on silicon.
- Format: Verilog source files typically use the “.v” extension.
Verilogは、デジタル回路を設計し、その動作を検証するために使用されるハードウェア記述言語(HDL: Hardware Description Language)です。
- 役割: チップ開発パイプラインの「RTL設計(RTL Design)」フェーズで使用されます。設計者はこれを用いて、組合せ回路、順序回路、状態マシンといったデジタル論理を記述します。
- 実体化: 「合成可能なVerilog(Synthesizable Verilog)」として書かれたコードは、Yosysなどのツール(論理合成ツール)によって、実際の論理ゲートの接続情報へと変換されます。
- 工程: チップ開発の出発点(Verilog Code)となり、シミュレーション(Icarus Verilog等)を経て、最終的にシリコン上のレイアウト(GDSファイル)へと自動変換されます。
- 形式: 通常、ソースファイルには「.v」という拡張子が使われます。
(Integrated Infrastructure for Collaborative Open Source IC Tools)
IIC-OSIC-TOOLS is an integrated environment that combines a suite of open-source EDA (Electronic Design Automation) tools for semiconductor chip design, verification, and physical layout. It serves as an all-in-one toolset for beginners to experience the full chip development pipeline, spanning from initial design (Verilog) to manufacturing readiness (GDS).
By using this environment, designers can complete the entire “RTL-to-GDS flow”—the process of transforming Verilog code into final GDS manufacturing data—exclusively with open-source tools.
IIC-OSIC-TOOLSは、半導体チップの設計から検証、レイアウト作成までを行うためのオープンソースEDA(電子設計自動化)ツール一式をまとめた環境で、初心者が「設計(Verilog)から製造準備(GDS)」までのチップ開発パイプライン全体を体験するための一体型ツールセットです。
この環境を使用することで、設計者は「RTL-to-GDSフロー」(Verilogコードから最終的な製造用データであるGDSファイルを作成するまでの流れ)を、すべてオープンソースツールのみで完結させることができます
Homework 1¶
Homework
- Install the course toolchain (Docker container)
https://tools.futures.academany.org/login

Instruction on Welcome page¶
About IIC-OSIC-TOOLS container:
- All tools run inside a Docker container — a self-contained Linux environment.
- A pre built all-in-one Docker image for analog and digital chip design.
- View all installed tools in this container
First try out?
- Open your tool’s server in the browser, enter the VNC password.
- Once inside, you should see your server desktop.
- Right click on the desktop and select “Open Terminal” to access the command line.
- Type: cd /foss/examples
- Run simulations with: make sim-fortune or make sim-all
Documenting and saving your work
Keep all your files in the following folder to make sure your work is saved during reboots.
/foss/designs/
Open Fabcloud Markdown Editor
Open this this is a web-based editor in a browser on your tools server, then you can edit your documentation website.
Start Container¶




Homework 2¶
Homework
2. Run a “hello world” synthesis
file structure: Click to open
/foss
├── designs
├── examples
│ ├── analog basics
│ ├── dice_roller
│ ├── fortune_teller
│ ├── lib
│ ├── Makefile
│ ├── morse_beacon
│ ├── pocket_synth
│ ├── ../foss/examples/QuickStart.md
│ ├── README.md
│ └── TROUBLESHOOTING.md
├── pdks
│ ├── ciel
│ ├── gf180mcuD
│ ├── ihp-sg13g2
│ └── sky130A
└── tools
├── bin
├── covered
├── cvc_rv
├── fpga
├── gaw3-xschem
├── gds3d
├── ghdl
├── gtkwave
├── irsim
├── iverilog
├── klayout
├── magic
├── netgen
├── ngspice
├── ngspyce
├── nvc
├── openems
├── openroad
├── openroad-librelane
├── openvaf
├── osic-multitool
├── padring
├── palace
├── pyopus
├── qflow
├── riscv-gnu-toolchain
├── rftoolkit
├── sak
├── slang
├── spicebind
├── surfer
├── veryl
├── verilator
├── xschem
├── xcircuit
├── xyce
└── yosys
Get text from docker and use in PC

git pullthe repo and edit in local
Practical way: Create a GitLab bookmark to save files from Docker container¶
From PC (Gitlab or local repo)
-
In Gitlab or local repo, create new file in docs/foss/designs
. ├── docs │ ├── foss │ │ └── designs │ │ └── bookmarks.html -
Copy and paste the following code to make bookmarks of:
- Web Editor
- Gitlab
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Bookmarks</title> </head> <body> <h1>Bookmarks</h1> <p> <a href="https://editor.fabcloud.org/editor" target="_blank"> Web Editor </a> </p> <p> <a href="https://gitlab.fabcloud.org/" target="_blank"> GitLab </a> </p> </body> </html> -
save as
bookmarks.htmland push it to gitlab - Go to Tool launcher and start container, then Open Browser VNC
In Docker Container
- Open browser and go to Gitlab
https://gitlab.fabcloud.org/ - Find
docs/foss/designs/bookmarks.html - Copy the html code
- Open Terminal and go to
/foss/designs/ - Create
bookmarks.htmland past the html code (and save)/foss/designs > nano bookmarks.html /foss/designs > ls bookmarks.html
Next time when open the docker
- Open File Manager
- Go to
designfolder and findbookmarks.html - Double click to open the
bookmarks.html, then go to Gitlab - Now, any files in the Docker container can be uploaded to GitLab
- Code created as assignments
- Lecture files
Simulate the Fortune Teller project¶
Step 3: Run Your First Simulation
make sim-fortuneon Terminal in Docker- Test complete

What was happened here
/foss/examples > make sim-fortune
iverilog -Wall -g2012 -Ilib -o fortune_teller/fortune_teller.vvp fortune_teller/fortune_teller.v fortune_teller/fortune_teller_tb.v lib/debounce.v lib/uart_tx.v
fortune_teller.v(main module)fortune_teller_tb.v(testbench)- library files such as
debounce.vanduart_tx.v
It generated a simulation file (fortune_teller.vvp).
vvp fortune_teller/fortune_teller.vvp
VCD info: dumpfile fortune_teller_tb.vcd opened for output.
Pressing button...
Cannot predict.
Pressing button again...
Yes definitely!
Test complete
fortune_teller/fortune_teller_tb.v:221: $finish called at 51055000000 (1ps)
- The testbench simulated pressing a button.
- The circuit produced responses such as “Cannot predict.” and “Yes definitely!”
- A waveform file (fortune_teller_tb.vcd) was generated.
- The simulation ended when $finish was called at line 221 of the testbench.
View the Waveforms¶
Note
gtkwave fortune_teller/fortune_teller_tb.vcd should be gtkwave fortune_teller_tb.vcd
gtkwave fortune_teller_tb.vcdon Terminal in Docker
- GTKwave is opened

A window opens showing signals over time.
Try:
1. Click the + next to fortune_teller_tb in the left panel
2. Select a signal (like clk or btn)
3. Click “Append” to add it to the view
4. Use the zoom buttons to see the waveform

In this window, we can see the button being clicked by program of the chip.
Look at the Code¶
cat fortune_teller/fortune_teller.v | less
fortune_teller.v
// ============================================================================
// Fortune Teller - A Magic 8-Ball on a Chip
// ============================================================================
//
// HOW IT WORKS:
// 1. Press the button
// 2. Chip picks a random fortune from memory
// 3. Fortune appears on your computer's serial terminal
//
// WHAT YOU'LL LEARN:
// - ROM (Read-Only Memory) - storing data in your chip
// - LFSR (Linear Feedback Shift Register) - generating random numbers
// - State machines - controlling the sequence of operations
// - Using library modules - connecting pre-built components
//
// ============================================================================
`timescale 1ns/1ps
module fortune_teller #(
// ========================================================================
// Parameters
// ========================================================================
parameter CLK_FREQ = 50_000_000, // Your board's clock speed (Hz)
parameter BAUD = 115200 // Serial communication speed
)(
// ========================================================================
// Ports
// ========================================================================
input wire clk, // Clock input from your board
input wire rst_n, // Reset button (active LOW)
input wire btn, // The "ask a question" button
output wire tx, // Serial output (connect to USB-serial adapter)
output wire led // Shows when chip is "thinking"
);
// ========================================================================
// Button Debouncing
// ========================================================================
// We use the debounce module from the library to clean up the button
// signal. btn_pressed will pulse HIGH for exactly one clock cycle
// when a valid button press is detected.
wire btn_pressed; // Clean, debounced button signal
debounce #(
.CLK_FREQ(CLK_FREQ) // Pass our clock frequency to the debouncer
) debounce_inst (
.clk(clk),
.rst_n(rst_n),
.btn_raw(btn), // Raw button input
.btn_pressed(btn_pressed) // Clean output
);
// ========================================================================
// Fortune ROM (Read-Only Memory)
// ========================================================================
// We store 8 different fortunes in memory. Each fortune can be up to
// 20 characters long. Characters are stored as ASCII codes.
//
// ASCII codes: 'A'=0x41, 'a'=0x61, ' '=0x20, '.'=0x2E, '\n'=0x0A, etc.
// 0x00 marks the end of a string (null terminator).
//
// Total memory: 8 fortunes x 20 bytes = 160 bytes
reg [7:0] rom [0:159]; // 160 bytes of ROM
// Initialize the ROM with our fortunes
// (In a real chip, this would be hardcoded during manufacturing)
initial begin
// Fortune 0: "Yes definitely!\n"
rom[0] = 8'h59; // 'Y'
rom[1] = 8'h65; // 'e'
rom[2] = 8'h73; // 's'
rom[3] = 8'h20; // ' '
rom[4] = 8'h64; // 'd'
rom[5] = 8'h65; // 'e'
rom[6] = 8'h66; // 'f'
rom[7] = 8'h69; // 'i'
rom[8] = 8'h6E; // 'n'
rom[9] = 8'h69; // 'i'
rom[10] = 8'h74; // 't'
rom[11] = 8'h65; // 'e'
rom[12] = 8'h6C; // 'l'
rom[13] = 8'h79; // 'y'
rom[14] = 8'h21; // '!'
rom[15] = 8'h0A; // '\n' (newline)
rom[16] = 8'h00; // End of string
rom[17] = 8'h00;
rom[18] = 8'h00;
rom[19] = 8'h00;
// Fortune 1: "Ask again later.\n"
rom[20] = 8'h41; // 'A'
rom[21] = 8'h73; // 's'
rom[22] = 8'h6B; // 'k'
rom[23] = 8'h20; // ' '
rom[24] = 8'h61; // 'a'
rom[25] = 8'h67; // 'g'
rom[26] = 8'h61; // 'a'
rom[27] = 8'h69; // 'i'
rom[28] = 8'h6E; // 'n'
rom[29] = 8'h20; // ' '
rom[30] = 8'h6C; // 'l'
rom[31] = 8'h61; // 'a'
rom[32] = 8'h74; // 't'
rom[33] = 8'h65; // 'e'
rom[34] = 8'h72; // 'r'
rom[35] = 8'h2E; // '.'
rom[36] = 8'h0A; // '\n'
rom[37] = 8'h00;
rom[38] = 8'h00;
rom[39] = 8'h00;
// Fortune 2: "Outlook not good.\n"
rom[40] = 8'h4F; // 'O'
rom[41] = 8'h75; // 'u'
rom[42] = 8'h74; // 't'
rom[43] = 8'h6C; // 'l'
rom[44] = 8'h6F; // 'o'
rom[45] = 8'h6F; // 'o'
rom[46] = 8'h6B; // 'k'
rom[47] = 8'h20; // ' '
rom[48] = 8'h6E; // 'n'
rom[49] = 8'h6F; // 'o'
rom[50] = 8'h74; // 't'
rom[51] = 8'h20; // ' '
rom[52] = 8'h67; // 'g'
rom[53] = 8'h6F; // 'o'
rom[54] = 8'h6F; // 'o'
rom[55] = 8'h64; // 'd'
rom[56] = 8'h2E; // '.'
rom[57] = 8'h0A; // '\n'
rom[58] = 8'h00;
rom[59] = 8'h00;
// Fortune 3: "Signs point to yes\n"
rom[60] = 8'h53; // 'S'
rom[61] = 8'h69; // 'i'
rom[62] = 8'h67; // 'g'
rom[63] = 8'h6E; // 'n'
rom[64] = 8'h73; // 's'
rom[65] = 8'h20; // ' '
rom[66] = 8'h70; // 'p'
rom[67] = 8'h6F; // 'o'
rom[68] = 8'h69; // 'i'
rom[69] = 8'h6E; // 'n'
rom[70] = 8'h74; // 't'
rom[71] = 8'h20; // ' '
rom[72] = 8'h74; // 't'
rom[73] = 8'h6F; // 'o'
rom[74] = 8'h20; // ' '
rom[75] = 8'h79; // 'y'
rom[76] = 8'h65; // 'e'
rom[77] = 8'h73; // 's'
rom[78] = 8'h0A; // '\n'
rom[79] = 8'h00;
// Fortune 4: "Very doubtful.\n"
rom[80] = 8'h56; // 'V'
rom[81] = 8'h65; // 'e'
rom[82] = 8'h72; // 'r'
rom[83] = 8'h79; // 'y'
rom[84] = 8'h20; // ' '
rom[85] = 8'h64; // 'd'
rom[86] = 8'h6F; // 'o'
rom[87] = 8'h75; // 'u'
rom[88] = 8'h62; // 'b'
rom[89] = 8'h74; // 't'
rom[90] = 8'h74; // 't'
rom[91] = 8'h75; // 'u'
rom[92] = 8'h6C; // 'l'
rom[93] = 8'h2E; // '.'
rom[94] = 8'h0A; // '\n'
rom[95] = 8'h00;
rom[96] = 8'h00;
rom[97] = 8'h00;
rom[98] = 8'h00;
rom[99] = 8'h00;
// Fortune 5: "It is certain.\n"
rom[100] = 8'h49; // 'I'
rom[101] = 8'h74; // 't'
rom[102] = 8'h20; // ' '
rom[103] = 8'h69; // 'i'
rom[104] = 8'h73; // 's'
rom[105] = 8'h20; // ' '
rom[106] = 8'h63; // 'c'
rom[107] = 8'h65; // 'e'
rom[108] = 8'h72; // 'r'
rom[109] = 8'h74; // 't'
rom[110] = 8'h61; // 'a'
rom[111] = 8'h69; // 'i'
rom[112] = 8'h6E; // 'n'
rom[113] = 8'h2E; // '.'
rom[114] = 8'h0A; // '\n'
rom[115] = 8'h00;
rom[116] = 8'h00;
rom[117] = 8'h00;
rom[118] = 8'h00;
rom[119] = 8'h00;
// Fortune 6: "Reply hazy.\n"
rom[120] = 8'h52; // 'R'
rom[121] = 8'h65; // 'e'
rom[122] = 8'h70; // 'p'
rom[123] = 8'h6C; // 'l'
rom[124] = 8'h79; // 'y'
rom[125] = 8'h20; // ' '
rom[126] = 8'h68; // 'h'
rom[127] = 8'h61; // 'a'
rom[128] = 8'h7A; // 'z'
rom[129] = 8'h79; // 'y'
rom[130] = 8'h2E; // '.'
rom[131] = 8'h0A; // '\n'
rom[132] = 8'h00;
rom[133] = 8'h00;
rom[134] = 8'h00;
rom[135] = 8'h00;
rom[136] = 8'h00;
rom[137] = 8'h00;
rom[138] = 8'h00;
rom[139] = 8'h00;
// Fortune 7: "Cannot predict.\n"
rom[140] = 8'h43; // 'C'
rom[141] = 8'h61; // 'a'
rom[142] = 8'h6E; // 'n'
rom[143] = 8'h6E; // 'n'
rom[144] = 8'h6F; // 'o'
rom[145] = 8'h74; // 't'
rom[146] = 8'h20; // ' '
rom[147] = 8'h70; // 'p'
rom[148] = 8'h72; // 'r'
rom[149] = 8'h65; // 'e'
rom[150] = 8'h64; // 'd'
rom[151] = 8'h69; // 'i'
rom[152] = 8'h63; // 'c'
rom[153] = 8'h74; // 't'
rom[154] = 8'h2E; // '.'
rom[155] = 8'h0A; // '\n'
rom[156] = 8'h00;
rom[157] = 8'h00;
rom[158] = 8'h00;
rom[159] = 8'h00;
end
// ========================================================================
// LFSR - Random Number Generator
// ========================================================================
// An LFSR (Linear Feedback Shift Register) creates pseudo-random numbers
// using XOR feedback. It cycles through all possible values (except 0)
// before repeating.
//
// POLYNOMIAL THEORY:
// The taps correspond to a primitive polynomial over GF(2):
// x^8 + x^5 + x^4 + x^3 + 1 (taps at bits 7,5,4,3 counting from 0)
//
// A primitive polynomial of degree n produces a sequence of length
// 2^n - 1 before repeating. For n=8: 2^8 - 1 = 255 unique states.
//
// Not all tap combinations work! The polynomial must be "primitive"
// (irreducible and of maximal period). These are tabulated in references
// like Xilinx XAPP052 or Wikipedia "Linear-feedback shift register".
//
// RANDOMNESS TRICK:
// The LFSR runs CONTINUOUSLY on every clock cycle. The exact moment
// you press the button determines which "random" value you get.
// Since humans can't time button presses to the nanosecond, this
// gives effectively random results!
reg [7:0] lfsr; // 8-bit shift register
// Feedback bit is XOR of bits 7, 5, 4, and 3
wire lfsr_feedback = lfsr[7] ^ lfsr[5] ^ lfsr[4] ^ lfsr[3];
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
lfsr <= 8'hAC; // Seed value (any non-zero value works)
end
else begin
// Shift left and insert feedback bit at position 0
lfsr <= {lfsr[6:0], lfsr_feedback};
end
end
// ========================================================================
// State Machine
// ========================================================================
// Controls the sequence: wait for button -> load char -> send char -> repeat
// State definitions (2 bits = 4 possible states)
localparam IDLE = 2'd0; // Waiting for button press
localparam LOAD = 2'd1; // Loading a character from ROM
localparam SEND = 2'd2; // Sending character to UART
localparam WAIT = 2'd3; // Waiting for UART to finish
// State machine registers
reg [1:0] state; // Current state
reg [2:0] fortune_sel; // Which fortune (0-7)
reg [4:0] char_idx; // Which character in the fortune (0-19)
reg [7:0] current_char; // The character we're currently sending
reg send_valid; // Tell UART to send
// Calculate ROM address: fortune_number * 20 + character_index
wire [7:0] rom_addr = fortune_sel * 20 + char_idx;
// UART ready signal (from the UART module)
wire uart_ready;
// ========================================================================
// UART Transmitter Instance
// ========================================================================
// Connect to the UART module from the library
uart_tx #(
.CLK_FREQ(CLK_FREQ),
.BAUD(BAUD)
) uart_inst (
.clk(clk),
.rst_n(rst_n),
.data(current_char), // Character to send
.valid(send_valid), // Start sending when HIGH
.ready(uart_ready), // UART tells us when it's ready
.tx(tx) // Serial output
);
// ========================================================================
// LED Output
// ========================================================================
// LED is ON whenever we're not idle (i.e., while sending a fortune)
assign led = (state != IDLE);
// ========================================================================
// Main State Machine Logic
// ========================================================================
always @(posedge clk or negedge rst_n) begin
// --------------------------------------------------------------------
// Reset
// --------------------------------------------------------------------
if (!rst_n) begin
state <= IDLE;
fortune_sel <= 0;
char_idx <= 0;
send_valid <= 0;
current_char <= 0;
end
// --------------------------------------------------------------------
// Normal Operation
// --------------------------------------------------------------------
else begin
// Default: don't start a UART transmission
send_valid <= 0;
case (state)
// ============================================================
// IDLE: Wait for button press
// ============================================================
IDLE: begin
if (btn_pressed) begin
// Capture 3 bits from LFSR to pick fortune 0-7
fortune_sel <= lfsr[2:0];
// Start at first character
char_idx <= 0;
// Move to LOAD state
state <= LOAD;
end
end
// ============================================================
// LOAD: Read character from ROM
// ============================================================
LOAD: begin
// Read the character at the current ROM address
current_char <= rom[rom_addr];
// Move to SEND state
state <= SEND;
end
// ============================================================
// SEND: Send character to UART
// ============================================================
SEND: begin
// Check if we've reached the null terminator (end of string)
if (current_char == 0) begin
// Done! Go back to idle
state <= IDLE;
end
// Otherwise, wait for UART to be ready
else if (uart_ready) begin
// Start sending the character
send_valid <= 1;
// Move to WAIT state
state <= WAIT;
end
end
// ============================================================
// WAIT: Wait for UART to start sending
// ============================================================
WAIT: begin
// When UART goes busy (ready drops), it has started
if (!uart_ready) begin
// Move to next character
char_idx <= char_idx + 1;
// Go load the next character
state <= LOAD;
end
end
endcase
end
end
endmodule
Make It Yours¶
- Copy an example to your designs folder:
cp -r fortune_teller /foss/designs/my_fortune_teller cd /foss/designs/my_fortune_teller - Edit the code:
gedit fortune_teller.v & - Change the fortunes (look for the ROM section around line 50)
my_fortune_teller
| my_fortune_teller | |
|---|---|
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | |
Test your changes:¶
Example
iverilog -Wall -g2012 -I/foss/examples/lib -o test.vvp \
fortune_teller.v fortune_teller_tb.v \
/foss/examples/lib/debounce.v /foss/examples/lib/uart_tx.v
vvp test.vvp
In my docker
iverilog -Wall -g2012 -I/foss/examples/lib -o test.vvp \
my_fortune_teller.v my_fortune_teller_tb.v \
/foss/designs/lib/debounce.v /foss/designs/lib/uart_tx.v
vvp test.vvp
cp -r Makefile /fos/designs/
cd ../designs
ls
Makefile my_fortune_teller
cd Makefile
Edit Makefile
fortune_teller -> my_fortune_teller
Makefile
| Makefile | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | |
File structure
.
├── designs
│ ├── Makefile
│ ├── lib
│ └── my_fortune_teller
│ ├── my_fortune_teller_tb.v
│ ├── my_fortune_teller.v
│ └── my_fortune_teller.vvp
cd foss/designs
make sim-fortune
/foss/designs > make sim-fortune
vvp my_fortune_teller/my_fortune_teller.vvp
VCD info: dumpfile fortune_teller_tb.vcd opened for output.
Pressing button...
Pressing button again...
Test complete
my_fortune_teller/my_fortune_teller_tb.v:221: $finish called at 51055000000 (1ps)
What Do These Files Mean?
fortune_teller/
├── fortune_teller.v # The actual chip design (Verilog)
└── fortune_teller_tb.v # Test code that
simulates pressing buttons
.vfiles = Verilog source code (what becomes your chip)_tb.vfiles = Testbench (simulates the outside world).vcdfiles = Waveform data (created when you simulate).vvpfiles = Compiled simulation (temporary, can delete)