主頁 > 後端開發 > 數字邏輯實踐6-> 從數字邏輯到計算機組成 | 邏輯元件總結與注意事項

數字邏輯實踐6-> 從數字邏輯到計算機組成 | 邏輯元件總結與注意事項

2022-03-13 06:12:53 後端開發

00 一些前言

數字邏輯是計算機組成與體系結構的前導課,但是在兩者的銜接之間并沒有那么流暢,比如對面向硬體電路的設計思路缺乏,這篇總結是在數字邏輯和計組體系結構的銜接階段進行的,

雖然這篇文是兩門課的交接,也算是兩個系列的一種過渡,但不代表我的數字邏輯部分就已經完成,這個系列后續會繼續更新FPGA的小專案記錄,以及閱讀筆記等等,

本文主要是對于這個視頻的筆記,我覺得很有用,加之此前我的實驗報告由于課程關系不好直接往網上發,所以在這里整理一部分代碼留作黑箱子,后續還會根據課程老師的要求對本文進行補充和優化:

從數字邏輯到計算機組成原理

01 前提準備

  1. 工具:仿真、綜合工具的熟練Vivado和編輯器
  2. 面向硬體電路的設計思路
  3. 要學會造CPU,而不是只會背課本,所以我打算加入試點班,

02 回顧數字邏輯

02-1 數值表示 | 原碼補碼 | 邏輯門 | 布爾代數

  • 數值和數制:
    • 重點是二進制、十六進制;
  • 數值的原碼表示和補碼表示:
    • 有符號數和無符號數
    • 加減溢位問題;
  • 基本邏輯門:
    • 與或非、NAND;
    • 以及CMOS門電路;
  • 布爾代數:
    • 邏輯運算式;
    • 真值表;
    • 邏輯運算律;
    • 卡諾圖;

02-2 譯碼器等器件

這部分基本上涵蓋了上學期數字邏輯的所有實驗,所以是數字邏輯里比較重要的部分,

  • n-2n譯碼器Decoder;
  • 資料選擇器MUX;
  • 一位全加器,串行進位多位全加器;
  • 鎖存器和觸發器;
  • 傳并行加載轉換器等;
  • 觸發器的時序分析、延遲分析;
  • 計數器;
  • 移位暫存器;
  • 狀態機設計;

02-3 原理部分

  • 組合邏輯電路和時序邏輯電路的原理
  • 只讀存盤器ROM基本原理
  • 隨機存盤器RAM基本原理
  • 動態存盤器DRAM基本原理
  • 現場可編程門陣列FPGA基本原理

這部分我的數字邏輯課程是沒有講解的,但后續我會繼續了解,畢竟是課程相關的東西,

03 主要過渡內容

03-1 Verilog

這是一個硬體語言,我此前也寫過數字邏輯實踐4->面向硬體電路的設計思維--FPGA設計總述,就是在描述Verilog與高級語言軟體思路的不同,

03-1-1 怎么學

  • 采用RTL(Register Transfer Level,暫存器傳輸級)設計;
  • 使用限制的可綜合子集
  • 將自己實作的代碼和參考代碼對比思考

03-1-2 面向硬體電路的設計思路

  • 謹記這不是在寫代碼,而是在設計電路(并行);
  • 先進行(設想)電路結構設計,再進行Verilog代碼撰寫;
  • 遵循自頂向下、模塊劃分、逐層細化的設計步驟;
  • 不要寫一點、試一下、改一點、再試一下,這樣效率很低;

?03-1-3 可綜合代碼Verilog(限制版)

在寫CPU時,主要使用以下語法,其他的盡量不要使用:

  • 模塊宣告module endmodule
  • 埠宣告input output inout
  • 線網資料型別 wire
  • 變數資料型別 reg,integer
  • 引數常量 (parameter constants)
  • 整型數 (literal integer numbers)
  • 模塊實體化
  • 連續賦值陳述句assgin
  • always結構化陳述句
  • begin...end塊
  • 阻塞賦值=和非阻塞賦值<=
  • 條件判斷陳述句if,if...else,case
  • for回圈
  • 組合邏輯敏感串列的 @*
  • 多維陣列(暫存器堆)
  • generate運算式

03-1-4 代碼風格建議(要求)

  1. 資料通路上的組合邏輯用assign寫,禁止用always寫;controller中可以用,datapath不可以,

  2. 用always寫組合邏輯的時候,只允許出現在生成狀態機的next state的時候,且該陳述句中只能出現阻塞賦值=;

  3. 寫時序邏輯的時候,always陳述句中,只允許出現非阻塞賦值(<=);

  4. 暫存器堆封裝成單獨的模塊,以實體化的方式使用;

  5. case陳述句在任何情況下都要有default

    • 這一點在上一篇文章也提到過;保證了安全性和沒實作指令的放置;
  6. 模塊實體化時候的引數和埠只允許用名字相關的方式進行賦值和連接;

    就是實體化的時候用名字對應的方式來確保實體化不會錯位;

    即這種方式??

    .clk(clk)
    
  7. 資料通路的組合邏輯中,1bit的邏輯運算用&、|、~、^這類位運算子;

    控制信號的組合邏輯中,1bit的邏輯運算用&& 、||、!這三個運算子,

  8. 運算優先級!

03-2 代碼實體

為了在實操里有效注意到上面提到過的東西,針對我寫過的實驗型別,來看看更好的實作方式,

視頻中提到的代碼在[這里][step_into_mips/rtl_code at prepare · lvyufeng/step_into_mips (github.com)],也是下面規范代碼的來源處,至于下面我的數字邏輯實驗代碼,對比之下,那沒有價值,

03-2-1 模塊呼叫和實體化

下面的代碼沒什么功能可言,但對于格式而言很標準,可以學習一下它的模塊呼叫和實體化,我作了標注,

module top;

wire [15:0] btm_a;
wire [ 7:0] btm_b;
wire [ 3:0] btm_c;
wire [ 3:0] btm_y;
wire        btm_z;

bottom #(
    .A_WIDTH (16),
    .B_WIDTH ( 7),
    .Y_WIDTH ( 3)
    )
    //這里的引數可以調整就相當于全域變數,用一個變數存盤常數,
    inst_btm(
    .a   (btm_a),  //I
    .b   (btm_b),  //I
    .c   (btm_c),  //I
    .y   (btm_y),  //O
    .z   (btm_z)   //O
    );
	//這里就是前面提到過的按名字來實體化變數
endmodule

module bottom #
(
    parameter A_WIDTH = 8,
    parameter B_WIDTH = 4,
    parameter Y_WIDTH = 2
)
(
    input   wire [A_WIDTH-1:0] a,
    input   wire [B_WIDTH-1:0] b,
    input   wire [        3:0] c,
    output  wire [Y_WIDTH-1:0] y,
    output  reg                z
);

// internal logic

endmodule

03-2-2 基本邏輯門

下面提到的是32位的與或非、與非、或非、異或、同或,這是ALU(運算器)實作的基礎,

module bit_logic(
    input  [31:0] a,  
    input  [31:0] b,
    output [31:0] y1,
    output [31:0] y2,
    output [31:0] y3,
    output [31:0] y4,
    output [31:0] y5,
    output [31:0] y6,
    output [31:0] y7
);

assign y1 = a & b;     //與
assign y2 = a | b;     //或
assign y3 = ~a;        //非
assign y4 = ~(a & b);  //與非
assign y5 = ~(a | b);  //或非
assign y6 = a ^ b;     //異或
assign y7 = a ~^ b;    //同或

endmodule

03-2-3 譯碼器

當時我校實驗二的任務有一個是2-4譯碼器,我當時的代碼(.v檔案)如下,使用always+case實作的:

module dec2to4(W,En,Y);
	input[1:0]W;
	input En;
	output reg [0:3]Y;
	
	always @(W,En)
		case({En,W})
			3'b100:Y = 4'b1000;
			3'b101:Y = 4'b0100;
			3'b110:Y = 4'b0010;
			3'b111:Y = 4'b0001;
			default: Y = 4'b0000;
		endcase
endmodule

這時候回憶一下上面的內容,資料通路上的組合邏輯用assign寫,禁止用always,看如下規范代碼:

module decoder_4_16(
    input  [ 3:0] in,
    output [16:0] out
);
// one-hot,獨熱編碼
assign out[ 0] = (in == 3'd0 );
assign out[ 1] = (in == 3'd1 );
assign out[ 2] = (in == 3'd2 );
assign out[ 3] = (in == 3'd3 );
assign out[ 4] = (in == 3'd4 );
assign out[ 5] = (in == 3'd5 );
assign out[ 6] = (in == 3'd6 );
assign out[ 7] = (in == 3'd7 );
assign out[ 8] = (in == 3'd8 );
assign out[ 9] = (in == 3'd9 );
assign out[10] = (in == 3'd10);
assign out[11] = (in == 3'd11);
assign out[12] = (in == 3'd12);
assign out[13] = (in == 3'd13);
assign out[14] = (in == 3'd14);
assign out[15] = (in == 3'd15);

endmodule

但明顯可以發現,上面的代碼缺點在于重復結構,看起來很笨重,所以可以用generate來代替,準確來說這不是for回圈,只是通過這種方式在編譯器的層面自動生成了上面那么多重復的陳述句:

//另一個5-32譯碼器
//用generate陳述句改善編碼效率
module decoder_5_32(
    input  [ 4:0] in,
    output [31:0] out
);

genvar i;
generate for (i=0; i<32; i=i+1) begin : gen_for_dec_5_32
    assign out[i] = (in == i);
end endgenerate

endmodule
//6-64譯碼器
module decoder_6_64(
    input  [ 5:0] in,
    output [63:0] out
);

genvar i;
generate for (i=0; i<63; i=i+1) begin : gen_for_dec_6_64
    assign out[i] = (in == i);
end endgenerate

endmodule

03-2-4 編碼器

編碼器當時學校任務是8-3編碼器,我的代碼如下,也是個case:

module enc8to3(x,y);
	input [7:0]x;
	output [2:0]y;
	reg[2:0]y;

always@(x)
begin
	case(x)
		8'b00000001:y=3'b000; 
        //x=8 ’b00000001,y  輸出為 3 ’b000
        
		8'b00000010:y=3'b001; 
        //x=8 ’b00000010,y  輸出為 3 ’b001
        
		8'b00000100:y=3'b010; 
        //x=8 ’b00000100,y  輸出為 3 ’b010
        
		8'b00001000:y=3'b011; 
        //x=8 ’b00001000,y  輸出為 3 ’b011
        
		8'b00010000:y=3'b100;
        //x=8 ’b00010000,y  輸出為 3 ’b100
        
		8'b00100000:y=3'b101; 
        //x=8 ’b00100000,y  輸出為 3 ’b101
        
		8'b01000000:y=3'b110; 
        //x=8 ’b01000000,y  輸出為 3 ’b110
        
		8'b10000000:y=3'b111; 
        //x=8·’b10000000,y  輸出為 3 ’b111
        
		default: y=3'b000;
	endcase
end
endmodule		

來看看好一點的規范代碼:??

module encoder_8_3(
    input  [7:0] in,
    output [2:0] out
);
//獨熱
assign out = in[0] ? 3’d0 :
             in[1] ? 3’d1 :
             in[2] ? 3’d2 :
             in[3] ? 3’d3 :
             in[4] ? 3’d4 :
             in[5] ? 3’d5 :
             in[6] ? 3’d6 :
                     3’d7 ;

endmodule
//這其實是一個優先級編碼器,是一層一層的else,所以最后的網格電路會比較慢

下面是一種更好的寫法:

//保證設計輸入in永遠至多只有一個1
//即at-most-1-hot向量
module encoder_8_3(
    input  [7:0] in,
    output [2:0] out
);

assign out = ({3{in[0]}} & 3’d0)
           | ({3{in[1]}} & 3’d1)
           | ({3{in[2]}} & 3’d2)
           | ({3{in[3]}} & 3’d3)
           | ({3{in[4]}} & 3’d4)
           | ({3{in[5]}} & 3’d5)
           | ({3{in[6]}} & 3’d6)
           | ({3{in[7]}} & 3’d7);

endmodule

用邏輯運算子 | 使得所有的運算式并行,在電路上表示為同一級并行結構,下面可以看到這個陳述句與多路選擇器其實也很相似,

03-2-4 多路選擇器

當時我寫的是:

module mux2to1(w0,w1,s,f);
	input w0,w1,s;
	output reg f;
	
	//assign f = s ? w1 : w0;
	//這不是可綜合的代碼,替換??
	//2022-3-12 
    //上面說錯了,assign對于reg型別不可綜合,wire還行,甚至在資料通路上這個組合邏輯模塊應當使用assign,
	always @(w0,w1,s)
		f = s ? w1 : w0;
endmodule

再來看規范代碼,與上面的編碼器相同,給出了一個優先級代碼(速度不那么快),和另一個并行代碼(速度快):

module mux5_8b(
  input  [7:0] in0, in1, in2, in3, in4,
  input  [2:0] sel,
  output [7:0] out
);
//優先級代碼
assign out = (sel==3’d0) ? in0 :
             (sel==3’d1) ? in1 :
             (sel==3’d2) ? in2 :
             (sel==3’d3) ? in3 :
             (sel==3’d4) ? in4 :
                           8’b0;
endmodule


module mux5_8b(
  input  [7:0] in0, in1, in2, in3, in4,
  input  [2:0] sel,
  output [7:0] out
);
//并行代碼
assign out = ({8{sel==3’d0}} & in0)
           | ({8{sel==3’d1}} & in1)
           | ({8{sel==3’d2}} & in2)
           | ({8{sel==3’d3}} & in3)
           | ({8{sel==3’d4}} & in4);

endmodule

//不要忘了寫{8{}}中的8,這是與in0等保持一致,

下面是一個特殊一點的多路選擇器,實作五選一,這個五中的每一個都是一個位寬為8的陣列,

module max5_1hot_8b(
    input [7:0]in0, in1, in2, in3, in4,
    input [4:0]sel_v,
    output [7:0]out
);
assign out = ({8{sel_v[0]}} & in0)
        |({8{sel_v[1]}} & in1)
        |({8{sel_v[2]}} & in2)
        |({8{sel_v[3]}} & in3)
        |({8{sel_v[4]}} & in4);
endmodule

03-2-5 全加器 / 加法器

全加器事實上代碼的操作空間不大,下面是我寫的:

module twoadder(x,y,carryin,Sum,carryout);
	parameter n = 2;
	input [n-1:0]x,y;
	input carryin;
	output reg [n-1:0]Sum;
	output reg carryout;
	
	always @(x,y,carryin)
	begin
		{carryout,Sum} = x + y + carryin;
	end
endmodule

這是參考代碼:

module adder(
    input  [31:0] a,
    input  [31:0] b,
    input         cin,
    output [31:0] s,
    output        cout
);

assign {cout, s} = a + b + cin;

endmodule
//基本一致

03-2-6 暫存器 / D觸發器

這部分就是時序邏輯了,有好幾個形態的Dflipflop:

  1. 最普通的上跳沿觸發的D暫存器

    module Dflipflop(
           input      clk,
           input      din,
           output reg q
       );
    
       always @(posedge clk) begin
           q <= din;
       end
    
       endmodule
    
  2. 帶使能端的D暫存器,兩種推薦寫法:

    //第一種:if
    module Dflipflop_en(
        input      clk,
        input      en,
        input      din,
        output reg q
    );
    
    always @(posedge clk) begin
        if (en) q <= din;
    end
    
    endmodule
    
    //第二種:三元運算
    module Dflipflop_en(
        input      clk,
        input      en,
        input      din,
        output reg q
    );
    
    always @(posedge clk) begin
        q <= en ? din : q;
    end
    
    endmodule
    
  3. 帶復位的D暫存器,兩種推薦寫法:

,//寫法1:if-else if
module Dflipflop_r(
    input      clk,
    input      rst,
    input      din,
    output reg q
);

always @(posedge clk) begin
    if      (rst) q <= 1’b0;
    else if (en)  q <= din;
end

endmodule

//寫法二:二重三元運算
module Dflipflop_r(
    input      clk,
    input      rst,
    input      din,
    output reg q
);

always @(posedge clk) begin
    q <= rst ? 1'b0 :
         en  ? din  : q;
end

endmodule
  1. 以上兩個暫存器都推薦使用if的實作方式,因為軟體會對這種方式進行優化,對三元運算子的不會;

    并且 if 的方式對于q優先級顯示得較為清楚,

這里強調一個問題:

就是rst要不要放在posedge里,即:

always @(posedge clk, rst) begin

產生這個問題多半是因為課本上的代碼,有些是上面實體代碼的形式,有些是這個形式,這個問題也很簡單,即記住要把時鐘敏感的信號放在@里,非時鐘敏感的就不放進去,

03-2-7 暫存器堆

這個實驗我沒有做過,基本就是實作一個指令集對應的暫存器陣列,

module regfile(
    input         clk,
    // READ PORT 1
    input  [ 4:0] raddr1,
    output [31:0] rdata1,
    // READ PORT 2
    input  [ 4:0] raddr2,
    output [31:0] rdata2,
    // WRITE PORT
    input         we,       
    //write enable, HIGH valid
    input  [ 4:0] waddr,
    input  [31:0] wdata
);
reg [31:0] rf[31:0];

//WRITE
always @(posedge clk) begin
    if (we) rf[waddr]<= wdata;
end

//READ OUT 1
assign rdata1 = (raddr1==5'b0) ? 32'b0 : rf[raddr1];

//READ OUT 2
assign rdata2 = (raddr2==5'b0) ? 32'b0 : rf[raddr2];
//讀的時候是一個組合邏輯,所以是we,而不是en
endmodule

下面還有一個寫法,看起來很長,如果仔細看,下面讀1和讀2的操作都是并行的,具體實作的就是一個譯碼的操作,即將地址譯為一個one-hot,這種寫法是上面代碼具體實作的樣子,

//另一個寫法
module regfile(
    input         clk,
    // READ PORT 1
    input  [ 4:0] raddr1,
    output [31:0] rdata1,
    // READ PORT 2
    input  [ 4:0] raddr2,
    output [31:0] rdata2,
    // WRITE PORT
    input         we,       //write enable, HIGH valid
    input  [ 4:0] waddr,
    input  [31:0] wdata
);

reg  [31:0] rf[31:0];
wire [31:0] waddr_dec, raddr1_dec, raddr2_dec;

//WRITE
decoder_5_32 U0(.in(waddr ), .out(waddr_dec));

always @(posedge clk) begin
    if (we & waddr_dec[ 0]) rf[ 0] <= wdata;
    if (we & waddr_dec[ 1]) rf[ 1] <= wdata;
    if (we & waddr_dec[ 2]) rf[ 2] <= wdata;
    if (we & waddr_dec[ 3]) rf[ 3] <= wdata;
    if (we & waddr_dec[ 4]) rf[ 4] <= wdata;
    if (we & waddr_dec[ 5]) rf[ 5] <= wdata;
    if (we & waddr_dec[ 6]) rf[ 6] <= wdata;
    if (we & waddr_dec[ 7]) rf[ 7] <= wdata;
    if (we & waddr_dec[ 8]) rf[ 8] <= wdata;
    if (we & waddr_dec[ 9]) rf[ 9] <= wdata;
    if (we & waddr_dec[10]) rf[10] <= wdata;
    if (we & waddr_dec[11]) rf[11] <= wdata;
    if (we & waddr_dec[12]) rf[12] <= wdata;
    if (we & waddr_dec[13]) rf[13] <= wdata;
    if (we & waddr_dec[14]) rf[14] <= wdata;
    if (we & waddr_dec[15]) rf[15] <= wdata;
    if (we & waddr_dec[16]) rf[16] <= wdata;
    if (we & waddr_dec[17]) rf[17] <= wdata;
    if (we & waddr_dec[18]) rf[18] <= wdata;
    if (we & waddr_dec[19]) rf[19] <= wdata;
    if (we & waddr_dec[20]) rf[20] <= wdata;
    if (we & waddr_dec[21]) rf[21] <= wdata;
    if (we & waddr_dec[22]) rf[22] <= wdata;
    if (we & waddr_dec[23]) rf[23] <= wdata;
    if (we & waddr_dec[24]) rf[24] <= wdata;
    if (we & waddr_dec[25]) rf[25] <= wdata;
    if (we & waddr_dec[26]) rf[26] <= wdata;
    if (we & waddr_dec[27]) rf[27] <= wdata;
    if (we & waddr_dec[28]) rf[28] <= wdata;
    if (we & waddr_dec[29]) rf[29] <= wdata;
    if (we & waddr_dec[30]) rf[30] <= wdata;
    if (we & waddr_dec[31]) rf[31] <= wdata;
end

//READ OUT 1
decoder_5_32 U1(.in(raddr1), .out(raddr1_dec));

assign rdata1 = ({32{raddr1_dec[ 1]}} & rf[ 1]) //NOTE: we omit No. 0 entry because GR[0] always be zero.
              | ({32{raddr1_dec[ 2]}} & rf[ 2])
              | ({32{raddr1_dec[ 3]}} & rf[ 3])
              | ({32{raddr1_dec[ 4]}} & rf[ 4])
              | ({32{raddr1_dec[ 5]}} & rf[ 5])
              | ({32{raddr1_dec[ 6]}} & rf[ 6])
              | ({32{raddr1_dec[ 7]}} & rf[ 7])
              | ({32{raddr1_dec[ 8]}} & rf[ 8])
              | ({32{raddr1_dec[ 9]}} & rf[ 9])
              | ({32{raddr1_dec[10]}} & rf[10])
              | ({32{raddr1_dec[11]}} & rf[11])
              | ({32{raddr1_dec[12]}} & rf[12])
              | ({32{raddr1_dec[13]}} & rf[13])
              | ({32{raddr1_dec[14]}} & rf[14])
              | ({32{raddr1_dec[15]}} & rf[15])
              | ({32{raddr1_dec[16]}} & rf[16])
              | ({32{raddr1_dec[17]}} & rf[17])
              | ({32{raddr1_dec[18]}} & rf[18])
              | ({32{raddr1_dec[19]}} & rf[19])
              | ({32{raddr1_dec[20]}} & rf[20])
              | ({32{raddr1_dec[21]}} & rf[21])
              | ({32{raddr1_dec[22]}} & rf[22])
              | ({32{raddr1_dec[23]}} & rf[23])
              | ({32{raddr1_dec[24]}} & rf[24])
              | ({32{raddr1_dec[25]}} & rf[25])
              | ({32{raddr1_dec[26]}} & rf[26])
              | ({32{raddr1_dec[27]}} & rf[27])
              | ({32{raddr1_dec[28]}} & rf[28])
              | ({32{raddr1_dec[29]}} & rf[29])
              | ({32{raddr1_dec[30]}} & rf[30])
              | ({32{raddr1_dec[31]}} & rf[31]);

//READ OUT 2
decoder_5_32 U2(.in(raddr2), .out(raddr2_dec));

assign rdata2 = ({32{raddr2_dec[ 1]}} & rf[ 1])
              | ({32{raddr2_dec[ 2]}} & rf[ 2])
              | ({32{raddr2_dec[ 3]}} & rf[ 3])
              | ({32{raddr2_dec[ 4]}} & rf[ 4])
              | ({32{raddr2_dec[ 5]}} & rf[ 5])
              | ({32{raddr2_dec[ 6]}} & rf[ 6])
              | ({32{raddr2_dec[ 7]}} & rf[ 7])
              | ({32{raddr2_dec[ 8]}} & rf[ 8])
              | ({32{raddr2_dec[ 9]}} & rf[ 9])
              | ({32{raddr2_dec[10]}} & rf[10])
              | ({32{raddr2_dec[11]}} & rf[11])
              | ({32{raddr2_dec[12]}} & rf[12])
              | ({32{raddr2_dec[13]}} & rf[13])
              | ({32{raddr2_dec[14]}} & rf[14])
              | ({32{raddr2_dec[15]}} & rf[15])
              | ({32{raddr2_dec[16]}} & rf[16])
              | ({32{raddr2_dec[17]}} & rf[17])
              | ({32{raddr2_dec[18]}} & rf[18])
              | ({32{raddr2_dec[19]}} & rf[19])
              | ({32{raddr2_dec[20]}} & rf[20])
              | ({32{raddr2_dec[21]}} & rf[21])
              | ({32{raddr2_dec[22]}} & rf[22])
              | ({32{raddr2_dec[23]}} & rf[23])
              | ({32{raddr2_dec[24]}} & rf[24])
              | ({32{raddr2_dec[25]}} & rf[25])
              | ({32{raddr2_dec[26]}} & rf[26])
              | ({32{raddr2_dec[27]}} & rf[27])
              | ({32{raddr2_dec[28]}} & rf[28])
              | ({32{raddr2_dec[29]}} & rf[29])
              | ({32{raddr2_dec[30]}} & rf[30])
              | ({32{raddr2_dec[31]}} & rf[31]);

endmodule

04 設計基本流程 | 注意事項

12312

基本如上圖所示,我們需要:

  • CPU結構圖
  • RTL代碼撰寫(即上面各種箱子)
  • 功能仿真,vivado里的Functional Simulation;必須先進行此步再綜合;仿真不正確不要向后做;
  • 測驗代碼testbench,cpu檢驗時老師會給
  • 綜合;
  • Vivado布局布線;
  • 驗證;

05 結語

05-1 課外書籍推薦

書不一定要是紙質書,看不一定是一頁一頁看,但這些書確實挺好:

  1. 《verilog數字系統設計教程》夏宇聞

    查一些基本語法;

  2. 《自己動手寫CPU》雷思磊

    快速做出來CPU;

  3. 《數字設計與計算機體系結構》戴維·莫尼·哈里斯

    MIPS-FPGA的鼻祖;

讀者如果需要的話,可以聯系我,我找到了一些資源,

05-2 安排

我想我會在下一篇會講解(記錄)vivado下載安裝使用以及第三方編輯器的調配,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/441908.html

標籤:Verilog

上一篇:Python容器資料型別(字典、集合)

下一篇:Spring Cloud快速使用教程

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more