<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="https://skinterqwe.github.io//feed.xml" rel="self" type="application/atom+xml" /><link href="https://skinterqwe.github.io//" rel="alternate" type="text/html" /><updated>2024-05-27T05:40:55+00:00</updated><id>https://skinterqwe.github.io//feed.xml</id><title type="html">Homer’s BLOG</title><subtitle>ASIC&lt;br/&gt;
Hardware&lt;br/&gt;
FPGA&lt;br/&gt;
MCU&lt;br/&gt;
&lt;a href=&quot;/static/img/wechat.jpg&quot; title=&quot;WeChat&quot;&gt;
  &lt;i class=&quot;fab fa-weixin&quot;&gt;&lt;/i&gt;
&lt;/a&gt;
&lt;a href=&quot;wxdxd6011@163.com&quot; title=&quot;Mail&quot;&gt;
  &lt;i class=&quot;fas fa-envelope&quot;&gt;&lt;/i&gt;
&lt;/a&gt;
&lt;a href=&quot;https://github.com/skinterqwe&quot; title=&quot;Github&quot;&gt;
  &lt;i class=&quot;fab fa-github&quot;&gt;&lt;/i&gt;
&lt;/a&gt;
&lt;a href=&quot;https://www.zhihu.com/people/skinterqwe/activities&quot; title=&quot;知乎&quot;&gt;
  &lt;i class=&quot;fab fa-zhihu&quot;&gt;&lt;/i&gt;
&lt;/a&gt;
&lt;br/&gt;
&lt;iframe
  src=&quot;https://music.163.com/outchain/player?type=2&amp;id=1842801328&amp;auto=1&amp;height=32&quot;
  width=100%
  height=52
  frameborder=&quot;no&quot;
  border=&quot;0&quot;
  marginwidth=&quot;0&quot;
  marginheight=&quot;0&quot;
&gt;&lt;/iframe&gt;
</subtitle><entry><title type="html">Homer’s first blog</title><link href="https://skinterqwe.github.io//_posts/2024-05-21-my-first-blog/" rel="alternate" type="text/html" title="Homer’s first blog" /><published>2024-05-21T02:12:10+00:00</published><updated>2024-05-21T02:12:10+00:00</updated><id>https://skinterqwe.github.io//_posts/my-first-blog</id><content type="html" xml:base="https://skinterqwe.github.io//_posts/2024-05-21-my-first-blog/"><![CDATA[<pre><code class="language-verilog">module my_module (
    input   wire logic          clk,
    input   wire logic          en,
    input   wire logic [7:0]    din,
    inout   wire logic [7:0]    bus,
    output  var  logic [7:0]    dout,
    output  var  logic [7:0]    bus
);
</code></pre>]]></content><author><name></name></author><category term="blog" /><summary type="html"><![CDATA[module my_module ( input wire logic clk, input wire logic en, input wire logic [7:0] din, inout wire logic [7:0] bus, output var logic [7:0] dout, output var logic [7:0] bus );]]></summary></entry><entry><title type="html">systemverilog设计</title><link href="https://skinterqwe.github.io//_posts/2024-05-21-sv-for_design/" rel="alternate" type="text/html" title="systemverilog设计" /><published>2024-05-21T00:00:00+00:00</published><updated>2024-05-21T00:00:00+00:00</updated><id>https://skinterqwe.github.io//_posts/sv-for_design</id><content type="html" xml:base="https://skinterqwe.github.io//_posts/2024-05-21-sv-for_design/"><![CDATA[<h1 id="1-过程块">1. 过程块</h1>
<h2 id="11-组合逻辑过程块">1.1 组合逻辑过程块</h2>
<p>always_comb不需要指明敏感列表，使用阻塞赋值(=)，如果过程内部写出锁存器，则会警告或报错</p>

<pre><code class="language-systemverilog">always_comb begin
	if(!mode)
		y = a + b;
	else
		y = a - b;
end
</code></pre>
<p><strong><em>注意</em></strong>：always@(*)并没有组合逻辑的语义，即可能产生latch</p>

<p><strong><em>注意</em></strong>：如果过程块要调用函数，最好用always_comb，因为always@(*)不会推断函数中读取的信号</p>
<h2 id="12-时序逻辑过程块">1.2 时序逻辑过程块</h2>
<p>always_ff，使用非阻塞赋值(&lt;=)，如果过程内部写出组合逻辑，则会报错</p>
<pre><code class="language-systemverilog">always_ff @ (posedge clk, negedge rst_n) begin
	if(!rst_n) 
		q &lt;= 0;
	else 
		q &lt;= d;
end
</code></pre>
<h2 id="13-锁存逻辑过程块">1.3 锁存逻辑过程块</h2>
<p>always_latch，使用非阻塞赋值(&lt;=)，如果写成其他电路，则会警告或报错</p>
<pre><code class="language-systemverilog">always_latch
	if(en)
		q &lt;= d;
</code></pre>

<h1 id="2-任务和函数">2. 任务和函数</h1>
<p>TODO</p>

<h1 id="3-for语句">3. for语句</h1>

<p>2种写法：
比如描述一个Reduced-xor电路，如下图</p>

<p><strong><em>第1种写法</em></strong></p>
<pre><code class="language-systemverilog">module reduced_xor_gen
	#(parameter N=8)
	(
	input logic [N-1:0] a,
	output logic y
	)
	
	logic [N-1:0] p;

	assign p[0] = a[0];
	
	generate
		genvar i;
		for(i=1; i&lt;N; i=i+1)
			assign p[i] = a[i] ^ p[i-1];
	endgenerate

	assign y = P[N-1];

endmodule
</code></pre>
<p>第1种写法也是verilog支持的写法</p>

<p><strong><em>第2种写法</em></strong></p>
<pre><code class="language-systemverilog">module reduced_xor_gen
	#(parameter N=8)
	(
	input logic [N-1:0] a,
	output logic y
	)
	
	always_comb
	begin
		logic tmp;
		tmp = a[0];
		for (int i=1; i&lt;N; i=i+1)
			tem = a[i] ^ tmp;
		y = tmp;
	end

endmodule
</code></pre>
<p>第2种写法只在sv中支持，i为声明的局部变量。当for循环启动时，就自动创建这个变量并初始化，当循环推出时，这个变量就被清楚</p>

<h1 id="3-数组结构体和联合体">3. 数组，结构体和联合体</h1>
<h2 id="31-结构体">3.1 结构体</h2>
<h3 id="结构体定义">结构体定义</h3>
<pre><code class="language-systemverilog">// IEEE 754 Binary 32 encoding
typedef struct packed {
    logic sign;
    logic[FLOAT32_EXP_WIDTH - 1:0] exponent;
    logic[FLOAT32_SIG_WIDTH - 1:0] significand;
} float32_t;
</code></pre>
<h3 id="使用">使用</h3>
<pre><code class="language-systemverilog">float32_t fop1;

assign fop1 = '{1'b1, 8'h12, 23'h111111};

assign s = fop1.sign;
assign exp = fop1.exponent;
assign sign = fop1.significand;
</code></pre>

<p>TODO</p>

<h1 id="4-sv声明的位置">4. sv声明的位置</h1>
<p>包含以下几个内容：package, $unit编译声明空间, 未命名块中的声明, timescale</p>
<h2 id="41-package">4.1 package</h2>
<p>package中可以包含的可综合的结构有：</p>

<ol>
  <li>parameter和localparameter常量定义</li>
  <li>const常量定义？</li>
  <li>typedef用户定义类型</li>
  <li>automatic task和function定义(static类型的task和function不可综合)</li>
  <li>从其他包中import语句？</li>
  <li>操作数重载定义？</li>
</ol>

<h3 id="411-定义如下">4.1.1 定义如下：</h3>
<pre><code class="language-systemverilog">package definitions;

	parameter VERSION = "1.1";
	typedef enum {ADD, SUM, MUL} opcode_t;
	typedef struct {
		logic [31:0] a, b;
		opcode_t opcode;
	} instruction_t;

	function automatic [31:0] mul (input [31:0] a, b);
		return a * b;
	endfunction

endpackage
</code></pre>
<p><strong><em>注意</em></strong>：包中的参数不能重新定义（verilog中可以对parameter重新定义）
<strong><em>注意</em></strong>：包中定义的任务和函数必须声明为automatic，并且不能包含静态变量</p>

<h3 id="412-引用包的内容">4.1.2 引用包的内容</h3>
<p>4种方式：</p>
<ol>
  <li>用范围解析操作符直接引用
    <pre><code class="language-systemverilog">logic definitions::instruction inst;
</code></pre>
  </li>
  <li>将包中特定子项导入到模块或接口中
    <pre><code class="language-systemverilog">import definitions::instruction;
logic instruction inst;
</code></pre>
  </li>
  <li>用通配符导入包中的子项到模块或接口中
    <pre><code class="language-systemverilog">import definitions::*;
logic instruction inst;
always_comb begin
 case(inst.opcode)
     ADD: result = inst.a + inst.b;
     SUB: result = inst.a - inst.b;
     MUL: result = mul(inst.a * inst.b);
 endcase
end
</code></pre>
  </li>
  <li>将包中子项导入到$unit声明域中
由于不能在关键字module和模块端口定义之间加一个import语句，因此，对于模块端口，包名任须显示引用，例如：</li>
</ol>

<pre><code class="language-systemverilog">module ALU
(input definitions::instruction_t inst,
 input logic [31:0] result
)

import definitions::*;
logic instruction inst;
always_comb begin
	case(inst.opcode)
		ADD: result = inst.a + inst.b;
		SUB: result = inst.a - inst.b;
		MUL: result = mul(inst.a * inst.b);
	endcase
end
</code></pre>
<p>将包中子项导入到$unit声明域中：</p>
<pre><code class="language-systemverilog">import definitions::*;
module ALU
(input instruction_t inst,
 input logic [31:0] result
)

logic instruction inst;
always_comb begin
	case(inst.opcode)
		ADD: result = inst.a + inst.b;
		SUB: result = inst.a - inst.b;
		MUL: result = mul(inst.a * inst.b);
	endcase
end
</code></pre>
<h1 id="42-unit编译声明空间">4.2 $unit编译声明空间</h1>
<p><strong><em>注意</em></strong>：当多个文件同时进行编译时，只有一个$unit域
当单个文件进行编译时，必须将包中子项导入到$unit域中（每个文件会产生一个$unit域）
当多个文件一起进行编译时，会发生包中子项多次导入的情况（非法），因此，需要使用条件编译
defines.pkg文件如下：</p>
<pre><code class="language-systemverilog">`ifndef __DEFINES_SVH
`define __DEFINES_SVH

package defines;

endpackage : defines
</code></pre>
<p>每个需要包中定义的设计都应该将</p>
<pre><code class="language-systemverilog">`include "defines.pkg"
</code></pre>
<p>放入文件的开始</p>

<h1 id="43-未命名块中的声明">4.3 未命名块中的声明</h1>
<p>verilog允许在命名的begin…end块中声明局部变量</p>
<pre><code class="language-systemverilog"> module chip (input clock);
 	integer i; // declaration at module level
 	always @(posedge clock)
 		begin: loop
 		// named block
 		integer i;
		// local variable
 		for (i=0; i&lt;=127; i=i+1) begin
 			...
 		end
 	end
 endmodule
</code></pre>
<p>sv允许在未命名的begin…end块中声明局部变量</p>
<pre><code class="language-systemverilog"> module chip (input clock);
 	integer i; // declaration at module level
 	always @(posedge clock)
 		begin
 		integer i;
 		// unnamed block 
		// local variable
 		for (i=0; i&lt;=127; i=i+1) begin
 			...
 		end
 	end
 endmodule
</code></pre>
<h1 id="44-timescale">4.4 timescale</h1>
<p>TODO</p>
<h1 id="5-层次化设计">5. 层次化设计</h1>

<h1 id="6-接口">6. 接口</h1>
<h2 id="61-接口的概念">6.1 接口的概念</h2>

<h2 id="62-接口声明">6.2 接口声明</h2>
<p>接口可以像模块那样拥有端口</p>

<p><strong><em>这样，clock, resetN, test_mode不需要像分立端口那样传递给每个模块实例</em></strong></p>

<p>例如：</p>
<pre><code class="language-systemverilog">interface main_bus (input logic clock, resetN, test_mode);
	wire [15:0] data;
	wire [15:0] addr;
	......
endinterface
</code></pre>
<p>顶层网表如下：</p>
<pre><code class="language-systemverilog">module top(input logic clock, resetN, test_mode);
	logic [15:0] pc;
	logic [7:0]  inst;

main_bus bus(
	.clock(clock),
	.resetN(resetN),
	.testmode(test_mode)
);

processor proc1(
	.bus(bus),
	.pc(pc),
	.inst(inst)
);
endmodule
</code></pre>
<h2 id="63-将端口用作模块端口">6.3 将端口用作模块端口</h2>

<h3 id="631-显示命名的接口端口">6.3.1 显示命名的接口端口</h3>
<p>模块端口可以显示的声明为特定接口类型。可以把接口名称当作端口类型使用。
例如：</p>
<pre><code class="language-systemverilog">interface chip_bus;
......
endinterface

module Cache(chip_bus pins,
			 input clock);
...
endmodule
</code></pre>
<h3 id="632-通用接口端口">6.3.2 通用接口端口</h3>
<p>通用接口端用关键字interface定义端口类型，而不是使用特定接口类型的名称。例如：</p>
<pre><code class="language-systemverilog">module RAM(  interface pins,
			 input clock);
...
endmodule
</code></pre>
<p>当模块实例化时，任何接口都可以连接到通用接口端口上。</p>

<p><strong><em>同一个模块可以用不同的接口连接？</em></strong>例子？</p>
<h3 id="633-综合指导">6.3.3 综合指导</h3>
<p>接口连接模块的两种方式都是可以综合的。</p>

<h2 id="64-接口的实例化和连接">6.4 接口的实例化和连接</h2>
<p><strong><em>接口类型的端口如果没有连接是非法的</em></strong>
模块实例的input, output和inout类型的端口可以没有任何连接。对于接口类型的端口则不行。</p>

<p>接口的端口也可以定义为一个接口</p>

<h2 id="65-接口内部信号的引用">6.5 接口内部信号的引用</h2>
<p>例如</p>
<pre><code class="language-systemverilog">always @ (posedge bus.clock, negedge bus.resetN)
...
</code></pre>
<h2 id="66-接口的modport">6.6 接口的modport</h2>
<p><strong><em>modport定义了，从模块的角度来看接口信号的端口方向</em></strong>
例如：</p>
<pre><code class="language-systemverilog">interface chip_bus (input logic clock, resetN);
	logic valid, ready;
	logic [31:0] addr;
	logic [31:0] data;

modport master (input clock,
				input resetN,
				output valid,
				input ready,
				output addr,
				output data);

modport slave (	input clock,
				input resetN,
				input valid,
				output ready,
				input addr,
				input data);
</code></pre>
<p>modport定义中不包含向量位数和类型。</p>

<h3 id="661-指定使用哪种modport方式">6.6.1 指定使用哪种modport方式</h3>
<ol>
  <li>在模块实例的接口连接中说明
    <pre><code class="language-systemverilog">chip_bus bus; //接口实例化
primary i1 (bus.master) //使用master modport
</code></pre>
  </li>
  <li>在模块定义的端口声明时说明
    <pre><code class="language-systemverilog">module secondary (chip_bus.slave pins)
</code></pre>
    <p><strong><em>以上两种方式不能同时使用</em></strong></p>
  </li>
</ol>

<p>即使接口定义了modport，模块连接到接口时仍然可以不指定modport。
但是，接口内部信号的端口方向只能在modport中定义。
如果没有在接口连接中指定modport，那么接口中所有的线网信号将默认是双向inout信号。</p>

<h3 id="662-使用modport定义不同的连接">6.6.2 使用modport定义不同的连接</h3>

<p>模块只可以直接访问在modport定义中列出来的信号。这使得接口中的某些信号可以完全地对某些模块隐藏。</p>

<h2 id="67-在接口中使用任务和函数">6.7 在接口中使用任务和函数</h2>
<h3 id="671-接口的方法">6.7.1 接口的方法</h3>

<h3 id="672-接口的方法的导入">6.7.2 接口的方法的导入</h3>
<ol>
  <li>使用函数和任务的名称名称导入
    <pre><code class="language-systemverilog">modport in(	import Read,
         import parity_gen,
         input clock, resetN);
</code></pre>
  </li>
  <li>使用函数和任务的完整原型导入
    <pre><code class="language-systemverilog">modport in(	import task Read(input [63:0] data,
                          output [31:0] addr),
         import function parity_gen(input [63:0] data),
         input clock, resetN);
</code></pre>
    <p><strong><em>使用从接口中导入的任务或函数的模块是可综合的。</em></strong>
<strong><em>导入的函数和任务必须声明为自动类型，并且不能包含静态声明，这样才是可综合的。</em></strong></p>
  </li>
</ol>

<p>下面是一个完整的例子：</p>
<pre><code class="language-systemverilog">///
// Simple AHB Interface with parity methods
///
interface simple_ahb (
  input logic  hclk,    // bus transfer clk
  input logic  hresetN  // bus reset, active low
);
  logic [31:0] haddr;   // transfer start address
  logic [32:0] hwdata;  // data to slave, with parity bit
  logic [32:0] hrdata;  // data from slave, with parity bit
  logic [ 2:0] hsize;   // transfer size
  logic        hwrite;  // 1 for write, 0 for read
  logic        hready;  // 1 for transfer finished
 
  function automatic logic parity_gen(logic [31:0] data);
    return(^data); // calculate parity of data (odd parity)
  endfunction
 
  function automatic logic parity_chk(logic [31:0] data,
                                      logic        parity);
    return (parity === ^data); // 1=OK, 0=parity error
  endfunction
 
  // master module port directions
  modport master_ports (
    output haddr, hwdata, hsize, hwrite, // to AHB slave
    input  hrdata, hready,               // from AHB slave
    input  hclk, hresetN,                // from chip level
    import parity_gen, parity_check      // function import
  );
 
  // slave module port directions
  modport slave_ports (
    output hrdata, hready,               // to AHB master
    input  haddr, hwdata, hsize, hwrite, // from AHB master
    input  hclk, hresetN,                // from chip level
    import parity_check                  // function import
  );
 
  // slave module port directions
  modport slave_ports_alt (
    output hrdata, hready,               // to AHB master
    input  haddr, hwdata, hsize, hwrite, // from AHB master
    input  hclk, hresetN,                // from chip level
    import function logic parity_chk(logic [31:0] data,
                                     logic        parity)
  );
endinterface: simple_ahb
</code></pre>

<h2 id="68-可重构接口">6.8 可重构接口</h2>
<h3 id="681-参数化接口">6.8.1 参数化接口</h3>

<pre><code class="language-systemverilog">///
// Simple AHB Interface with pareterized bus widths
///
interface simple_ahb 
#(parameter DWIDTH=32)        // Data bus width
(
  input logic  hclk,          // bus transfer clk
  input logic  hresetN        // bus reset, active low
);
  logic [31:0]       haddr;   // transfer start address
  logic [DWIDTH-1:0] hwdata;  // data sent to slave
  logic [DWIDTH-1:0] hrdata;  // return data from slave
  logic [ 2:0]       hsize;   // transfer size             
  logic              hwrite;  // 1 for write, 0 for read
  logic              hready;  // 1 for transfer finished
 
  // master module port directions
  modport master_ports (
    output haddr, hwdata, hsize, hwrite, // to AHB slave
    input  hrdata, hready,               // from AHB slave
    input  hclk, hresetN                 // from chip level
  );
 
  // slave module port directions
  modport slave_ports (
    output hrdata, hready,               // to AHB master
    input  haddr, hwdata, hsize, hwrite, // from AHB master
    input  hclk, hresetN                 // from chip level
  );
endinterface: simple_ahb
</code></pre>
<p>例化</p>
<pre><code class="language-systemverilog">simple_ahb #(.DWIDTH(64)) 
	ahbl(.hclk,
		 .hresetN
) ;
</code></pre>

<h3 id="682-使用generate块">6.8.2 使用generate块</h3>
<p>TODO</p>]]></content><author><name>Homer</name></author><category term="systemverilog" /><summary type="html"><![CDATA[1. 过程块 1.1 组合逻辑过程块 always_comb不需要指明敏感列表，使用阻塞赋值(=)，如果过程内部写出锁存器，则会警告或报错 always_comb begin if(!mode) y = a + b; else y = a - b; end 注意：always@(*)并没有组合逻辑的语义，即可能产生latch 注意：如果过程块要调用函数，最好用always_comb，因为always@(*)不会推断函数中读取的信号 1.2 时序逻辑过程块 always_ff，使用非阻塞赋值(&lt;=)，如果过程内部写出组合逻辑，则会报错 always_ff @ (posedge clk, negedge rst_n) begin if(!rst_n) q &lt;= 0; else q &lt;= d; end 1.3 锁存逻辑过程块 always_latch，使用非阻塞赋值(&lt;=)，如果写成其他电路，则会警告或报错 always_latch if(en) q &lt;= d; 2. 任务和函数 TODO 3. for语句 2种写法： 比如描述一个Reduced-xor电路，如下图 第1种写法 module reduced_xor_gen #(parameter N=8) ( input logic [N-1:0] a, output logic y ) logic [N-1:0] p; assign p[0] = a[0]; generate genvar i; for(i=1; i&lt;N; i=i+1) assign p[i] = a[i] ^ p[i-1]; endgenerate assign y = P[N-1]; endmodule 第1种写法也是verilog支持的写法 第2种写法 module reduced_xor_gen #(parameter N=8) ( input logic [N-1:0] a, output logic y ) always_comb begin logic tmp; tmp = a[0]; for (int i=1; i&lt;N; i=i+1) tem = a[i] ^ tmp; y = tmp; end endmodule 第2种写法只在sv中支持，i为声明的局部变量。当for循环启动时，就自动创建这个变量并初始化，当循环推出时，这个变量就被清楚 3. 数组，结构体和联合体 3.1 结构体 结构体定义 // IEEE 754 Binary 32 encoding typedef struct packed { logic sign; logic[FLOAT32_EXP_WIDTH - 1:0] exponent; logic[FLOAT32_SIG_WIDTH - 1:0] significand; } float32_t; 使用 float32_t fop1; assign fop1 = '{1'b1, 8'h12, 23'h111111}; assign s = fop1.sign; assign exp = fop1.exponent; assign sign = fop1.significand; TODO 4. sv声明的位置 包含以下几个内容：package, $unit编译声明空间, 未命名块中的声明, timescale 4.1 package package中可以包含的可综合的结构有：]]></summary></entry></feed>