国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

查看: 82533|回復(fù): 84
打印 上一主題 下一主題

跟著我從零開始入門FPGA

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2012-5-12 00:22:06 | 只看該作者 |只看大圖 回帖獎勵 |倒序?yàn)g覽 |閱讀模式
這是一個大任務(wù),但我打算只是引門外漢入門,大約7個帖子來完成,一周入門FPGA

1、假設(shè)讀者對硬件數(shù)字電路熟悉,比如自己可以用74芯片做跑馬燈
2、C語言都比較熟悉,因?yàn)橄旅嬗玫?a href="http://www.qingdxww.cn/keyword/Verilog" target="_blank" class="relatedlink">Verilog語言就跟它很類似,暫時規(guī)避晦澀的VHDL

我打算分幾個部分
1、Verilog語法
2、組合邏輯設(shè)計
3、時序邏輯設(shè)計
4、阻塞和非阻塞
5、同步和異步設(shè)計
6、有限狀態(tài)機(jī)
7、設(shè)計一個只有4條指令的CPU

評分

參與人數(shù) 2積分 +40 收起 理由
步從容 + 10 thx!
@︻$▅▆▇◤ + 30

查看全部評分

沙發(fā)
 樓主| 發(fā)表于 2012-5-12 00:22:29 | 只看該作者
1、Verilog語法


沒錯,我們就是拿C語言照貓畫虎,下面是一個“老虎”的模型。
我們一個個看他跟“貓”不一樣的地方

module nand(
            input   in1,
            input   in2,
            output   out
);

    wire    tmp;
    assign tmp = in1 & in2;
    assign out = ~tmp;

endmodule


模塊定義跟C語言的函數(shù)很相似吧
1、模塊必須使用“module”關(guān)鍵字,他也沒有返回值。
2、模塊沒有beginmodule,只有endmodule
3、模塊對外接口有input,output,inout,但為了入門著想,只談input和output

模塊內(nèi)部還有個中間變量耶,是不是看見了tmp就有很熟悉的感覺了。
沒錯,他就是中間“變量”,在硬件上他就是一根導(dǎo)線,wire望文生義即可。

看見了“=”就應(yīng)該猜到這是賦值語句了,沒錯,但Verilog的語法要求前面必須有個苦B的assign關(guān)鍵字

至于“&”和“~”這2個運(yùn)算符號,就不講了吧,C語法搞不清的兄弟,對不住了


有人會說,你這“變量”到底是int還是long還是flot抑或double呢?
好了,咱繼續(xù)照貓畫虎,不過老虎畢竟跟貓是不一樣的,比如老虎會虎嘯,貓只會喵喵。

wire[7:0]   tmp;
這一下子把tmp從一根線,擴(kuò)展成了8根線,覺得是7根線的自己去看C語言課本去。

好了,我們要虎嘯了,同時喵喵幾下,對比著看

wire[7:0]   tmp;
wire[3:0]   high;

assign high = tmp[7:4];     //虎嘯的Verilog
high = tmp<<4;              //喵喵的C語言

硬件就是硬件,可以隨意飛線,你甚至可以把tmp里面的bit6,bit3,bit1,bit7組成一個Nibble
不知道Nibble不要緊,它就是Half Byte的

assign high = {tmp[6],tmp[3],tmp[1],tmp[7]};        //虎嘯的Verilog

high  = (tmp & 0x40) ? 0x08 : 0;                //喵喵的C語言
high |= (tmp & 0x08) ? 0x04 : 0;                //喵喵的C語言
high |= (tmp & 0x02) ? 0x02 : 0;;               //喵喵的C語言
high |= (tmp & 0x80) ? 0x01 : 0;;               //喵喵的C語言

這下知道喵喵跟虎嘯的差距了吧,C語言,把如貓?zhí)硪?表達(dá)式都用上了,還是4行代碼才表達(dá)出自己的意圖。
當(dāng)然,Verilog也有他的?表達(dá)式,那用上了,就真的是如虎添翼了

C語言的switch/case語句
switch(tmp)
{
    case 1:
        high =1;
        break;
    case 3:
        high =5;
        break;
    case 5:
        high =2;
        break;
    case 9:
        high =1;
        break;
    default:
        high =11;
}
Verilog的case語句
case(tmp)
    1:          high =1;
    2:          high =5;
    3:          high =1;
    4:          high =1;
    default:    high = 1;

發(fā)現(xiàn)了沒,首先打字要少敲很多case了吧,case已經(jīng)升級當(dāng)主管了,小羅羅們直接跟這冒號就可以了。
細(xì)心的文藝青年,應(yīng)該發(fā)現(xiàn)了一個大秘密,那個四處張揚(yáng),到處留種的break居然不見了。
Verilog不需要break了,它默認(rèn)每個語句自動break,這時有人又擔(dān)心,那我有2個語句咋辦?

問得好,又有2個keyword要粉末登場了,begin/end
學(xué)會Pascal語言的朋友,肯定認(rèn)得他倆,在C語言中被{和}所替代

Verilog本來也想用{和}的,畢竟寫代碼是要敲鍵盤的,能少敲誰也不愿意多敲。
可惜{和}被用掉了,用在了哪里?到上面找去,

case(tmp)
    1,2,3,4:
    begin
        high =1;
        high1 =3;
        high8 =9;
    end
    default:
        high = 1;

這個排版,是不是又點(diǎn)更像C語言的風(fēng)格了
你也許已經(jīng)看到了,C語言中多個case項(xiàng)公用一段代碼的情況,在Verilog里面也有,而且更TMD的簡潔

if/else語句就不講了,這方面貓和老虎太像了,照貓畫虎就八九不離十了。


好了,下面有個用得非常多的always語句

always(tmp1, tmp2)
    begin
        out1 = tmp1 ^ tmp2;
        out2 = tmp1 + tmp2;
    end
又是喵喵和虎嘯的區(qū)別了,C語言的while也是always的意思,但while不如always忠誠。
C的while語句,是隨著CPU的時鐘節(jié)奏,一步一步的走,然后Loop循環(huán)回來,直到永遠(yuǎn)或者有人叫她出臺(霸王的break或者while條件不滿足了)
Verilog的always可就忠誠多了,只要tmp1和tmp2中的任何一個變動,out1和out2都跟著動,clk來不來都會工作,這就是主動和被動的差別


好了,看到這里,你應(yīng)該知道,文藝青年和苦B青年其實(shí)也有很多共同之處的,如果你認(rèn)識文藝青年,那跟苦B青年交朋友也不難了。
板凳
 樓主| 發(fā)表于 2012-5-12 00:22:51 | 只看該作者
2、組合邏輯設(shè)計


2、組合邏輯設(shè)計

組合邏輯是神馬?
所謂組合邏輯就是,一堆輸入注定了一個(或多個)輸出,明天你再送同樣的這一堆輸入,可以得到跟今天完全相同的結(jié)果。
或者說,輸出的值跟先前任何狀態(tài)沒有一毛錢的關(guān)系,只跟當(dāng)前的輸入有關(guān)系。

來個最簡單的:
assign out = in1 & in2;
這是個與門,out的值只跟in1和in2有關(guān)。

這時候?語句很有作用了,比如
assign out = sel ? in1 : in2;
這是一個二選一的選擇器。

你肯定覺得二選一太簡單了,來個4選一看看
assign out = (sel==2'b00) ? in0 : (sel==2'b01) ? in1 : (sel==2'b10) ? in2 : (sel==2'b11) ? in3;
不知道你感覺如何,反正我從第二個問號開始花眼,咋辦?
首先一個辦法,?表達(dá)式的復(fù)合,我們可以用括號來區(qū)分層次,但仍然感覺很不直觀。
想到了什么,C語言的switch/case,OK,我們就用Verilog的case語句寫一下

always @(sel or in0 or in1 or in2)
    case(sel)
        2'b00:  out = in0;
        2'b01:  out = in0;
        2'b10:  out = in0;
        2'b11:  out = in0;
    endcase

OK,我們看看這個case語句是什么?沒錯,他就是那個真值表的美麗化身。
怎么,你還想到了卡諾圖輔助邏輯表達(dá)式化簡,當(dāng)年讀書時候,整天對著田字格橫看豎看的,很神奇的。

現(xiàn)在我們有Verilog語言了,化簡的事情交給綜合器好了。
啥,你不知道綜合器是啥?C語言的C編譯器,你知道吧,他倆基本是一個地位的。

always的小老鼠后面的括號里不是有很多“變量”嗎,那叫敏感信號。
只要敏感信號任何一個有變動,下面的語句就執(zhí)行一次,其實(shí)這是個形象的說法,幾乎是專門給C語言工程師定制的一個解釋。

說到邏輯電路,我們找個非典型的用途吧-----地址譯碼
CPU就說是8051吧,其實(shí)其他的也一樣

我們有個外設(shè),內(nèi)部有8個寄存器,我們打算把它安排到地址0xF080~0xF0087,設(shè)計它的片選信號

比較笨的方法:
assign sel = (addr==16'hF080) | (addr==16'hF081) | ...............
我就不敲完了,8個啊,復(fù)制完了,還要一個個修改,還要校對,夠苦B的了

always @(addr)
    case(addr)
        16'hF080, 16'hF081, 16'hF082, 16'hF083, 16'hF084, 16'hF085, 16'hF086, 16'hF087:
            sel = 1;
        default:
            sel = 0;
    endcase
這個case語句簡單多了吧,16'hF080的含義就是此數(shù)據(jù)有16個bit,h表示后面是十六進(jìn)制表示的。
F080你要不知道什么意思,估計你們學(xué)校是體育老師講計算機(jī)基礎(chǔ)課,當(dāng)然也可能是政治老師。

其實(shí),case里面連續(xù)寫8個項(xiàng),然后一個冒號,感覺也很是苦B

那我們手工分析下0xF080~0xF0087的特征,高位的3個Nibble是F08,低位Nibble是0~7
我們再用二進(jìn)制的方式看看:
1111 0000 1000 0000
1111 0000 1000 0001
1111 0000 1000 0010
1111 0000 1000 0011
1111 0000 1000 0100
1111 0000 1000 0101
1111 0000 1000 0110
1111 0000 1000 0111
---------------------------------------
1111 0000 1000 0xxx

這3個小x的含義我就不說了,這點(diǎn)歸納的邏輯都沒有的話,您真不適合做工程師,適合做公務(wù)員。

always @(addr)
    casex(addr)
        16'b1111_0000_1000_0xxx:
            sel = 1;
        default:
            sel = 0;
    endcase
是不是帥呆了,如果你不是太粗心的話,應(yīng)該看到了這個是casex而不是case


其實(shí)帥不是目的,泡到妞才是根本。看一個assign語句就可以搞定的事,何必羅嗦這么多呢。
assign sel = (addr==16'b1111_0000_1000_0xxx);

估計你還看到了一個小東西,那下劃線。
沒錯,他就是個擺設(shè),增加可讀性的擺設(shè),去掉也可以,不過我舍不得去掉。


C語言里如果要判斷這個sel信號,一般用bit mask的方法
sel = ((addr&0xFFF8)==0xF0808);
看來照貓畫虎,這招也可以用在這里,雖然代碼稍微差異,思路近似。

關(guān)于case語句的一個注意事項(xiàng),就是所謂的full-case,這個很重要
always @(addr)
    casex(addr)
        16'b1111_0000_1000_0xxx:
            sel = 1;
    endcase
那么,當(dāng)?shù)刂凡宦湓谖覀冎付ǚ秶鷥?nèi)的時候,沒有語句來處理。
沒來命令,就是要原地駐軍。

其實(shí)相當(dāng)于,
always @(addr)
    casex(addr)
        16'b1111_0000_1000_0xxx:
            sel = 1;
        default:
            sel = sel;
    endcase

天啊,sel=sel,這就是傳說中的意外的latch,這跟我們的意圖不一致
即使邏輯上可以完成指定功能,他也額外用掉了一個寄存器。

記住,用case語句的時候一定要full-case處理,除非你設(shè)計的就是寄存器

寄存器的latch是時序邏輯里面的內(nèi)容
欲知后市如何,請聽下回分解。
地板
 樓主| 發(fā)表于 2012-5-12 00:23:03 | 只看該作者
3、時序邏輯設(shè)計

所謂時序邏輯,簡而言之,就是CLK驅(qū)動,不來時鐘不干活,同時能自我保持。
最簡單的例子,跑馬燈

model led_led(input rst, input clk, output out0, output out1, output out2, output out3);
reg ary[3:0];

assign out0 = ary[0];
assign out1 = ary[1];
assign out2 = ary[2];
assign out3 = ary[3];
always @(clk)
begin
    if(rst)
        ary <= 4'h00;
    else
    begin
        ary[3] <= ary[2];
        ary[2] <= ary[1];
        ary[1] <= ary[0];
        ary[0] <= ary[3];
    end
end
endmodele

有人會說那個ary的“中間變量”是不是可以省掉,還真省不了,因?yàn)樗粌H僅是“臨時變量”。
它是個鎖存器,寄存器-----------數(shù)據(jù)保持是它的特點(diǎn)。而wire信號是無法保持的。

當(dāng)然那4個信號單獨(dú)賦值,挺形象,但是不夠緊湊,C語言可以用ary = ary<<1來表示,那Verilog就如下:
model led_led(input rst, input clk, output out[3:0]);
reg ary[3:0];
assign out = ary;
always @(clk)
begin
    if(rst)
        ary <= 4'h00;
    else
        ary <= {ary[2:0],ary[3]};
end

跑馬燈,用組合邏輯做不出來,是因?yàn)樗妮敵霾粌H僅跟輸入有關(guān),也跟前一個狀態(tài)有關(guān)。

看到時序邏輯,很多人發(fā)現(xiàn)了無比強(qiáng)大的clk信號,到處都有他的影子,他才是真正的到處留種的風(fēng)流才子。

“輸出不僅僅跟輸入有關(guān),也跟前一個狀態(tài)有關(guān)”,這句話,應(yīng)該很熟悉吧。 -----沒錯,就是狀態(tài)機(jī)。
后面有個專門貼講FSM,這是一個非常有效的解決問題的工具------智商99的人可以做到智商120的設(shè)計。
如果天才用了,那肯定要更加newbility了。

下面看個十進(jìn)制的計數(shù)器,是前幾天給一個初學(xué)者的sample,但愿這小哥真的去看懂了,而不是搞完畢設(shè)就完蛋鳥。

    module bcd_counter(rst, clk, qout);
    input rst;
    input clk;
    output[7:0] qout;

    reg [3:0] low;
    reg [3:0] high;

    assign qout ={high,low};

    always @(posdage clk)
        if(rst)
            begin
                low <= 4'h0;
                high <= 4'h0;
            end
        else
            begin
                case(low)
                0,1,2,3,4,5,6,7,8:
                    low <= low+4'h1;
                9:
                    begin
                        low <= 4'h0;
                        case(high)
                            0,1,2,3,4,5,6,7,8:
                                high <= high+4'h1;
                            9:
                                high <= 0;
                        endcase
                    end
                endcase
            end
    end module  

這里面有2個十進(jìn)制數(shù)據(jù),分別占用一個nibble---4個bit,其實(shí)就是BCD碼。
使用了case語句來完成,而且兩個case還套起來用了,跟C語言一個樣,照貓畫虎即可。

細(xì)心的文藝青年,應(yīng)該發(fā)現(xiàn)了,module的定義貌似跟以前不一樣了。
不用貌似,就是不一樣了,這是2種風(fēng)格,其實(shí)苦B的C語言也有這個風(fēng)格的。
bool fun1(X,Y)
int X, Y;
{
}
C語言的古老風(fēng)格,現(xiàn)在很少人用了,畢竟多敲鍵盤,不代表多干活。
那時候C語言還沒有國際標(biāo)準(zhǔn),此K&R C是以2個工程師的名字首字母命名的。
后來才有ANSI C和ISO C(C89/C90/C99),這巨人的肩膀好高啊,搞技術(shù)就不能有恐高癥。

Verilog亦是如此,建議使用輸入輸出定義在括號里面的風(fēng)格,至少要少碼好幾個字母不是。


不知道有沒有人注意到,上面幾個帖子用的都是always @(posdage clk),敏感信號列表中不見rst的身影。
下面的判斷rst的信號,決定復(fù)位還是干活,這叫做同步復(fù)位。

同步復(fù)位,你要理解成rst一有效就復(fù)位就錯了。同步的含義,與CLK同步,類似于與襠中央保持一致。

異步復(fù)位,是立即的。異步復(fù)位,同步釋放。這個話題就比較遠(yuǎn)了,后面有個帖子,會專門說這個話題。


后面的會稍微有些難度,但我會為了入門的學(xué)習(xí)臺階,盡量把難的趕跑,容易的留下-----“男的趕跑,女的留下”。


預(yù)知后市如何,明天再看紅盤綠盤。
地下室
 樓主| 發(fā)表于 2012-5-12 00:23:20 | 只看該作者
4、阻塞和非阻塞

話說大禹治水,因?yàn)樗系嗡”贿沁橇耍坏靡讶ロ敻住?br /> 他也琢磨啊,其父也不是等閑之輩,沒搞定,說明必須得換個法子,否則自己也得被大哥給嗝屁了。
大禹父子治水,分別用的是阻塞和非阻塞的方法,下面我們就扯一下邏輯電路中的阻塞和非阻塞。

通常所說的阻塞和非阻塞,指的是always塊中的語句。
always語句中有時序邏輯,也有組合邏輯。前者用非阻塞,后者用阻塞。
其實(shí)“阻塞”這個術(shù)語,也是專門給軟件出身的電工看的,硬電工才懶得管你阻不阻的呢。

    reg[7:0] in1;
    reg[7:0] out;

    always @ (posedge clk)
    begin
        in1 <= in1+8'h01;
        out <= in1;
    end
endmodule


先從容易的下刀,我們先看看這個非阻塞的語句,它很簡單,就是in1的自身完成一個自加一
注意這個“<=”,是不是又想起了C語言里用來搞指針的“->”,不過真的沒有一毛錢的關(guān)系。

in1拿到的是clk上升沿之前的“in1”值再加1,跟clk上升沿之后的in1沒有關(guān)系了。


正如,已畢業(yè)的小明的時候?qū)在讀大四GF小芳承諾說,哥等你大學(xué)畢業(yè)就討你做LP了。
時光如箭,日月如梭,時間如白駒過隙,學(xué)校7月份小芳走出了象牙塔的大學(xué)校門。
小明履行承諾,娶小芳為妻。話說,無巧不成書。
小芳大學(xué)畢業(yè)了,但大三的同學(xué)也該升級讀大四了,正好里面也有個女娃的名字也叫小芳。
搶答開始,問:小明,娶的是哪個小芳?

答案是,去年讀大四今年畢業(yè)的那個小芳,而不是去年大三今年大四的那個小芳。
您感覺拗口嗎,反正我有點(diǎn)繞口令的感覺了。

非阻塞操作也是這個效果,你娶的是畢業(yè)(clk上升沿)之前的那個大四的小芳。

我們知道硬件是并行執(zhí)行的,所以,上面的代碼,這么寫,效果一樣。
        in1 <= in1+8'h01;   //老小芳畢業(yè),新小芳升級大四
        out <= in1;         //小明娶老婆
   


但,如果把非阻塞改為阻塞的,那小明娶的老婆,到底是誰?且看分析。
        in1 <= in1+8'h01;   //老小芳畢業(yè),新小芳升級大四
        out <= in1;         //小明娶老婆
所謂阻塞,就是一步一步來,就是寫軟件的那個思路,小明順利娶他昔日的戀人為妻。

我們要調(diào)整語句順序了,再看看小明的執(zhí)行結(jié)果咋樣
        in1 = in1+8'h01;    //老小芳畢業(yè),新小芳升級大四
        out = in1;          //小明娶老婆

要順序執(zhí)行的哦,先完成“老小芳畢業(yè),新小芳升級大四”,然后“小明娶老婆”。
小明娶到了剛剛大三升大四的小芳,你完全可以認(rèn)定,小明是一個喜新厭舊的文藝青年。

而如果,做下語句的調(diào)整,就像下面這樣
        out = in1;          //小明娶老婆
        in1 = in1+8'h01;    //老小芳畢業(yè),新小芳升級大四
小明喜新厭舊的企圖,被強(qiáng)大的阻塞語句,給堵回去了。

一般用阻塞語句來實(shí)現(xiàn)assign語句描述困難的組合邏輯,一般情況下代碼塊會比較小。
非阻塞的一般是用于時序邏輯,時序邏輯往往比較復(fù)雜,有時候復(fù)雜得有些變態(tài)。
如果月老執(zhí)行Verilog語句的時候,一不小心,小明就娶錯了老婆。


阻塞,有個地方用起來很方便,也許你也猜到了,testbench

tb代碼本身,就不被用來綜合到電路,所以,可以大膽使用阻塞語句
        #10 rst = 1;
        #10 clk = 0;
        #10 clk = 1;
        #10 clk = 0;
        #10 clk = 1;
        #10 rst = 0;
        repeat(100)
        begin
            #10 clk = 0;
            #10 clk = 1;
        end

這是一段,模擬單片機(jī)復(fù)位釋放以及振蕩器啟動的激勵。
反正是順序執(zhí)行的,就拿這寫軟件的腦袋來理解就夠了,估計軟電工都喜歡。


客戶下單了,我得看看還有多少物料,還得準(zhǔn)備安排焊接。

今天就先扯到這里吧。
請一定記住今天的學(xué)習(xí)任務(wù),我們要幫小明娶到正確的老婆。
6
 樓主| 發(fā)表于 2012-5-12 00:23:28 | 只看該作者
5、同步和異步設(shè)計

前面已有鋪墊,同步就是與時鐘同步。
同步就是走正步,一二一,該邁哪個腳就邁那個腳,跑的快的要等著跑的慢的。
異步就是搞賽跑,各顯神通,盡最大力量去跑,誰跑得快,誰拿獎牌。

我們舉個例子,SPI接口,他是一個低成本的單端的高速串行數(shù)據(jù)傳輸協(xié)議。
四個信號,nCS、SCK、MISO、MOSI

下面是一個Slave SPI的接口部分,簡化了,

model mySPI(input nCS, input SCK, input MOSI, output MISO);
    reg[3:0]    bitcnt;
    reg[7:0]    shift_in;   //寫入
    reg[7:0]    shift_out;  //讀出

    reg[7:0]    data_wt;
    reg[7:0]    data_rd;

    always @(posdge SCK)
    if(nCS)
        bitcnt <= 0;
    else
    begin
        if(bit_cnt!=4'h7)
        begin
            bitcnt <= bitcnt+4'h1;
            shift_in <= {shift_in[6:0], MOSI};
            shift_out <= {shift_out[6:0], 0};
        end
        else
        begin
            bitcnt <= 4'h0;
            ...........
            data_wt <= deshift_in;
            shift_out <= data_rd;
        end
    end
endmodule

這段代碼是同步的還是異步的?
其實(shí),他遠(yuǎn)看是同步的,近看是異步的,仔細(xì)一看還是同步的。

大致一看,丫的還配時鐘呢,按鐘點(diǎn)走步,八成是同步的。
然后一想,不對啊,SPI的SCK是Master提供的,跟自家的全局時鐘沒有必然關(guān)系啊,異步的。
思索一陣,假如俺系統(tǒng)全局時鐘都靠SCK不就是同步的了嗎?

實(shí)際情況如何呢?
舉個例子,SPI Flash,比如25系列,其實(shí)就是同步的,SCK就是全局時鐘。

比如某ARM core的MCU內(nèi)置SPI模塊,為了簡化問題,我們只談Slave的情況,問題就來了。
ARM MCU肯定有其自家的時鐘,SPI的Master又送來一個時鐘,咋辦呢?

當(dāng)你發(fā)愁的時候,你該慶幸自己遇到了幾乎所有入門的人都必須解決的問題----多時鐘系統(tǒng)。

多時鐘,各自都是同步,放在一起就是異步。
正如兩隊(duì)人馬,都在走正步,**走得快,國軍走的更快,他們各自都是同步的,扯蛋到一塊就是異步。
咋辦呢?
叢林法則要起作用了,單一時鐘同步化處理,勢力小的聽勢力大的人安排。

model mySPI(input clk, input nCS, input SCK, input MOSI, output MISO);

    always @(clk)
    ...................................
endmodule

clk是自家的全局CLK信號,對方的SCK信號,只在自家CLK觸發(fā)才看一眼對方的各個信號,包括SCK信號。
這就是強(qiáng)者的統(tǒng)戰(zhàn)部,你家的可汗(SCK),見到我家皇帝(clk),也是稱臣子。

當(dāng)然,這個處理方法是有前提的,就是clk的頻率要遠(yuǎn)遠(yuǎn)高于SCK信號。
所謂遠(yuǎn)遠(yuǎn)高于,就是即使我clk的上升沿,瞄你一眼,就不會漏掉你所有的表現(xiàn)。
根據(jù)XXXOOO定律,要達(dá)到采樣不丟信息,尼瑪?shù)念l率至少是人家的2倍,實(shí)際應(yīng)用中一般保證4倍,或更高。
就好比有4個小弟的人,叫只有一個小弟的人,對自己稱臣,聽話大家就,不聽就干你。

前面有朋友談到了復(fù)位信號的同步化處理,最簡單的就是復(fù)位和釋放都同步處理,我前面幾個帖子有用到。
復(fù)位,是什么,是殺頭,復(fù)位釋放是什么,是重新投胎。
你跟情敵斗志斗勇的時候,想到了制勝的一招時候,你覺得是立馬去執(zhí)行,還是等下一次例行見面時再執(zhí)行。
當(dāng)然是立馬執(zhí)行了,這不就是異步把情敵給復(fù)位了嘛。
你擊敗情敵之后,要對全班同學(xué)宣布的你勝利,是每天早會宣布呢,還是里面召集同學(xué)宣布呢?
此時大勢已定,當(dāng)然是按CLK四平八穩(wěn)來得妥當(dāng),大家會認(rèn)為你是一個做事不魯莽,有步驟的,電工十佳青年。

所以,我們稱之為,異步復(fù)位,同步釋放。
always @ (posedge clk or negedge nRST)
    if (!nRST)
        擊敗情敵;
    else
        把擊敗情敵的戰(zhàn)果宣布;
   

再舉個例子,Memory的訪問,為了簡化,我們做個ROM,這樣只有讀的一種情況,適合理解記憶
model memory8(input[7:0] addr, output[7:0] dat)
    reg[7:0]    rom[255:0];
    assign dat = rom[addr];
endmodule

model memory8(input clk, input[7:0] addr, output[7:0] dat)
    reg[7:0]    rom[255:0];
    reg[7:0]    outbuf;

    assign dat = outbuf;
    always @(posedge clk)
        outbuf <= rom[addr];
endmodule

簡單的是異步的,只要地址變化了,輸出立馬就表現(xiàn)。
我們實(shí)際使用的27系列的EPROM,61系列的異步SRAM,都是這樣的,始終把OE信號置于有效即可。

復(fù)雜的就是同步的了,我不管你地址變了沒,在CLK上升沿到來之前,我懶的理你。
異步的SRAM,剛查了下,也有61系列的; 看來不能以前綴來瞎子摸象了。

一般實(shí)際用的時候,異步SRAM肯定比同步的好用,同步的老要CLK,你是IO口模擬呢,還是怎么輸出呢?
但同步的Memory也不是吃素的,吃的多必然長得壯,同步可以提高更高的傳輸速度。

該往回說了,為何同步電路可以提高更高的速度呢?

異步,就是賽跑,速度以跑得慢的人為準(zhǔn),團(tuán)隊(duì)精神嘛,這不能平均,只能搞木桶原理。
同步,就是大家按一個節(jié)奏,你慢的話,就用2個節(jié)奏完成,但必須按節(jié)奏。

這樣負(fù)責(zé)協(xié)調(diào)的那個人,就是喊一二一的那個人(clk),可以把握全局的節(jié)奏來達(dá)到速度最大化。

所以一般FPGA里面都有全局時鐘,強(qiáng)大的扇出能力,最小的傳輸延遲,因?yàn)樗抢洗螅觅Y源他先挑的。
他就好比系統(tǒng)的原子銫鐘,他很精確,我們每天跟他對一下時間,我們自家的表,就不會產(chǎn)生誤差積累。

異步,2個隊(duì)伍,各自有自家的老大,比如一個是地址線,一個是數(shù)據(jù)先,某個時刻,主控一抓。
可能地址線跑得快,數(shù)據(jù)線跑的慢,就會出現(xiàn)數(shù)據(jù)錯位的情況,數(shù)字電路上叫競爭。
你作為運(yùn)籌帷幄的總統(tǒng),不能斷定2個隊(duì)伍能同事到達(dá),你仍然用這個方法,你就是在冒險。

作為設(shè)計而言,應(yīng)盡量避免競爭冒險。
如果系統(tǒng)簡單,工期緊,速度要求低,邏輯簡單,用異步的。
如果系統(tǒng)龐大,速度要求越高越好,邏輯交叉錯節(jié),堅決用同步的。
同步設(shè)計就是個工具,讓智商90的人可以干智商120的人的工作。

Asynchronous 和 Synchronous 這兩個單詞我老是分不清
后來學(xué)軟件學(xué)邏輯電路,給記住了,帶A的要要冒尖的,是異步的

明天要講的有限狀態(tài)機(jī),是以同步設(shè)計為基礎(chǔ)的設(shè)計方式,然后我們就可以用90的智商做150智商的工作了。
7
 樓主| 發(fā)表于 2012-5-12 00:23:37 | 只看該作者
6、有限狀態(tài)機(jī)

狀態(tài)機(jī),只要C代碼寫過2年的人,估計無人不識君,稍微復(fù)雜的邏輯都可以借助狀態(tài)機(jī)來簡化問題。

為了方便,我們使用前面用過的一個例子,來說明狀態(tài)機(jī)的應(yīng)用,也就是說我們前面已經(jīng)有意無意的用過狀態(tài)機(jī)了。

我們以SPI的Slave接口,為例,來說明狀態(tài)機(jī)的使用


為了簡化問題
1、我們沒有把信號同步到本地時鐘
2、把其他信號同步到SCK
3、我們把SPI暫時按照單向來分析

下面,我們分析SPI通訊
1、nCS高電平時候,總線是空閑的
2、nCS低電平時傳輸數(shù)據(jù)
3、滿了8個bit,湊夠了一個字節(jié),要保存當(dāng)前已經(jīng)收到的字節(jié),并準(zhǔn)備收下一個;

nCS高電平的時候,我們稱之為idel態(tài)(IDEL)
接受0~7逐個bit的時候,稱之為bit接受態(tài)(BIT_RECV)
收滿一個字節(jié),稱之為字節(jié)轉(zhuǎn)存態(tài)(BYTE_SAVE)

我們開始畫狀態(tài)轉(zhuǎn)移圖


model SlaveSPI(input nCS, input SCK, input MOSI, output MISO);

parameter IDEL = 0,
          BIT_RECV = 1,
          BIT_SAVE = 2;

    reg[3:0]    bitcnt;
    reg[7:0]    shift_in;   //寫入
    reg[7:0]    shift_out;  //讀出

    reg[7:0]    data;

    reg[1:0]    state;
    reg[1:0]    next_state;

    always @(*)
    begin
        case(state)
        IDEL:
            if(nCS==1'b1)
                next_state = IDEL;
            else
                next_state = BIT_RECV;
        BIT_RECV:
            if(nCS==1'b0)
            bgein
                if(bitcnt<4'h8)
                    next_state = BIT_RECV;
                else
                    next_state = BYTE_SAVE;
            end
            else
                next_state = IDEL;
        BYTE_SAVE:
            if(nCS==1'b0)
                next_state = BIT_RECV;
            else
                next_state = IDEL;
        defalut:
            next_state = IDEL;
        endcase
    end


    always @(posdge SCK)
        if(nCS)
            bitcnt=0;
        else
            state = next_state


    always @(posdge SCK)
        case(state)
        BIT_RECV:
            begin
                bitcnt <= bitcnt+4'h1;
                shift_in <= {shift_in[6:0], MOSI};
            end
        BYTE_SAVE:
            begin
                bitcnt <= 4'h0;
                data <= deshift_in;
            end
        endcase
   
我用了所謂的三段式,來描述這個狀態(tài)機(jī),用了3個always語句
第一個always用來描述狀態(tài)轉(zhuǎn)移的條件
第二個always用來描述狀態(tài)轉(zhuǎn)移
第三個always用來描述狀態(tài)機(jī)的輸出,也就是狀態(tài)機(jī)實(shí)際要干的活


與前面帖子(同步和異步設(shè)計)中的SPI代碼相比,是不是冗長了很多。
冗長,并不代表著脫褲子放屁,自找麻煩。您難道沒有反顯,代碼很容易讀懂了嗎?

沒錯,這就是空間換時間的策略,我們寫更長的代碼來增強(qiáng)可分析性。

狀態(tài)機(jī)的代碼撰寫一般不復(fù)雜,復(fù)雜的是狀態(tài)機(jī)的構(gòu)建過程,這個過程中,我們要分析
實(shí)際遇到的各個情況,同時把狀態(tài)機(jī)進(jìn)行優(yōu)化,某些狀態(tài)進(jìn)行合并,某些狀態(tài)去掉。
  
有人問,為何某些狀態(tài)要去掉?
這要說下FSM的來頭了,有限狀態(tài)機(jī),是有限的狀態(tài)機(jī)。
自然界實(shí)際的狀態(tài)機(jī),往往起狀態(tài)的數(shù)量,是非常大的,直接建模使用簡直是勞民傷財。
而且,現(xiàn)實(shí)的往往是無限的狀態(tài)機(jī),這根本無法用于工程實(shí)現(xiàn),所以有限狀態(tài)機(jī)就橫空出世了。

正如,軟件算法中的DAG(Directed Acyclic Graph)有向無環(huán)圖,比純粹的圖有實(shí)用價值。
二叉樹,比多叉樹,也更容易實(shí)現(xiàn)。

越說,軟件和FPGA越近了。可謂是天下大勢,分久必合,合久必分。

好了,這篇比較倉促,周六晚上專門來辦公室寫這個帖子。
8
 樓主| 發(fā)表于 2012-5-12 00:23:44 | 只看該作者
7、設(shè)計一個只有4條指令的CPU


我們要設(shè)計一個簡單的CPU

既然做CPU,我們要做流水線的,要簡單,做2級流水線就夠了。

為了實(shí)例的簡單,我們選擇設(shè)計一個8bit的MCU的內(nèi)核
仍然我們要簡單,所以選擇RISC的內(nèi)核,類似PIC的結(jié)構(gòu)
還是為了要簡化,我們只支持4條指令
繼續(xù)為了要簡化,我們不考慮Status寄存器

有人會問,只有4條指令,你還加減法都有,有一個不就可以了。
這也是我有意的,你想,假設(shè)ALU只能做加法,你不覺得ALU這個名稱太不名副其實(shí)了嗎。

mov  A,#35H 把立即數(shù)mov到A寄存器
add  A,#42H (A) + 12 -> A
sub  A,#62H (A) - 12 -> A
JMP  imd    跳轉(zhuǎn)到某地址


我們先給他們做機(jī)器編碼,我們用16bit寬度的指令集編碼

0x0035      00是MOV的OP code
0x0142      01是ADD的OP Code
0x0265      02是SUB的OP code
0x8000      80是JMP的OP CODE

我們繼續(xù)看,指令集,用Verilog的方式來描述
16'b0000_0000_????_????     MOV
16'b0000_0001_????_????     ADD
16'b0000_0010_????_????     SUB
16'b1???_????_????_????     JMP

我們可以看到JMP的跳轉(zhuǎn)地址范圍是15個bit地址,也就是32K地址范圍

有人說ALU很重要,好,我們就先來看ALU的組成,因?yàn)橹挥屑訙p2種情況,所有ALU的OP代碼只用1個bit表示
op為1的時候,做加法,為0的時候做減法。

module alu(input op, input[7:0] in1, input[7:0] in2, output[7:0] out)
    assign out = op ? (in1+in2) : (in1-in2);

看到上面的代碼,估計不少人大跌眼鏡,莫非傳說中的alu就這么簡陋。
沒錯,如果你只要做加法和減法,而且不考慮進(jìn)位和溢出的ALU,就是這么easy的。

好了,cpu的運(yùn)轉(zhuǎn)過程,包括加載指令,解碼指令,執(zhí)行指令,大家都知道。

我們還要使用流水線技術(shù),雖然這里不用也許更簡單,但我們的目標(biāo)是學(xué)習(xí)。

      一  |   加載指令1   |   加載指令2    |   加載指令3    |   ..........
----------+---------------+----------------+----------------+-----------------
      二  |               |   解碼1 執(zhí)行1  |   解碼2 執(zhí)行2  |   解碼3 執(zhí)行3

我們可以看到加載和解碼和執(zhí)行,并沒有在一個周期中完成,而是分開了
在運(yùn)行第二條指令的時候,CPU正在加載第三條指令,一心二用,事事不耽擱。

clkcnt;

always @(posdge clk)
    if(nCS)
        clkcnt <= 0;
        instr <= 0;
    else
        instr <= rom_dat_out;


下面是CPU的解碼和執(zhí)行過程

always @(posdge clk)
    if(!nCS)
    casex(instr)
        16'b0000_0000_????_????:        //MOV
            begin
                acc <= instr[7:0];
                pc <= pc + 16'h0001;
            end
        16'b0000_0001_????_????:        //ADD
            begin
                acc <= aluout;
                pc <= pc + 16'h0001;
            end
        16'b0000_0010_????_????:        //SUB
            begin
                acc <= aluout;
                pc <= pc + 16'h0001;
            end
        16'b1???_????_????_????:        //JMP
            begin
                pc <= instr[14:0];
                pc <= pc + 16'h0001;
            end


下面完成CPU核心和ALU之間的連線

assign aluop  = (instr[15:8]==8'h01);
assign aluin1 = acc;
assign aluin2 = instr[7:0];

alu alu1(aluop, aluin1, aluin2, aluout);

有人說,只看到執(zhí)行指令,沒看到解碼指令的過程,有木有啊?當(dāng)然有

16'b0000_0000_????_????     MOV
16'b0000_0001_????_????     ADD
16'b0000_0010_????_????     SUB
16'b1???_????_????_????     JMP

這幾個逐個的case不就是在做解碼?只是沒有獨(dú)立的解碼步驟而已,因?yàn)樘唵瘟寺铩?br />
還有個地方,我故意做了遺漏,就是JMP指令的處理。

所謂流水線,就是取指和執(zhí)行是同時的,但JMP的到來,帶來了異常。
正常都是PC加一,所以取指其實(shí)一直在取下一條指令,而JMP的目標(biāo)是不確定的,所以取的指令就不對了

我們一般稱之為預(yù)測失敗,然后繼續(xù)取JMP目標(biāo)地址的指令,但執(zhí)行部分,會有一個空的指令周期。
從CPU的用戶角度看,就是JMP指令要使用2個指令周期。

CPU的設(shè)計基本到此結(jié)束了。
關(guān)于FPGA,我也沒有能力做太深入的講解了,否則誤人子弟,豈不是背離了我的目標(biāo)。

我的blog基本上也是很少更新,你點(diǎn)進(jìn)去看也沒多少貨。
有個哥們說得好,MP的博客,寫得比別人的微薄還短小。

至此,這個帖子連載終于完成了,總算沒有辜負(fù)自己和一些網(wǎng)友。
9
 樓主| 發(fā)表于 2012-5-12 00:24:40 | 只看該作者
占樓完成,下周每天一貼。
10
發(fā)表于 2012-5-12 09:24:46 | 只看該作者
算沙發(fā)吧
11
發(fā)表于 2012-5-12 09:39:31 | 只看該作者
頂一把毛片哥,多謝先啦!     
12
發(fā)表于 2012-5-12 12:46:21 | 只看該作者
mp哥太厲害了,fpga也會,崇拜ing。
13
發(fā)表于 2012-5-12 16:41:34 | 只看該作者
要自己搞一個小項(xiàng)目來做,一步一步貼出來,包括軟件的使用。
毛片用X還是A的?
14
 樓主| 發(fā)表于 2012-5-12 17:15:56 | 只看該作者
如果你不需要自己設(shè)計,只需要看懂一些代碼,理解Team中別人的意思。
這個帖子就是教你一周學(xué)會XXOO的

如果你已經(jīng)入門而登堂入室了,這個帖子真的不應(yīng)該看了,否則會退步的。
15
發(fā)表于 2012-5-13 08:18:12 | 只看該作者
thanks
16
 樓主| 發(fā)表于 2012-5-13 18:35:41 | 只看該作者
要自己搞一個小項(xiàng)目來做,一步一步貼出來,包括軟件的使用。
毛片用X還是A的?
忘情天書 發(fā)表于 2012-5-12 16:41


還軟件的使用,要不要拿著你的手敲鍵盤呢,你還以為你花錢請我做你的家庭教師呢。
哥哥我這一周教你學(xué)會XXOO可都是實(shí)打?qū)嵉牧希回?fù)責(zé)教人用軟件拉這個menu點(diǎn)那個button的。

我只寫Verilog的,至于X還是A要看哪個有優(yōu)勢了-------采購周期短,價格石灰,等等。
17
發(fā)表于 2012-5-13 18:46:12 | 只看該作者
田鼠的存在意義就是呵呵大家鄙視的
18
發(fā)表于 2012-5-13 21:50:34 | 只看該作者
VHDL語言也不是很難啊
19
發(fā)表于 2012-5-13 22:36:59 | 只看該作者
田鼠的存在意義就是呵呵大家鄙視的
dddg 發(fā)表于 2012-5-13 18:46
我鄙視你個卵子!哥哥早在08年就用EP2C8做過項(xiàng)目。FPGA最難就是用硬件的思維去實(shí)現(xiàn)軟件。用軟件有人教最好啦,不然你會在線仿真設(shè)置?離線仿真編寫?那些語言還不是差球不多,幾天看本書就行了。就是一些思維要轉(zhuǎn)變而已,什么阻塞和非阻塞的區(qū)別,同步異步,單一時鐘N個時鐘同步,保持,狀態(tài)機(jī),我插死你。你要是從頭開始,花在軟件上的時間比那些爛語言要多得多,除非你不是很懂C和硬件基礎(chǔ)。tnnd,你要是綜合出錯了,都不知道在那里找原因。綜合知道嗎?我一磚拍死你個瓜娃子。
20
發(fā)表于 2012-5-13 22:37:57 | 只看該作者
還軟件的使用,要不要拿著你的手敲鍵盤呢,你還以為你花錢請我做你的家庭教師呢。
哥哥我這一周教你學(xué)會XXOO可都是實(shí)打?qū)嵉牧希回?fù)責(zé)教人用軟件拉這個menu點(diǎn)那個button的。

我只寫Verilog的,至于X還是A要看 ...
McuPlayer 發(fā)表于 2012-5-13 18:35
我一磚拍死個毛皮

評分

參與人數(shù) 1積分 -10 收起 理由
kbgyzp -10 鄙視你!丫的要不你來給哥上一課

查看全部評分

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 97在线观看视频 | 天天操天天擦 | 麻豆91在线 | 国精品日韩欧美一区二区三区 | 麻豆app在线观看 | 日韩毛片免费观看 | 色原网站 | 国产精品成人免费福利 | 精品h视频 | 一级不卡毛片 | 无限免费动漫看片的 | 日韩欧美中文字幕一区二区三区 | 在线免费观看色 | 丁香婷婷在线视频 | 玖玖精品视频在线观看 | 国产精品久久久一区二区三区 | 中文国产成人精品久久久 | 亚洲 欧美 手机 在线观看 | 久久99热狠狠色精品一区 | 国产激情对白一区二区三区四 | 麻豆你懂的| 97成人在线视频 | 精品成人一区二区三区免费视频 | 国产亚洲精品自在久久77 | 日产精品一卡2卡三卡4乱码久久 | 99精品国产在热久久 | 午夜视频在线免费播放 | 毛片一区二区三区 | 蓝军出击电视剧在线观看 | 天天夜夜啦啦啦 | 国产三级网 | 国内永久第一免费福利视频 | 伊伊人成亚洲综合人网香 | 亚洲一区综合在线播放 | 99视频在线精品免费观看18 | 日韩免费福利视频 | 亚洲精品毛片久久久久久久 | 亚洲国产亚洲片在线观看播放 | 免费看黄视频的网站 | 久久亚洲国产高清 | 国产最新视频 |