├── LICENSE ├── README.md ├── coding-style.md └── examples ├── draw_field_helper.sv ├── qstage.sv └── reverse_counter.sv /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Ivan Shevchuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johan92/verilog-coding-style/744c4c05310315c9e50fdfed7e8c6562fa82f6c0/README.md -------------------------------------------------------------------------------- /coding-style.md: -------------------------------------------------------------------------------- 1 | # Verilog (SystemVerilog) Coding Style 2 | 3 | ## Отступы и пробелы 4 | Отступ - 2 пробела. Табы (`\t`) запрещены. 5 | 6 | Отступ нужны для обозначения "вложения". 7 | 8 | Пример: 9 | ```systemverilog 10 | if( a ) 11 | b = c; 12 | ``` 13 | 14 | ### Пробелы 15 | Пробел должен ставится: 16 | - после открывающейся `(` и перед закрывающейся скобкой `)` в конструкциях `if`, `for`, `always`, `function`, `task`, сложных логических условиях 17 | - перед и после элементов, требующих двух операндов ( `&`, `|`, `&&`, `||`, `=`, `<=`, `+`) 18 | - перед и после использованием переменных и констант. Исключение: перед `,` и `;` пробел не ставится. 19 | 20 | Примеры: 21 | ```systemverilog 22 | if( a > c ) 23 | ``` 24 | 25 | ```systemverilog 26 | a = b && ( c > d ); 27 | ``` 28 | 29 | ```systemverilog 30 | a = ( b == c ) ? ( y ) : ( z ); 31 | ``` 32 | 33 | ### Пустые строчки 34 | Любые логические вещи необходимо отделять пустой строчкой. 35 | Под `логической вещью` понимается какой-то интерфейс или совокупность сигналов, которые имеют одинаковое назначение или цель. 36 | 37 | Пример: 38 | 39 | ```systemverilog 40 | ... 41 | input clk_i, 42 | input [1:0] mode_i, 43 | input mode_en_i, 44 | output [7:0] data_o, 45 | output data_val_o 46 | ... 47 | ``` 48 | 49 | Здесь мы видим, что есть три разные сущности: 50 | - синхроимпульс `clk_i` 51 | - настройка какого-то режима работы `mode_i` и его разрешения `mode_en_i` 52 | - сигнал выходных данных `data_o` и валидность этого сигнала `data_valid_o` 53 | 54 | Для облегчения чтения необходимо делать пустые пробелы между сущностями: 55 | ```systemverilog 56 | ... 57 | input clk_i, 58 | 59 | input [1:0] mode_i, 60 | input mode_en_i, 61 | 62 | output [7:0] data_o, 63 | output data_val_o 64 | ... 65 | ``` 66 | 67 | ## Выравнивание 68 | Выравнивание необходимо для облегчения чтения кода. 69 | Выравнивание производится с помощью пробелов. Табы (`\t`) запрещены. 70 | 71 | Необходимо выравнивать названия, размерность и комментарии по "логическим" колонкам. 72 | 73 | ### Пример #1 74 | Неправильно: 75 | ```systemverilog 76 | // BAD EXAMPLE 77 | logic rd_stb; //buffer read strobe 78 | logic [31:0] ram_data; //data from RAM block 79 | logic [1:0]if_mode; //interface mode 80 | ``` 81 | 82 | Правильно: 83 | ```systemverilog 84 | // GOOD EXAMPLE 85 | logic rd_stb; // buffer read strobe 86 | logic [31:0] ram_data; // data from RAM block 87 | logic [1:0] if_mode; // interface mode 88 | ``` 89 | 90 | ### Пример #2 91 | Неправильно: 92 | ```systemverilog 93 | // BAD EXAMPLE 94 | input clk_i, 95 | input rst_i, 96 | input [31:0] data_i, 97 | input data_valid_i, 98 | output logic [7:0] data_o, 99 | output data_valid_o 100 | ``` 101 | 102 | Правильно: 103 | ``` systemverilog 104 | // GOOD EXAMPLE 105 | input clk_i, 106 | input rst_i, 107 | 108 | input [31:0] data_i, 109 | input data_valid_i, 110 | 111 | output logic [7:0] data_o, 112 | output data_valid_o 113 | 114 | ``` 115 | Примечание: 116 | - по умолчанию логические колонки "разделяются" одним пробелом, однако, допускается делать 117 | больше пробелов, если это улучшает читаемость (как в примере выше). 118 | 119 | ### Пример #3 120 | 121 | Неправильно: 122 | ```systemverilog 123 | // BAD EXAMPLE 124 | assign next_len = len + 16'd8; 125 | assign next_pkt_len = pkt_len + 16'd4; 126 | ``` 127 | 128 | Правильно: 129 | ```systemverilog 130 | // GOOD EXAMPLE 131 | assign next_len = len + 16'd8; 132 | assign next_pkt_len = pkt_len + 16'd4; 133 | ``` 134 | 135 | ### Пример #4 136 | Неправильно: 137 | ```systemverilog 138 | // BAD EXAMPLE 139 | always_ff @( posedge clk_i ) 140 | begin 141 | pkt_data_d1 <= pkt_data_i; 142 | pkt_empty_d1 <= pkt_empty_i; 143 | end 144 | ``` 145 | 146 | Правильно: 147 | ```systemverilog 148 | // GOOD EXAMPLE 149 | always_ff @( posedge clk_i ) 150 | begin 151 | pkt_data_d1 <= pkt_data_i; 152 | pkt_empty_d1 <= pkt_empty_i; 153 | end 154 | ``` 155 | 156 | Допускается: 157 | ```systemverilog 158 | // GOOD EXAMPLE 159 | always_ff @( posedge clk_i ) begin 160 | pkt_data_d1 <= pkt_data_i; 161 | pkt_empty_d1 <= pkt_empty_i; 162 | end 163 | ``` 164 | 165 | ## Примеры использования конструкций и операторов 166 | 167 | ### Логические выражения 168 | - Необходимо использовать логическое И/ИЛИ/НЕ (`&&`/`||`/`!`) при описании каких-то логических выражений, 169 | а не их побитовые аналоги (`&`/`|`/`~`). 170 | - Любые сравнения, отрицания, и пр. берутся в скобки. 171 | 172 | #### Пример #1 173 | ```systemverilog 174 | logic data_ready; 175 | 176 | assign data_ready = ( pkt_word_cnt > 8'd5 ) && ( !data_enable ) && ( pkt_len <= 16'd64 ); 177 | ``` 178 | 179 | #### Пример #2 180 | 181 | ```systemverilog 182 | always_comb begin 183 | if( data_enable && ( fifo_bytes_empty >= pkt_size ) ) 184 | ... 185 | end 186 | ``` 187 | 188 | #### Пример #3 189 | 190 | ```systemverilog 191 | assign start_stb_o = ( ( state == RED_S ) && ( next_state != IDLE_S ) ) || 192 | ( ( state == YELLOW_S ) && ( next_state != GREEN_S ) ); 193 | ``` 194 | 195 | ### `if-else` 196 | 197 | ```systemverilog 198 | if( a > 5 ) 199 | d = 5; 200 | else 201 | d = 15; 202 | ``` 203 | 204 | ### `if-else` вместе с `begin/end` 205 | 206 | ```systemverilog 207 | if( a > 5 ) begin 208 | c = 7; 209 | d = 5; 210 | end else begin 211 | c = 3; 212 | d = 7; 213 | end 214 | ``` 215 | 216 | ### Вложенный `if-else` 217 | 218 | ```systemverilog 219 | if( a > 5 ) 220 | c = 7; 221 | else if( a > 3 ) 222 | c = 4; 223 | else 224 | c = 5; 225 | ``` 226 | 227 | ### Тернарный оператор `?` 228 | 229 | ```systemverilog 230 | assign y = ( a > c ) ? ( d ) : ( e ); 231 | ``` 232 | 233 | Обращаю внимание, что условие и переменные `d`, `e` взяты в круглые скобки. 234 | 235 | Для облегчения чтения (и проверки/написания) допускается (и во многих случаях рекомендуется) писать в две строки: 236 | ```systemverilog 237 | assign y = ( a > c ) ? ( cnt_gt_zero ): 238 | ( cnt_le_zero ); 239 | ``` 240 | 241 | ### `case` 242 | 243 | Каждый из вариантов описывается в своем `begin/end` блоке, отделяя 244 | варианты друг от друга пустой строкой. 245 | 246 | ```systemverilog 247 | case( opcode[1:0] ) 248 | 2'b00: begin 249 | next_state = OR_S; 250 | end 251 | 252 | 2'b01: begin 253 | next_state = AND_S; 254 | end 255 | 256 | 2'b10: begin 257 | next_state = NOT_S; 258 | end 259 | 260 | 2'b11: begin 261 | next_state = XOR_S; 262 | end 263 | 264 | default: begin 265 | next_state = AND_S; 266 | end 267 | endcase 268 | ``` 269 | 270 | Если `case` простой и не подразумевает никаких вложенных конструкций в `begin/end` блоке, 271 | то допускается делать так (для уменьшения строк и текста): 272 | 273 | ```systemverilog 274 | case( opcode[1:0] ) 275 | 2'b00: next_state = OR_S; 276 | 2'b01: next_state = AND_S; 277 | 2'b10: next_state = NOT_S; 278 | 2'b11: next_state = XOR_S; 279 | default: next_state = AND_S; 280 | endcase 281 | ``` 282 | 283 | Заметьте, что здесь выровнено по `next_state` для облегчения чтения. 284 | 285 | ### `function` и `task` 286 | 287 | ```systemverilog 288 | function int calc_sum( input int a, int b ); 289 | return a + b; 290 | endfunction 291 | ``` 292 | 293 | ```systemverilog 294 | task receive_pkt( output packet_t pkt ); 295 | ... 296 | endtask 297 | ``` 298 | 299 | При большом количестве аргументов допустимо сводить к описанию в столбик: 300 | ```systemverilog 301 | task some_magic( 302 | input int a, 303 | input bit [31:0] data, 304 | output packet_t pkt 305 | ); 306 | ... 307 | endtask 308 | ``` 309 | Однако, если у вас большое количество аргументов, возможно что-то вы делаете не так... 310 | 311 | ### Еще один пример 312 | ```systemverilog 313 | if( condition1 ) begin 314 | for( int i = 0; i < 10; i = i + 1 ) 315 | statement1; 316 | end else begin 317 | if( condition2 ) 318 | statement2; 319 | else if( condition3 ) 320 | statement3; 321 | else 322 | statement4; 323 | end 324 | ``` 325 | 326 | ## Комментарии 327 | Комментарии пишутся на английском языке. 328 | После знака комментария `//` ставится один пробел. 329 | 330 | Желательно писать комментарии перед (возле) тем блоком, который необходимо пояснить: 331 | ```systemverilog 332 | 333 | // current packet word number 334 | always_ff @( posedge clk_i or posedge rst_i ) 335 | if( rst_i ) 336 | pkt_word <= 16'd0; 337 | else if( pkt_valid && pkt_eop ) // reset counter at last valid packet word 338 | pkt_word <= 'd0; 339 | else if( pkt_valid ) 340 | pkt_word <= pkt_word + 1'd1; 341 | ``` 342 | 343 | Примечание: 344 | - для описания комментариев необходимо пользоваться здравым смыслом и 345 | классическим рассуждением "лучший комментарий тот, которого нет". 346 | Пример, который расположен выше, показывает *где* необходимо располагать 347 | комментарии, но не надо комментировать каждый блок и каждую строчку 348 | (с этой точки зрения пример не совсем корректен). 349 | 350 | ## Наименование переменных и модулей 351 | 352 | - Стиль названия переменных, функций, тасков и модулей - `snake_case`, т.е. слова или префиксы 353 | разделяются `_`, и всё пишется маленькими буквами. 354 | 355 | Пример: 356 | - `pkt_anlz` 357 | - `is_ptp_pkt` 358 | - `super_task` 359 | 360 | - Большими буквами (но так же через `_`) пишутся только константы, параметры, дефайны, состояния FSM 361 | 362 | Пример: 363 | - `parameter A_WIDTH = 9;` 364 | - `define CRC_LEN 32'd4` 365 | 366 | - Имя переменной должно отражать ее назначение. 367 | Следует избегать чрезмерно длинных и, особенно, чрезмерно коротких названий (`rd_addr` лучше чем `ra`). 368 | 369 | - Названия портов должны содержать суффикс `_i` для входных, `_o` для выходных, `_io` для 370 | двунаправленных сигналов. 371 | 372 | ## Описание клоков 373 | - Для описания клоков используется префикс `clk`. 374 | - При объявлении портов модуля клоки описываются в самом начале. 375 | - Если необходимо указать, какой частоты предполагается этот клок, то необходимо использовать шаблон `clk_XmABC`, где: 376 | - `X` - значение частоты в МГц 377 | - `ABC` - оставшая часть (старшие три знака), если она не равна нулю. 378 | Примеры: 379 | - `2.048 МГц -> clk_2m048` 380 | - `156.25 МГц -> clk_156m25` 381 | - `250 МГц -> clk_250m` 382 | - Большинству модулей без разницы, какой именно клок (конкретное точное значение) к нему приходит, 383 | поэтому если разрабатываете модуль, который будет работать на частоте 100 МГц, то для названия порта модуля 384 | следует использовать общее название `clk_i`, а где-то "сверху" подключить нужные 100 МГц: 385 | 386 | ```systemverilog 387 | .clk_i ( clk_100m ), 388 | .... 389 | ``` 390 | 391 | - Если нужна какая-то параметризация в зависимости от клока, то необходимо сделать параметр в модуле: 392 | 393 | ```systemverilog 394 | parameter CLK_FREQ_HZ = 100_000_000; 395 | ``` 396 | 397 | И затем его использовать в модуле. 398 | 399 | - Все триггеры должны защелкиваться только по положительному фронту `posedge`. 400 | Исключение: требования физических интерфейсов (например, DDR). 401 | 402 | Категорически **запрещается**: 403 | - использовать сигнал клока для описания условий или создания комбинационной логики, типа: 404 | 405 | ```systemverilog 406 | assign my_super_clk = clk_i && ( cnt == 8'd4 ); 407 | ``` 408 | 409 | ## Описание ресетов 410 | Есть два типа ресета (сброса): 411 | - асинхронный `rst` 412 | - синхронный `srst` 413 | 414 | Чаще всего это используется как вход для описываемого модуля: 415 | ```systemverilog 416 | ... 417 | 418 | input clk_i, 419 | input rst_i, 420 | 421 | ... 422 | ``` 423 | 424 | Активным уровнем для сброса считаем `1`, т.е. когда `rst_i == 1'b1`, то схема находится в ресете. 425 | 426 | Описание триггера с асинхронным ресетом: 427 | ``` 428 | always_ff @( posedge clk_i or posedge rst_i ) 429 | if( rst_i ) 430 | cnt <= 8'd0; 431 | else 432 | ... 433 | ``` 434 | 435 | Описание триггера с синхронным ресетом: 436 | ``` 437 | always_ff @( posedge clk_i ) 438 | if( srst_i ) 439 | cnt <= 8'd0; 440 | else 441 | ... 442 | ``` 443 | 444 | Описание триггера с синхронным и асинхронным ресетом: 445 | ``` 446 | always_ff @( posedge clk_i or posedge rst_i ) 447 | if( rst_i ) 448 | cnt <= 8'd0; 449 | else if( srst_i ) 450 | cnt <= 8'd0; 451 | else 452 | ... 453 | ``` 454 | 455 | Для большинства модулей используется **асинхронный сброс** для приведения модуля в начальное состояние. 456 | 457 | Категорически **запрещается**: 458 | - путать синхронный и асинхронный сброс как по заведению сигналов, так и по их наименованию 459 | - создавать модули без сбросов. Исключение: модули без триггеров/памяти (чистая комбинационная логика). 460 | - производить какие-то манипуляции с асинхронным сбросом, типа: 461 | ```systemverilog 462 | logic [7:0] cnt; 463 | assign my_rst = rst_i || ( cnt == 8'd5 ); 464 | 465 | always_ff @( posedge clk_i or posedge my_rst ) 466 | if( my_rst ) 467 | cnt <= 8'd0; 468 | else 469 | ... 470 | ``` 471 | 472 | ## Описание конечного автомата (FSM) 473 | 474 | Для описания конечного автомата используется следующая схема (в интернете она ходит под названием `FSM 3 process`): 475 | 476 | ```systemverilog 477 | enum logic [1:0] { IDLE_S, 478 | RUN_S, 479 | WAIT_S } state, next_state; 480 | 481 | always_ff @( posedge clk_i or posedge rst_i ) 482 | if( rst_i ) 483 | state <= IDLE_S; 484 | else 485 | state <= next_state; 486 | 487 | always_comb 488 | begin 489 | next_state = state; 490 | 491 | case( state ) 492 | IDLE_S: begin 493 | if( ... ) 494 | next_state = RUN_S; 495 | end 496 | 497 | RUN_S: begin 498 | if( ... ) 499 | next_state = WAIT_S; 500 | else if( ) 501 | next_state = IDLE_S; 502 | end 503 | 504 | WAIT_S: begin 505 | if( ... ) 506 | next_state = RUN_S; 507 | end 508 | 509 | default: begin 510 | next_state = IDLE_S; 511 | end 512 | 513 | endcase 514 | end 515 | 516 | // some logic, that generates output values on state and next_state signals 517 | 518 | ``` 519 | 520 | Пояснение: 521 | - `state` обозначает текущее состояние, `next_state` - то, которое будет в `state` на следующем такте. 522 | - `IDLE_S` - дефолтное состояние, поэтому его устанавливают во время асинхронного сброса и `default` в `case`-блоке. 523 | для удобства считаем считаем, что это состояние должно идти первым в `enum` списке. 524 | 525 | - Имена состояний FSM описываются большими буквами и должны содержать суффикс `_S` (`IDLE_S`, `TX_S`, `WAIT_S` и т.д.). 526 | 527 | Категорически **запрещается**: 528 | - делать в одном модуле больше одного конечного автомата 529 | - в блоке, где происходит назначение на `next_state` делать назначение еще каких-либо сигналов 530 | - производить какие-либо другие операции, кроме операции сравнения (`==`, `!=`) с переменными `state`, `next_state`, например: 531 | 532 | ```systemverilog 533 | assign b = ( state > RED_S ); 534 | assign c = ( state + 3'd2 ) > ( IDLE_S ); 535 | ``` 536 | 537 | ## Размещение исходников 538 | 539 | Исходники размещаются в файлах. 540 | Правило простое: один модуль, package, интерфейса - один файл. Название файла - название этого модуля. 541 | 542 | - Расширения: 543 | - Verilog: `.v` 544 | - SystemVerilog: `.sv` 545 | - Verilog Header: `.vh` 546 | - SystemVerilog Header: `.svh` 547 | - VHDL: `.vhd` 548 | 549 | - Файлы содержащие только декларации package следует помечать окончанием `_pkg`: `func_pkg.sv` 550 | - Файлы содержащие только константами, функции, таски, которые подгружаются в исходник при помощи include, следует именовать расширением .vh Пример 551 | `defines.vh`. 552 | 553 | ## Описание логических блоков/элементов 554 | 555 | Общее: 556 | - В одном блоке желательно описывать присваивание только в **одну** переменную. 557 | - Присваивания в переменную может происходить только в одном блоке. 558 | - Желательно блоки разделять пустой строчкой (сверху и снизу). 559 | 560 | ### Комбинационная логика 561 | - Для описания комбинационных схем можно использовать: 562 | - блок `always_comb` 563 | - непрерывное (continuous) присваивание `assign` 564 | - Разрешается использовать только блокирующие присваивание `=`. 565 | 566 | Пример: 567 | ```systemverilog 568 | always_comb begin 569 | a = b + d; 570 | end 571 | ``` 572 | 573 | Категорически **запрещается**: 574 | - описывать логику при "создании" переменной: 575 | ```systemverilog 576 | logic a = b && d; 577 | ``` 578 | 579 | - описывать начальные значения для комбинационной логики: 580 | ```systemverilog 581 | logic [7:0] a = 8'd5; 582 | 583 | assign a = b + d; 584 | ``` 585 | 586 | ### Триггеры 587 | - используется блок `always_ff` 588 | - разрешается использовать только неблокирующие присваивание (`<=`). 589 | 590 | Пример: 591 | ```systemverilog 592 | logic [31:0] data_d1; 593 | logic [7:0] cnt; 594 | 595 | always_ff @( posedge clk_i ) 596 | begin 597 | data_d1 <= data_i; 598 | end 599 | 600 | always_ff @( posedge clk_i or posedge rst_i ) 601 | if( rst_i ) 602 | cnt <= '0; 603 | else if( cnt == 8'h92 ) 604 | cnt <= 'd0; 605 | else 606 | cnt <= cnt + 1'd1; 607 | ``` 608 | 609 | #### Создание триггеров с начальным ненулевым значением 610 | 611 | ```systemverilog 612 | logic [7:0] cnt = 8'd5; 613 | 614 | always_ff @( posedge clk_i or posedge rst_i ) 615 | if( rst_i ) 616 | cnt <= 8'd5; 617 | else 618 | ... 619 | ``` 620 | 621 | ### Защелки (латчи) 622 | 623 | Используется блок `always_latch`. 624 | 625 | Пример: 626 | ```systemverilog 627 | always_latch 628 | begin 629 | if( en ) 630 | data = data_i; 631 | end 632 | ``` 633 | 634 | Категорически **запрещается** 635 | - использовать/создавать латчи в синхронных схемах. 636 | 637 | ## Описание и объявление модулей 638 | 639 | ### Описание модуля 640 | Каждый модуль описывается в отдельном файле. 641 | 642 | Файл `some_module.sv`: 643 | 644 | ```systemverilog 645 | module some_module #( 646 | parameter DATA_WIDTH = 32, 647 | parameter CNT_WIDTH = 8 648 | )( 649 | input clk_i, 650 | input rst_i, 651 | 652 | input [DATA_WIDTH-1:0] data_i, 653 | input data_val_i, 654 | 655 | output logic [CNT_WIDTH-1:0] cnt_o 656 | ); 657 | 658 | // some code... 659 | 660 | endmodule 661 | ``` 662 | 663 | Т.е.: 664 | - Описание параметров и сигналов начинается с отступа (2 пробела). 665 | 666 | - При описании параметров и сигналов всё выравнивается по колонкам: 667 | - название сигналов 668 | - квадратные скобки 669 | - зарезервированные слова типа `parameter`, `input`, `output` 670 | - знак `=` в параметрах 671 | 672 | - Сигналы не смешиваются в кучу. Те сигналы, которые формируют логический интерфейс 673 | должны отделятся пустой строкой. 674 | 675 | - Предпочтительно сначала описывать входные сигналы, потом выходные, однако, 676 | первочердным должен соблюдаться принцип интерфейсов, который описан выше. 677 | 678 | - Первым в описании сигналов должно идти описание клоков/синхросигналов и сбросов. 679 | 680 | ### Инстанс модуля 681 | 682 | ```systemverilog 683 | some_module #( 684 | .DATA_WIDTH ( 64 ), 685 | .CNT_WIDTH ( 4 ) 686 | ) some_module ( 687 | .clk_i ( rx_clk ), 688 | .rst_i ( main_rst ), 689 | 690 | .data_i ( rx_data ), 691 | .data_val_i ( rx_data_val ), 692 | 693 | .cnt_o ( cnt ) 694 | ); 695 | ``` 696 | 697 | Т.е.: 698 | - При подключении сигнала или переопределении параметра делается отступ (2 пробела). 699 | - Cкобки, точки, запятые выравниваются. 700 | - Для передачи параметров используется `#`, а не `defparam`. 701 | - Пустые строчки, которые отделяют логические интерфейсы (или сигналы, которые должны быть вместе) 702 | расположены так же как и в описании модуля. 703 | - Чаще всего зкземпляр модуля называется так же как и сам модуль; 704 | если экземпляров одного модуля несколько, то их названия 705 | дополняются суффиксами `_inst0`, `_inst1` ( либо просто `0`, `1` ) и т.д. 706 | Однако иногда названия получается слишком длинные и засчет вложенности модулей иерархический 707 | путь может быть очень длинным, что приведет к неудобству смотрения в ModelSim или TimeQuest. 708 | Поэтому допускается инстансы(!) модулей типа: `main_engine` сокращать до `me`. Однако без 709 | необходимости этим не злоупотреблять. 710 | 711 | ## Описание переменных 712 | 713 | Переменные в модуле "создаются" после описания сигналов модуля и до начала "работы" с этими сигналами. 714 | 715 | ```systemverilog 716 | output logic abc_o 717 | ); 718 | 719 | logic [7:0] cnt; 720 | logic cnt_en; 721 | 722 | logic [63:0] pkt_data; 723 | // ... some more signals 724 | 725 | // work with signal starts here 726 | ``` 727 | 728 | - Связанные переменные, как и сигналы модуля необходимо логически отделять пустой строкой. 729 | - Допускается создавать сигналы "рядом" с тем местом, где они употребляются, например: 730 | ```systemverilog 731 | logic [2:0] vlan_mpls_cnt; 732 | // more signals 733 | 734 | // some code 735 | always_comb begin 736 | if( vlan_mpls_cnt > 2 ) 737 | ... 738 | end 739 | 740 | // calc vlan_mpls_cnt 741 | logic [1:0] vlan_cnt; 742 | logic [1:0] mpls_cnt; 743 | 744 | assign vlan_cnt = vlan[0] + vlan[1] + vlan[2]; 745 | assign mpls_cnt = mpls[0] + mpls[1] + mpls[2]; 746 | 747 | assign vlan_mpls_cnt = vlan_cnt + mpls_cnt; 748 | ``` 749 | 750 | ## Прочее 751 | 752 | - Категорически запрещается реализовывать в устройствах сигналы с нулевым 753 | активным уровнем. Исключением могут быть стандартные интерфейсы, где такие 754 | сигналы изначально предусмотрены (sram interface, к примеру). Допускается 755 | наличие подобных сигналов на входах FPGA, но на верхнем уровне иерархии (в top-файле) 756 | они должны быть проинвертированы. 757 | 758 | - При наличии двунаправленных шин, направления передачи должны развязываться на 759 | верхнем уровне иерархии (top-файле). 760 | 761 | - В RTL описаниях использовать тип logic (за исключением тех случаев, когда 762 | необходимы множественные драйверы). Это позволит выявить ошибки, связанные с 763 | множественным назначением на этапе компиляции и ошибки, вызванные отсутствием 764 | инициализации (так как logic инициализируется неопределенным значением). 765 | 766 | - Настоятельно рекомендуется защелкивать в триггеры выходные сигналы модулей. 767 | Это повысит максимальную скорость работы устройства. 768 | 769 | - Все критичные к быстродействию узлы по возможности следует размещать в 770 | отдельном модуле. Это позволит оптимизировать его независимо от прочих узлов. 771 | 772 | - Все макроподстановки (`define) должны определяться в отдельном файле либо в 773 | модуле верхнего уровня иерархии. 774 | 775 | - Hard-code недопустим и, по возможности, модули должны быть параметризованы. 776 | Исключения возможны в тех случаях, когда параметризуемость делает программу 777 | менее читабельной и понятной. Главное требование - модуль не должен требовать 778 | допиливания после присвоения нового значения параметру, т.е. должен полностью 779 | сохранять функционал. 780 | -------------------------------------------------------------------------------- /examples/draw_field_helper.sv: -------------------------------------------------------------------------------- 1 | module draw_field_helper #( 2 | parameter PIX_WIDTH = 12, 3 | 4 | parameter BRICK_X = 20, 5 | parameter BRICK_Y = 25, 6 | 7 | parameter BRICK_X_CNT = 10, 8 | parameter BRICK_Y_CNT = 20, 9 | 10 | parameter BORDER_X = 2, 11 | parameter BORDER_Y = 2 12 | ) ( 13 | 14 | input clk_i, 15 | 16 | input [PIX_WIDTH-1:0] start_x_i, 17 | input [PIX_WIDTH-1:0] start_y_i, 18 | 19 | output [PIX_WIDTH-1:0] end_x_o, 20 | output [PIX_WIDTH-1:0] end_y_o, 21 | 22 | // current pix value 23 | input [PIX_WIDTH-1:0] pix_x_i, 24 | input [PIX_WIDTH-1:0] pix_y_i, 25 | 26 | output logic in_field_o, 27 | output logic in_brick_o, 28 | 29 | output logic [$clog2(BRICK_X_CNT)-1:0] brick_col_num_o, 30 | output logic [$clog2(BRICK_Y_CNT)-1:0] brick_row_num_o 31 | 32 | ); 33 | 34 | assign end_x_o = start_x_i + BORDER_X * ( BRICK_X_CNT + 1 ) + BRICK_X * BRICK_X_CNT - 1; 35 | assign end_y_o = start_y_i + BORDER_Y * ( BRICK_Y_CNT + 1 ) + BRICK_Y * BRICK_Y_CNT - 1; 36 | 37 | // значения границ, включая для col по X 38 | logic [BRICK_X_CNT-1:0][PIX_WIDTH-1:0] col_pix_start; 39 | logic [BRICK_X_CNT-1:0][PIX_WIDTH-1:0] col_pix_end; 40 | 41 | logic [BRICK_Y_CNT-1:0][PIX_WIDTH-1:0] row_pix_start; 42 | logic [BRICK_Y_CNT-1:0][PIX_WIDTH-1:0] row_pix_end; 43 | 44 | genvar g; 45 | generate 46 | for( g = 0; g < BRICK_X_CNT; g++ ) begin : g_col_pix 47 | assign col_pix_start[g] = ( g + 1 ) * BORDER_X + g * BRICK_X; 48 | assign col_pix_end[g] = col_pix_start[g] + BRICK_X - 1'd1; 49 | end 50 | endgenerate 51 | 52 | generate 53 | for( g = 0 ; g < BRICK_Y_CNT; g++ ) begin : g_row_pix 54 | assign row_pix_start[g] = ( g + 1 ) * BORDER_Y + g * BRICK_Y; 55 | assign row_pix_end[g] = row_pix_start[g] + BRICK_Y - 1'd1; 56 | end 57 | endgenerate 58 | 59 | // текущие значения 60 | logic [$clog2( BRICK_X_CNT )-1:0] brick_col_num; 61 | logic [$clog2( BRICK_Y_CNT )-1:0] brick_row_num; 62 | 63 | logic in_brick_col; 64 | logic in_brick_row; 65 | 66 | // просто смещенные значения 67 | logic [PIX_WIDTH-1:0] in_field_pix_x; 68 | logic [PIX_WIDTH-1:0] in_field_pix_y; 69 | 70 | assign in_field_pix_x = pix_x_i - start_x_i; 71 | assign in_field_pix_y = pix_y_i - start_y_i; 72 | 73 | 74 | // высчитываем текущий блок для отображения 75 | // сделано не очень оптимально - можно подумать... 76 | always_comb begin 77 | brick_col_num = '0; 78 | in_brick_col = 1'b0; 79 | 80 | for( int i = 0; i < BRICK_X_CNT; i++ ) begin 81 | if( ( in_field_pix_x >= col_pix_start[i] ) && 82 | ( in_field_pix_x <= col_pix_end[i] ) ) begin 83 | brick_col_num = i; 84 | in_brick_col = 1'b1; 85 | end 86 | end 87 | end 88 | 89 | always_comb begin 90 | brick_row_num = '0; 91 | in_brick_row = 1'b0; 92 | 93 | for( int i = 0; i < BRICK_Y_CNT; i++ ) begin 94 | if( ( in_field_pix_y >= row_pix_start[i] ) && 95 | ( in_field_pix_y <= row_pix_end[i] ) ) begin 96 | brick_row_num = i; 97 | in_brick_row = 1'b1; 98 | end 99 | end 100 | end 101 | 102 | always_ff @( posedge clk_i ) begin 103 | in_field_o <= ( pix_x_i >= start_x_i ) && ( pix_x_i <= end_x_o ) && 104 | ( pix_y_i >= start_y_i ) && ( pix_y_i <= end_y_o ); 105 | 106 | in_brick_o <= in_brick_col && in_brick_row; 107 | 108 | 109 | brick_col_num_o <= brick_col_num; 110 | brick_row_num_o <= brick_row_num; 111 | end 112 | 113 | endmodule 114 | -------------------------------------------------------------------------------- /examples/qstage.sv: -------------------------------------------------------------------------------- 1 | `include "defs.vh" 2 | 3 | module qstage #( 4 | parameter A_WIDTH = 4, 5 | parameter D_WIDTH = 16, 6 | 7 | parameter STAGE_NUM = 1, 8 | 9 | parameter OPT_LEVEL = 0 10 | ) ( 11 | 12 | input clk_i, 13 | input rst_i, 14 | 15 | qstage_ctrl_if ctrl_if, 16 | 17 | input lookup_en_i, 18 | input [A_WIDTH-1:0] lookup_addr_i, 19 | input [D_WIDTH-1:0] lookup_data_i, 20 | 21 | output lookup_en_o, 22 | output [A_WIDTH-1:0] lookup_addr_o, 23 | output [D_WIDTH-1:0] lookup_data_o 24 | 25 | ); 26 | 27 | localparam STAGE_A_WIDTH = ( STAGE_NUM == 0 ) ? ( 1 ) : ( 2*STAGE_NUM ); 28 | localparam MAX_DELAY = ( OPT_LEVEL == 0 ) ? ( 4 ) : ( 5 ); 29 | 30 | ram_data_t rd_data_w; 31 | 32 | logic [MAX_DELAY-1:1] lookup_en_d; 33 | logic [MAX_DELAY-1:1][A_WIDTH-1:0] lookup_addr_d; 34 | logic [MAX_DELAY-1:1][D_WIDTH-1:0] lookup_data_d; 35 | 36 | always_ff @( posedge clk_i or posedge rst_i ) 37 | if( rst_i ) begin 38 | for( int i = 1; i < MAX_DELAY; i++ ) begin 39 | lookup_en_d [ i ] <= '0; 40 | lookup_addr_d [ i ] <= '0; 41 | lookup_data_d [ i ] <= '0; 42 | end 43 | end else begin 44 | lookup_en_d [ 1 ] <= lookup_en_i; 45 | lookup_addr_d [ 1 ] <= lookup_addr_i; 46 | lookup_data_d [ 1 ] <= lookup_data_i; 47 | 48 | for( int i = 2; i < MAX_DELAY; i++ ) begin 49 | lookup_en_d [ i ] <= lookup_en_d [ i - 1 ]; 50 | lookup_addr_d [ i ] <= lookup_addr_d [ i - 1 ]; 51 | lookup_data_d [ i ] <= lookup_data_d [ i - 1 ]; 52 | end 53 | end 54 | 55 | 56 | simple_ram #( 57 | .DATA_WIDTH ( $bits( ram_data_t ) ), 58 | .ADDR_WIDTH ( STAGE_A_WIDTH ) 59 | ) tr_ram ( 60 | 61 | .clk ( clk_i ), 62 | 63 | .write_addr ( ctrl_if.wr_addr[STAGE_A_WIDTH-1:0] ), 64 | .data ( ctrl_if.wr_data ), 65 | .we ( ctrl_if.wr_en ), 66 | 67 | .read_addr ( lookup_addr_i[STAGE_A_WIDTH-1:0] ), 68 | .q ( rd_data_w ) 69 | ); 70 | 71 | // less or equal values l, m, r 72 | logic le_l; 73 | logic le_m; 74 | logic le_r; 75 | 76 | generate 77 | if( OPT_LEVEL == 0 ) begin : no_opt 78 | assign le_l = ( lookup_data_d[2] <= rd_data_w.l ); 79 | assign le_m = ( lookup_data_d[2] <= rd_data_w.m ); 80 | assign le_r = ( lookup_data_d[2] <= rd_data_w.r ); 81 | end else begin : opt 82 | always_ff @( posedge clk_i ) begin 83 | le_l <= ( lookup_data_d[2] <= rd_data_w.l ); 84 | le_m <= ( lookup_data_d[2] <= rd_data_w.m ); 85 | le_r <= ( lookup_data_d[2] <= rd_data_w.r ); 86 | end 87 | end 88 | endgenerate 89 | 90 | logic [1:0] next_addr_append; 91 | 92 | always_ff @( posedge clk_i ) 93 | begin 94 | casex( { le_l, le_m, le_r } ) 95 | 3'b01x: next_addr_append <= 'd1; 96 | 3'b001: next_addr_append <= 'd2; 97 | 3'b000: next_addr_append <= 'd3; 98 | default: next_addr_append <= 'd0; 99 | endcase 100 | end 101 | 102 | assign lookup_addr_o = ( STAGE_A_WIDTH == 1 ) ? ( next_addr_append ): 103 | ( { lookup_addr_d[MAX_DELAY-1][STAGE_A_WIDTH-1:0], next_addr_append } ); 104 | 105 | assign lookup_en_o = lookup_en_d [MAX_DELAY-1]; 106 | assign lookup_data_o = lookup_data_d[MAX_DELAY-1]; 107 | 108 | endmodule 109 | -------------------------------------------------------------------------------- /examples/reverse_counter.sv: -------------------------------------------------------------------------------- 1 | module reverse_counter #( 2 | parameter CNT_WIDTH = 32 3 | ) ( 4 | 5 | input clk_i, 6 | input rst_i, 7 | 8 | input reverse_i, 9 | 10 | input [CNT_WIDTH-1:0] set_value_data_i, 11 | input set_value_en_i, 12 | 13 | output logic [CNT_WIDTH-1:0] cnt_o 14 | 15 | ); 16 | 17 | always_ff @( posedge clk_i or posedge rst_i ) 18 | if( rst_i ) 19 | cnt_o <= 'd0; 20 | else if( set_value_en_i ) 21 | cnt_o <= set_value_data_i; 22 | else if( reverse_i ) 23 | cnt_o <= cnt_o - 1'd1; 24 | else 25 | cnt_o <= cnt_o + 1'd1; 26 | 27 | endmodule 28 | --------------------------------------------------------------------------------