在閱讀本文之前,推薦先閱讀筆者的另一篇文章:《計組碎碎念》,了解北航計組課設內容全貌。
閱讀本文,您的收獲可能有:從課下測試部分,了解一些用logisim畫電路實現功能的部分可能出現的bug以及修復方法;從課上測試部分,了解一下課上測試的問題類型以及可能出現的bug,知道怎么准備課上測試。
課下測試部分:
P0課下測試部分的題目是CRC校檢,4-bit ALU,GRF,正則表達式匹配。
CRC校檢:
這個題比較簡單,在這個題之前有一節講解搭建CRC校檢電路的教程,該教程的意義不只是告訴我們CRC咋搞,它更重要的意義在於:告訴我們設計出符合題目要求電路的基本步驟:找輸入輸出(有哪些?多少位?)、分析輸入與輸出的關系(暴力真值表 or 找到計算規律,比如模2除法)、分塊搭建(和程序設計里寫函數並調用類似),測試(平凡數據、極限數據、非法數據、搭測試電路自動化測試)。注意,電路是解決問題的一種工具,而不是解決問題的方案,通俗一點來說就是給你一把槍並不代表你能打中人。所以,在搭建電路之前,一定要把問題的模型抽象出來,算法想清楚(最好寫一下),這樣就相當於保證了你掌握了射擊技術,這時拿到槍,才有更高的概率打中人。
經驗教訓:在看CRC前面的教程的時候,以為只能是8位數,所以在模2除法之前沒有對8位的原數據幀進行補0操作,導致錯誤(題目其實已經提示要補成11位了但我只是認為只要結果是11位就好);模2除法開始沒有看懂余數的生成規則。
4-bit-ALU:
這個題算是一個水題吧,只讓實現四位的加減法,與,或運算,考慮到logisim中有現成的加減法器,所以這個題很容易過去。唯一可能注意的地方,就是模塊的appearance,如果不對應的話必定會錯得很離譜。
關於ALU,說說logisim自帶的比較器吧,這個比較器默認是有符號數比較,所以使用時一定要注意是否需要修改其工作狀態。
實現GRF:
(部編版語文教材《童趣》插圖)
余憶童稚時,能張目對日,明察秋毫…………不好意思走錯片場了。。。
這個題不算難,但卻足夠繁瑣。從入手到AC,我大約用了三個小時。雖然最后是交了第二次就過了(第一次忘了把自己測試用的時鍾去掉了,第二次把時鍾改回普通輸入之后就對了),但是期間是踩了很多的坑。下面把此題的坑點總結一下。
第一,時鍾的給予者沒有搞對。根據題中給出的測試電路,我們發現測試用的時鍾是測試電路給出來的,所以我們只需要用一個普通的輸入去接受這個時鍾信號就可以了,而不必自己加時鍾。
第二,DMX的使用。之前就知道DMX似乎有一個Three state的選項,但是不知道有什么用處,直到今天在某位大佬的評論中才明白:如果Three state勾選為yes,那么DMX輸出端沒有被選中的路徑會保持原來的值不變,這樣就實現了本題的重要需求:根據A3的值不僅要將數據寫入到相應的寄存器中,同時還保持其它寄存器不變。 有些同學是最開始沒想到這一點,所以提交出錯,而我是想到了這一點,苦於不知道如何實現這個功能而去評論區找靈感,才發現這個簡單方法,並知道了Decoder同樣擁有三態選項。多讀官方幫助文檔,會有很多好處的!
第三,別一用tunnel就興奮,這玩意兒確實省事兒,但是你不能用着用着忘了自己要干啥,以至於腦子抽筋把32位輸入用spliter拆開了,題目中本來就要求32位輸出,別忘了任務!
第四,還是模塊的appearance,這種比較復雜的,一定要看測試電路怎么設計的,然后在appearance中逐個檢查看看接口是不是對應的!!!
正則表達式匹配:
吸取了CRC的經驗,先認真讀了題,了解了正則表達式的生成規則,以及檢驗規則:在輸入到某一個字符x的時候,發現從這個字符前面的某個字符y開始,一直到x所組成的字符串如果符合要求,就輸出1。本題要求同步復位,是一個容易錯的地方:一是可能會忘記按同步復位連,二是即使想同步復位但連錯了。我屬於后者。不知為什么我這個題用到了15個狀態,要不是有analyse circuit我就死了
//10月16日補充:確實是我狀態想多了,其實我那個本質上是個Moore型狀態機,改成Mealy型之后瞬間15->7,然后經過室友的優化,合並了狀態,最后只用3個狀態就結束了(主要是對b的處理以及Mealy型本身省狀態的優勢)
經驗教訓:1.有限狀態機搭建關鍵操作:
只有狀態存儲電路中有寄存器,也就是說,在搭建狀態轉移電路時,可以使用analyse circuit,注意先把輸入數據全部用spliter分開 (這條純屬廢話,只是提醒我這個好久沒搭建過狀態機的人)
填寫真值表的時候,操作規模主要取決於輸入的個數,如果輸入為n個,輸出為m個,則需要操作的次數為m*2^n,所以一般不超過7個輸入都可以接受,不要太害怕
狀態少可以用獨熱編碼,狀態多就必然得用二進制編碼或者其他更優秀的編碼
看清楚是搭建Moore型還是Mealy型狀態機,這兩種狀態機的輸出不同,Mealy型狀態機設計輸出的時候需要傳遞寄存器保存的狀態以及當前輸入
如果在搭建完畢狀態轉移電路之后發現自己類型搭建錯誤了,不要着急,這兩種類型的狀態機的狀態轉移部分基本是一樣的,所以可能不需要修改狀態轉移電路
有限狀態機中的同步復位:一種實現方法:二選一多路選擇器法。利用復位信號reset選擇是輸出算出的狀態(即狀態轉移電路剛算出來的下一次的狀態)還是初始置零狀態。
看圖便於理解:
(某巨佬的圖)
下面是我對於該同步復位方法的應用(看中間)
Warning:錯誤的“同步復位”:首先如果僅僅將CLR與寄存器的reset相連肯定不能實現同步的操作,比如在時鍾處於某個電平時,如果CLR置1,那寄存器狀態會立馬改變,不能按照題目要求的在時鍾上升沿才實現復位操作。 其次,如果上面直接連reset行不通,很容易想到直接在CLR后面加一個寄存器,然后同步清除狀態寄存器的值,但是這個方法也有問題,雖然在CLR為1時復位寄存器沒有問題,但是由於CLR置0之后需要一個上升沿才能到reset,這個上升沿狀態寄存器是不能存儲狀態的,所以后面要延遲了一個周期,所以這種方法也不是同步的,這樣的話輸出就有可能出錯。
2.模塊外觀的重要性:模塊和要求的有一點不一樣,就會running time error輸出xxxxx。看測試電路是怎么連接的,別輸入的順序連接反了,不然也是running time error
備戰P0心情:今天嘗試重做斐波那契數列,結果從七點搭到十一點,愣是沒有搭出來,心情爆炸,感覺自己會死在P0上,希望周四不要涼涼。學會兒競賽換換腦子。
課上測試部分:
第一題:題面大概是有一個售貨機,你只能往里面不投幣,投一元,投兩元,投五元,只要大於等於5元就要使得出貨信號dispense為1,然后找錢信號1,2,4相應的給出。題目要求異步復位,要求一旦出貨之后,就需要讓售貨機下一個狀態無條件變成初始的沒有接收到錢的狀態,並且忽略剛變回初始狀態的時候的投幣(應該是這樣,題面有點記不清楚了),要求使用moore型狀態機實現。
本題有很多同學最開始搭成了mealy型狀態機,但是這樣似乎是過不了的,不妨舉一個例子:假設現在已經投入了4元,即now_state=4,即狀態存儲電路里面現在存儲的是4,我們現在輸入1元,那么由於mealy型狀態機的輸出與輸入和當前狀態有關系,故輸出變為dispense=1,考慮這時候的狀態轉移電路,是一個state=5與一個1元輸入進行運算,得到state=0,即這時候state=0到了存儲電路的左邊,但目前state里面還是4,等到下一個時鍾上升沿來臨的時候,我們給一個輸入,比如輸入為5元,我們希望這個輸入被忽略掉,並且輸出dispense=0,但是事實上,dispense是state=0與輸入1共同決定的,實際上此時卻是輸出了dispense=1,與題目要求不符,所以mealy型就炸了。下面給出mealy型的圖以便於思考這個錯誤例子。
關於正解,其實就是按照moore型直接搭建即可。狀態有0-9這十個,輸入有四種,由狀態和輸入用真值表畫出來狀態轉移電路,然后利用現在的狀態列出輸出的四個值的真值表(注意理解moore型狀態機),狀態轉移部分記得把reset直接連到寄存器的reset上面(異步復位),自備時鍾(看測試電路可以知道需要自備時鍾,其實題目中也說了),最后在主電路里把各個模塊拼接起來,檢查一下模塊名字,appearance,就可以了。這個題的提問有問到如何進行單步調試(ctrl T調時鍾),如何查看單步調試的時候子電路的狀態(右鍵單擊某個子電路,點view xxxx),以及logisim自帶加法器對於有符號和無符號運算的區別(感覺最后一個問題好迷啊,我記得那個加法器不能選擇有符號無符號的,我就回答了Logisim自帶加法器默認為無符號運算……然后我人就沒了,助教讓我再看看。。。。后來我發現這好像和符號沒關系,比如1001+0111,結果是0000,理解成有符號的話,就是進位進沒了,理解為無符號,就是0111-0111=0000,跟符號沒關系,看來是我理論課太摸了)
第二題:大概的意思是通過理解下圖所示的邏輯左移的電路,去設計一個算數右移電路。
(方框中自己腦補DMX)
先講一下這個圖中的移位器怎么實現的。看第一組(最左邊兩個)spliter,那個錯開一位連接是容易理解的,移位嘛。由於是邏輯左移,所以最低位的數據會往高位處移動,以至於低位會沒有數據,沒有數據我們需要補上0。右邊三組spliter類似。通過觀察,我們發現這幾組分別錯開了1,2,4,8位,然后又注意到下面的4位選擇信號分別控制四組DMX的輸出,我們大概明白了,這個移位是用位的權重來看到底需要移多少位的。假設大家已經腦補了DMX,我們不妨用一組數據試試,比如選擇信號為1001,那么,最左邊和最右邊的DMX都是選擇的下路輸出,上路呢,根據DMX的特性,我們知道輸出是0.由於是從下路輸出的,所以這組數據通過第一組spliter發生了1位的位移,之后再和0做按位或運算(就是得到自己本身)。這樣就把1位移位傳給了下一組spliter。而下一個DMX選擇的是上路(因為1001,這一位是0),所以數據沒有被移位,就傳到了或門,和0進行按位或,得到本身,即相當於1001的第二位0使得未發生移位運算。第三組類似。第四組類似地,由於被選中了下路,所以數據進入spliter發生了8位位移,正好對應了1001最高位1,綜上,數據移動了9位(1001)。
明白了上面給出的移位原理,我們就容易搭建移位電路了,不再過多解釋。唯一需要解釋的一點是,算數右移,意味着我們不是補0,而是補符號位,即負數補1,正數補0。這樣的話,我們就不能給spliter接常數0了,而是應該接常數1邏輯與符號位,這樣我們就可以補符號位了。另外,我們不用把數據轉成補碼,直接做即可。雖然本題不讓用Logisim自帶的shifter,但是你可以先用那個東西試一試,看看算術移位是什么意思,然后再去搭建,就不會有那么多問題了。
如果沒看懂上面的講解,還有一個暴力打表法:搭建一個只能將這個8位數據移動一位的電路,然后在主電路里堆8個,把每一步移位的結果都接到一個8位的MUX上,用選擇信號直接選擇答案(打表法)。很暴力,但是,助教問答的時候涼了不怪我哦。
第三題:
考察浮點數相關的知識,理論課上有講過浮點數的表示,當時雖然聽課的時候沒有摸,也問了老師相關的問題,但是我對於這個題里面的補碼=expontent-01111 有點不太理解。這個題我場上沒做出來,加時也沒用。題面在宿舍里,回去之后再補上題面,並且說說自己的想法。希望大佬們會的能給我講講為啥這個補碼要這樣算(我記得和課上講的不太一樣,雖然我們可以無視這一點,直接拿這個公式去做)。