主頁 >  其他 > Scheme實作數字電路仿真(2)——原語

Scheme實作數字電路仿真(2)——原語

2020-09-20 21:31:01 其他

  著作權申明:本文為博主窗戶(Colin Cai)原創,歡迎轉帖,如要轉貼,必須注明原文網址

  http://www.cnblogs.com/Colin-Cai/p/12045295.html 

  作者:窗戶

  QQ/微信:6679072

  E-mail:[email protected]

  上一章給出了組合電路的仿真實作,這一章開始思考時序電路的仿真實作,但時序電路遠比組合電路復雜的多,我們先從組成電路的每個元件說起,在程式實作層次,我們可以考慮給每個基礎元件一個自定義描述方式,稱為原語,

 

  Verilog原語

 

  Verilog提供了元件原語建模的方式,說白了,就是用一個表格來體現所有情況下的輸出,Verilog的原語只允許有一個輸出,

  比如and門,用Verilog原語來描述如下

primitive myand(out,in1,in2);
output out;
input in1,in2;
table
// in1 in2    out
    0   ?   :  0;
    1   0   :  0;
    1   1   :  1;
endtable
endprimitive

    Verilog原語中不能使用高阻(因為除了三態門產生高阻輸出之外,這的確與真實電路不符,而Verilog并無VHDL那般抽象),不能表示三態門,

   對于時序電路,Verilog也一樣可以支持,所謂時序電路,意味著電路的輸出不僅僅與當前電路的輸入有關,還與電路之前的狀態有關,所謂電路之前的狀態也就是電路之前的輸出,

  我們來考慮這樣一個時序元件,稱之為D鎖存器,有兩個輸入en和in,一個輸出out,當en為0時,out和in保持一致;當en為1時,out保持不變,這稱之為電平觸發,用波形圖可以描述其特性:

  D鎖存器波形

  用verilog描述可以如下:

module dlatch(out, en, in);
output out;
input en, in;
reg out;
always@(in)
if(!en)
  out <= in;
endmodule

  電平觸發的D鎖存器可以用原語描述如下:

primitive dlatch(out, en, in);
output out;
input en, in;
reg out;
table
//en in : out : next out
   0   0 :  ?   :  0;
   0   1 :  ?   :  1;
   1   ? :  ?   :  -;
endtable
endprimitive

  狀態表的最后一行next out位置的 - 符號代表狀態保持,

  再來一個我們數字設計時最常用的元件D觸發器,它有兩個輸入信號clk和in,有一個輸出信號out,當clk從0變到1的瞬間(稱之為上升沿),out被賦予in的值,其他時候out保持不變,這種觸發稱之為沿觸發,波形圖可以用以下描述其特性:

  D觸發器波形

  用Verilog描述如下:

module dff(out, clk, in);
output out;
input clk, in;
reg out;
always@(posedge clk)
  out <= in;
endmodule

  而用Verilog原語描述則如下:

primitive dff(out, clk, in);
output out;
input clk, in;
reg out;
table
// clk  in : out : next out 
  (01) 0  :  ?   : 0;
  (01) 1  :  ?   : 1;
endtable
endprimitive

  原語沒有寫的部分都是保持,換句話說,之前D鎖存器的原語實作table的最后一行保持是可以不寫的,

  前面的D鎖存器是電平觸發,D觸發器是沿觸發,實際上原語也可以同時支持兩種觸發,比如存在異步復位的D觸發器,多了個觸發的rst信號,在rst為1的時候,out會被賦予0,波形圖如下:

  帶復位D觸發器波形

  Verilog描述可以如下:

module dff(out, rst, clk, in);
output out;
input rst, clk, in;
reg out;
always@(posedge rst or posedge clk)
if(rst)
  out <= 1'b0;
else
  out <= in;
endmodule

  用原語描述則為:

primitive dff(out, rst, clk, in);
output out;
input rst, clk, in;
reg out;
table
// rst clk  in : out : next out 
     0 (01) 0  :  ?   : 0;
     0 (01) 1  :  ?   : 1;
     1  ?   ?  :  ?   : 0;
endtable
endprimitive

  以上的原語中就同時包含電平觸發和沿觸發,

 

  Scheme建模下的原語

 

  Verilog原語用表來表示,實際上是用表來代表一個函式關系,于是我們要做的,是試著用一個函式來代表基本元件的原語描述,

  比如與門,我們是不是可以用以下函式來描述:

(define (myand in1 in2)
  (if (and (= in1 1) (= in2 1)) 1 0))

  上述函式方便的表示一個組合邏輯,甚至上述可以延伸到表示任意多輸入的一個與門,描述如下

(define (myand . in)
    (if (member 0 in) 0 1))

 

  可是上述的描述并未方便的引入時序的概念,最終在仿真的時候無法區分組合邏輯和時序邏輯,從而上述的函式來代表原語描述是失敗的,需要再修改一下,

  于是我們描述函式的引數串列里不僅有當前各輸入信號,還得有當前輸出信號,考慮到沿觸發器件,還得加入沿的資訊,于是我們可以定義原語是這樣的一個函式:帶有三個引數,第一個引數是輸入信號值的串列,第二個引數是當前輸出信號值,第三個引數代表沿觸發的信號,簡單起見,就用沿觸發的信號在輸入信號串列中的序號來表示,如果不是沿觸發則此處傳入-1;函式回傳即將輸出的信號值,

  那么我們的任意多輸入的與門,描述如下

(define (myand input current-output edge-)
    (if (member 0 input) 0 1))

  那么D鎖存器的原語描述如下

(define (dlatch input current-output edge)
 (let ((en (car input)) (in (cadr input)))
  (if (= en 1) current-output
   in)))

  上面的let顯示了輸入串列是[en, in];

  D觸發器的原語描述如下,輸入串列為[clk, in]

(define (dff
 (let ((clk (car input)) (in (cadr input)))
  (if (and (= edge 0) (= clk 1)) in
   current-output)))

  對于之前帶異步復位的D觸發器,作為一個既有電平觸發又有沿觸發的例子

(define (dff-with-rst input current-output edge)
 (let ((rst (car input))(clk (cadr input)) (in (caddr input)))
  (cond
   ((= rst 1) 0)
   ((and (= edge 0) (= clk 1)) in)
   (else current-output))))

 

  進一步修改原語

 

  之前的設計已經完備,但未必方便,比如可能一些邏輯可編程器件的編程粒度不會細到門級,Verilog的原語里,只有一個輸出,我們可以考慮這里原語的輸出可以有多個,

  在此我們考慮一位全加器,也就是三個單bit的數相加,得到兩位輸出的組合電路,輸出信號既然可能不止一個,原語函式的輸出當然是一個串列,第二個引數current-output當然也是串列,

(define (add input current-output edge)
 (let ((a (car input))(b (cadr input)) (c (caddr input)))
  (let* ((sum (+ a b c)) (cout (if (>= sum 2) 1 0)) (s (if (= cout 0) sum (- sum 2))))
   (list cout s))))

 

  最后,我們考慮,原語可以為每一個信號可以加一個位寬,

  在這里,我們來考慮做一個四位計數器,有一個異步復位(rst),有一個時鐘(clk),一個4位的輸出(out),每當clk上升沿,輸出都會加1,注意如果當前輸出如果是1111,下一個輸出將會是0000,描述如下

(define (counter input current-output edge)
 (define (add1-list lst)
  (cond
   ((null? lst) '())
   ((= (car lst) 0) (cons 1 (cdr lst)))
   (else (cons 0 (add1-list (cdr lst))))))
 (let ((rst (car input)) (clk (cadr input)))
  (cond
   ((= rst 1) '((0 0 0 0)))
   ((and (= edge 1) (= clk 1)) (list (add1-list (car current-output))))
   (else current-output))))

  用0/1的list有一些不方便的地方,我們可以用數來代替,也可以考慮數和list一起支持,那么我們在處理的時候可能需要判斷一下傳入的是數還是list,Scheme里提供了兩個函式來判斷,一個是list?用來判斷是不是list,一個是number?用來判斷是不是數,在上面定義的基礎上加上對于數的支持也很容易,

 

  迭代

 

  以上雖然用函式來定義了原語,但是從函式卻沒有定義任何表示原語信號介面的東西,不看原語定義無法知道原語怎么使用,并且在仿真的時候,上述原語本身并不提供各個信號當前的值,

  本來會在后面的章節提到解決方案,在此也給個方案,

  我們可以用閉包解決這個問題,閉包中包含著輸入、輸出信號的資訊,Scheme的閉包可以有多種方式,可以采用上一章中區域作用域變數的方法(這種方法并不是所有的語言都支持,比如Python則只能用class建立類了),另一種方式則是用不變數了,也就是純函式式編程方式,本章就來說說第二種方式,雖然在我之前的其他文章中說到的閉包主要是采取這種方式,

  我們先看一個簡單的例子,我們希望有這樣的需求:

  定義一個變數x

  (define x (make-sum 0))

  (set! x (x 1))

  (set! x (x 2))

  (set! x (x 3))

  (x)得到6

  這樣,每次x都是一個閉包,現在要看如何定義make-sum,

  我們先這樣定義:

(define (make-sum n)
 (lambda (m)
  (make-sum (+ n m))))

  但是,我們馬上發現,我們要求的值變的不可提取,閉包回傳的這個函式,不僅僅可以帶一個引數用來再度回傳閉包,還應該可以不帶引數,以支持上面(x)這樣的提取,

  上面的實作需要一點修改,需要判斷一下引數個數:

(define (make-sum n)
 (lambda s
  (if (null? s) n
   (make-sum (+ n (car s))))))

  測驗一下,OK了,最后得到了6,說明make-sum是可行的,

  

  然后,我們可以抽象加法這個符號,繼續做算子f-step,

(define (f-step step n)
 (lambda s
  (if (null? s) n
   (f-step step (step n (car s))))))

  這樣,make-sum可以由上述算子定義而得

(define make-sum
 (lambda (n) (f-step + n))

 

  定義f-step算子有什么好處呢?實際上,它是為迭代的每一步動作進行建模,

  于是我們可以用f-step為零件,構建所有的迭代,

  比如對于輾轉相除法(歐幾里得演算法)求最大公約數,描述如下

(define (gcd a b)
 (if (zero? b) a
  (gcd b (remainder a b))))

  如果要用f-step,則首先要把迭代的內容表示成一個物件,可以用cons對來對gcd的兩個引數a,b打包,

  f-step的第二個引數是一個函式,我們稱之為step,step函式有兩個引數,一個是用于迭代的資料,在這里就是這個cons對,而第二個引數可以看成是外界激勵,這里是不需要的,傳任意值即可,

  我們清楚輾轉相除法的這一步,應該描述如下

(define (step pair none)
 (cons (cdr pair) (remainder (car pair) (cdr pair))))

  反復的迭代,其終止條件是判斷pair的第二個成員是否為0,如果是0則回傳pair的第一個成員,否則繼續迭代

(define (continue-gcd-do f)
 (let ((x (f)))
  (if (zero? (cdr x)) (car x)
   (continue-gcd-do (f '())))))

  于是,我們的gcd就被重新設計了

(define (gcd a b)
 (continue-gcd-do (f-step step (cons a b))))

  雖然看起來的確比最開始的實作復雜了不少,但是可以實作統一的設計,以便更復雜的情況下的應用, 

 

  反柯里化

 

  f-step還可以用來設計fold-left算子,我們回憶一下fold-left

  (fold-left cons 'a '(b c d))

  得到

  '(((a . b) . c) . d)

  我們可以看成是一個迭代,

  最開始是'a

  然后通過函式cons和'b,得到

  '(a . b)

  然后再通過函式cons和'c,得到

  '((a . b) . c)

  最后再通過函式cons和'd,得到

  '(((a . b) . c) . d)

  顯然,我們可以使用f-step,定義以下

  (define func (f-step cons 'a))

  那么

  (((func 'b) 'c) 'd)

  則是最后的結果,

  但這樣似乎不太好用,假如我們有這么一個函式,暫且稱為F

  ((F func) 'b 'c 'd)

  也就是

  (apply (F func) '(b c d))

  那么就容易實作了,

  F這個程序正好和我之前的文章《map的實作和柯里化(Curring)》里的柯里化程序相反,稱之為反柯里化,重新給個合適的名字叫uncurry

(define (uncurry f)
 (lambda s
  (if (null? s) (f)
   (apply (uncurry (f (car s))) (cdr s)))))

  于是fold-left就可以如下實作

(define (my-fold-left f init lst)
 (apply (uncurry (f-step f init)) lst))

  

  封裝

 

  繞了一圈,似乎與主題有點遠了,一個原語所表示的電路,實際上也是隨著外界輸入,在不斷的變化輸出,也可以用f-step算子來模擬,

  電路的狀態包含了電路的輸出,同時也包含著電路的輸入,因為需要判斷沿變化,當然我們只需要關注沿觸發的信號就行了,其他輸入信號不需要在狀態里,

  我們就以之前的帶復位的D觸發器為例,我們重新給出它的原語描述,并按第三節里修改之后的來,

(define (dff-with-rst input current-output edge)
 (let ((rst (caar input))(clk (caadr input)) (in (caaddr input)))
  (cond
   ((= rst 1) '((0)))
   ((and (= edge 0) (= clk 1)) (list (list in)))
   (else current-output))))

  我們的初始狀態可以設定為

  '((z) . (z))

  之所以用z來表示,而不是0/1,在于初始的時候,我們認為都是一種渾沌的狀態,當然,也可以設為用0/1,這完全可以按仿真意愿來,

  前面第一個'(z)表示所有可以帶來沿觸發的信號串列,這里可以帶來沿觸發的是第二個信號clk,序號從0開始算為1,而輸出信號初始也先設定為'(z)

  于是狀態轉換函式則為

(define step
(lambda (stat input)
(cons (cadr input) (dff
-with-rst input (cdr stat) (if (eq? (caar stat) (caadr input)) -1 1)))))

  于是

  (f-step step '(() . ()))則是一個原語的實體封裝,里面包含著狀態,可以用來在仿真中反復迭代,

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

標籤:其他

上一篇:npm解決node-sass安裝失敗

下一篇:TCP/IP詳解,卷1:協議--RARP:逆地址決議協議

標籤雲
其他(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)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more