虛擬化數電底層

虛擬化數電底層

目前已基本實現函數和結構體的面向對象化。node

對象:以數電模塊爲單位(應該)網絡

內部成員:線路,邏輯門,鏈接關係。以及虛擬化的輸入端(調試用)。框架

方法:函數

  1. 創建線路(Line_create)
  2. 創建邏輯門(Gate_create)
  3. 鏈接輸入端(Pin_attach)
  4. 鏈接元件(Attach)
  5. 模塊充電(Power_on)
  6. 模塊計算(CST)
  7. 改變輸入(Update)

 

一.基本操做:測試

  • 創建線路
    • 實現框架:
      typedef _line* line; 
      
      #define line_create(lptr) do { \
          _line_create(&lptr); \
      } while(0)
      
      main() {
          line l; 
          line_create(l); 

        (...) }

       

      其中:
      typedef struct _LINE {
      (...)
      } _line;
      #define MAXN 50000 _line _line__ALLOC_SPACE[MAXN]; _line* LAS_ptr = _line__ALLOC_SPACE; //initial is first address void _line_create(_line **ptr_addr) { //_line's pointer's address *ptr_addr = ++LAS_ptr;
      (...)
      }

       

      效果:申請從內存池中分配一個線路,將指針返回給封裝好的line類型。優化

  • 創建邏輯門
    • 實現框架:
      typedef _logic_gate* gate; 
      
      #define gate_create(gptr, value) do { \
          _logic_gate_create(&gptr, value); \
      } while(0)
      
      main() {
          gate g; 
          gate_create(g, n); 

        (...) }
      //n = 1: and gate n = 2: or gate n = 3: not gate

       其中:ui

      typedef struct _LOGIC_GATE {
          char gate; //and = 1  or = 2  not = 3
          
          (...)
          
      } _logic_gate; 
      
      
      _logic_gate _logic_gate__ALLOC_SPACE[MAXN]; 
      _logic_gate* LGAS_ptr = _logic_gate__ALLOC_SPACE; 
      
      void _logic_gate_create(_logic_gate **ptr_addr, char value) {
          *ptr_addr = ++LGAS_ptr; 
          (**ptr_addr).gate = value; 
          
          (...)
          
      }

      效果:申請從內存池中分配一個邏輯門,將指針返回給封裝好的gate類型。this

  • 鏈接輸入端
    • 原理:咱們把輸入端虛擬化,不展開一個對象,而是在line類型中標記,並惟一肯定這個line中的電平。
    • 實現框架:
      #define ATT_NULL 0
      #define PIN -1
      
      typedef struct _LINE {
          (...)
          BOOL level; //electric level
          char attach_name; //-1:pin   0:ATT_NULL   >0:logic_gate's name(1,2,3....)
          (...)
      } _line; 
      
      BOOL _pin_attach(_line *line_ptr, BOOL pin_value) {
          (...)
          (*line_ptr).attach_name = PIN; 
          (*line_ptr).level = pin_value; 
          (...)
      }
      
      #define pin_attach(lptr, value) do { \
          _pin_attach(lptr, value); \
      } while(0)
      
      main() {
          line l; 
          line_create(l); 
          
          pin_attach(l, BOOL_VALUE); 

        (...) }

      效果:l被標記成爲鏈接輸入端的線路,並被持續性地賦值爲BOOL_VALUE(TRUE或者FALSE)spa

  • 鏈接元件:
    • 鏈接線路和邏輯門:
      • 思路:因爲一條線路能夠鏈接多個邏輯門入口,可是一個邏輯門的出口只能鏈接一個線路,因此能夠把每一個線路鏈接的邏輯門入口保存爲一個靜態鏈表,而把邏輯門出口和線路簡單地一一對應起來。
      • 實現框架:
        #define attin(gptr, inptr) do { \
            _logic_gate_income_attach(gptr, inptr); \
        } while(0)
        
        #define attout(gptr, outptr) do { \
            _logic_gate_outcome_attach(gptr, outptr); \
        } while(0)
        
        main() {
            line l1, l2, l3; 
            gate g; 
        
            (...)
        
            attin(g, l1); 
            attin(g, l2); 
            attout(g, l3); 
        
            (...)
        }

         其中:3d

        typedef struct _LINE {
            (...)
            struct _LOGIC_GATE_LIST* list_head; 
            (...)
        } _line; 
        
        typedef struct _LOGIC_GATE {
            (...)
            struct _LINE *outcome_ptr; 
            (...)
        } _logic_gate;
        
        typedef struct _LOGIC_GATE_LIST {
            struct _LOGIC_GATE* gate_ptr; 
            struct _LOGIC_GATE_LIST* next; 
        } _logic_gate_list;  
        

        _logic_gate_list _logic_gate_list__ALLOC_SPACE[MAXN]; _logic_gate_list
        *LGLAS_ptr = _logic_gate_list__ALLOC_SPACE;
        BOOL _logic_gate_income_attach(_logic_gate
        *gate_ptr, _line *income_ptr) { LGLAS_ptr++; //allocate new node into the list table "line's logic_gates" (*LGLAS_ptr).gate_ptr = gate_ptr; (*LGLAS_ptr).next = (*income_ptr).list_head; (*income_ptr).list_head = LGLAS_ptr; (...) //income_ptr's list <- gate_ptr } BOOL _logic_gate_outcome_attach(_logic_gate *gate_ptr, _line *outcome_ptr) { (*gate_ptr).outcome_ptr = outcome_ptr; (...) }

         

    • 鏈接線路和線路:
      • 因爲線路連起來實質上是把一根線整合到另外一根線上面了,因此只需刪除整合過去的線路,並將它鏈接的全部邏輯門都轉移到被整合的線路上便可。此外由於咱們實現的內存池沒有回收功能,因此那個刪除的空間就浪費了。可是總體上提升了效率,利大於弊。
      • 實現框架:
        #define line_merge(lmge, lmged) do { \
            _line_merge(&lmge, &lmged); \
        } while(0)
        
        main() {
            l l1, l2; 
            
            (...)
            
            line_merge(l1, l2); 
            
            (...)
            
        }

        其中:

        typedef struct _LINE {
            (...)
            BOOL remove; //be removed or not?
            (...)
        } _line;
        
        
        void _line_free(_line **ptr_addr) {
            (**ptr_addr).remove = TRUE; //in this case, a space in LAS[] will be wasted, but it worthed
        }
        
        BOOL _line_merge(_line **lineA_ptr_addr, _line **lineB_ptr_addr) {
            //merge lineB's logic gates into lineA   P.S: maybe a gate will connect to a line twice.
            _logic_gate_list* list_ptr = (**lineB_ptr_addr).list_head; 
            while(list_ptr != GATE_NULL) {
                _logic_gate_income_attach((*list_ptr).gate_ptr, *lineA_ptr_addr); 
                list_ptr = (*list_ptr).next; //get next logic_gate
            }
            
            _line_free(lineB_ptr_addr); //delete
            (*lineB_ptr_addr) = (*lineA_ptr_addr); 
            
            (...)
        }

        注意:

        struct _LOGIC_GATE_LIST* GATE_NULL = (struct _LOGIC_GATE_LIST*)987654321; 
        
        void _line_create(_line **ptr_addr) { //_line's pointer's address
        
            (...)
            
            (**ptr_addr).list_head = GATE_NULL; //logic_gate_list' head points to GATE_NULL
            
            (...)
        }

        從而這樣就能夠實現靜態鏈表結構。

  • 模塊充電:
    • 假設咱們已經創建好了一個模塊,其中有完整的線路,邏輯門,鏈接關係,以及虛擬化的輸入端。那麼一開始模塊沒有初始化的時候,全部的值都是缺省的。如今咱們要作的就是把模塊初始化,完成在當前輸入端下的模塊狀態,從而能夠實現進一步的計算。
    • 具體操做上,考慮一下物理條件下的實際狀態。當邏輯門沒有供電的時候,不管輸入端是什麼,輸出端都不會有電。當模塊開機,邏輯門同時開始供電,因爲全部邏輯門同時開始計算,此時模塊內部可能會產生很雜亂的數電信號,這種信號沒有意義,咱們依然將其看做是缺省的。那麼咱們把能夠肯定的穩定的信號做爲有意義的信息進行計算,最初的信息確定是從輸入端開始的,由於在必定時期中輸入端是恆定不變的。
    • 因而咱們就從輸入端開始進行廣搜,把全部計算出來的新的線路加入下一輪隊列中,那麼加入過隊列的值由穩定的信號轉移過來,就也能夠當作穩定的。(這種狀況存在一個反例,就是模塊中存在環狀電路,就有可能產生高頻脈衝,沒法得出穩定的信號值。然而咱們不予以考慮。)廣搜足夠多的的次數之後,中止廣搜。此時模塊能夠當作初始化完畢。
  • 模塊計算:

    • 數電模塊本質上是一個有限狀態機,在物理上全部元件在同一時間並行計算,爲了模擬物理的並行結構,能夠用相似於上面廣搜的辦法,每一次將模塊中全部與線路和邏輯門按照規則計算,實現狀態轉移。也就是在當前時刻內,掃描全部邏輯門,由邏輯門的入口線路,更新出口線路。
    • 優化:有的邏輯門顯然不用轉移。能夠貪心地發現若是當前邏輯門兩個入口線路的值在上一個時刻點都沒有轉移過,那麼這個邏輯門也就不用計算了,由於結果顯然也不會變。因此就不用更新出口線路,讓出口線路的值繼續掛着。
    • 進而能夠實現相似上面廣搜的模式:存儲上一個時刻點全部更新過的線路,進而計算全部相關的邏輯門。若是邏輯門出口線路的值更新了,則把這個線路存入下一輪廣搜隊列。
    • 模塊計算和模塊充電的核心代碼相似:
      void CST() { //Circut_state_transition
          _line now_line; 
          _logic_gate now_gate; 
          _logic_gate_list* list_ptr; 
          
          //enumerate all the lines and logic_gates
          while(!LPS.empty()) {
              now_line = LPS.pop() //last period's lines
              list_ptr = now_line.list_head; 
              while(list_ptr != GATE_NULL) {
                  now_gate = *(*list_ptr).gate_ptr; //get now_gate's informations
                  (...)
                  LGPS.push(now_gate) //add this logic_gate into logic_gate stack
                  (...)
                  list_ptr = (*list_ptr).next; //get next logic_gate
              }
          }
          
          
          (...) //calcaulate logic_gates in logic_gate stack, answers stored in logic_gate_outcome_update_level
      
      
          //update LPS[]:
          LPS_clear(); 
          while(!LGPS.empty()) {
              now_gate = LGPS.pop(); 
              (...)
              if((*now_gate.outcome_ptr).level != _logic_gate_outcome_update_level) {
                  (*(now_gate.outcome_ptr)).level = _logic_gate_outcome_update_level;  
                  LPS_push(now_gate.outcome_ptr); 
              }
              (...)
          }
      }

       

  • 改變輸入:
    • 實際上這一步甚至虛擬化輸入端都是多餘的,調試的意義大於實際意義。真正開發中輸入端會用線路鏈接起來,而不是虛擬一個輸入端。那麼在調試的時候咱們可能要在模塊充電完畢後,模擬各類輸入端的值。考慮實際操做中若是輸入端是做爲」線路「而存在的,那麼每一次更新輸入端,都會在CST中加入隊列,進行計算。因此咱們就人工地實現廣搜過程當中加入隊列的操做:
      inline void pin_update(line lpin, BOOL value) { //still pin, no need to change name's value
          if(value != (*lpin).level) {
              (*lpin).level = value; 
              LPS_push(lpin); //in many situation, this operation will wake-up this circut.
          }
      }

       

二.進階操做:

  我在VM_basis++.h中封裝了一些經常使用函數,這裏列出函數的聲明以及用法:

#define and_create(gptr, inptr1, inptr2, outptr) do { \
    (...) \
} while(0) 
#define or_create(gptr, inptr1, inptr2, outptr) do { \
    (...) \
} while(0) 
#define not_create(gptr, inptr, outptr) do { \
    (...) \
} while(0) 
#define line_array_create(array) do { \
    (...) \
} while(0)
void pins_attach(int argn, ...) {
    (...)
}

main() {
    line L[12]; 
    gate og, ag, ng; 
    
    line_array_create(L); 
    /******************************************************
    for(int i = 1; i < sizeof(L)/sizeof(line); i++)
        line_create(L[i]);     
    ******************************************************/
    
    and_create(ag, L[1], L[3], L[5]); 
    /******************************************************
    gate_create(ag, 1); 
    attin(ag, L[1]); 
    attin(ag, L[3]); 
    attout(ag, L[5]);     
    ******************************************************/
    
    or_create(og, L[2], L[4], L[6]); 
    not_create(ng, L[7], L[8]); 
    
    pins_attach(3,   L[9], FALSE,   L[10], FALSE,   L[11], TRUE); 
    /******************************************************
    pin_attach(L[9], FALSE); 
    pin_attach(L[10], FALSE); 
    pin_attach(L[11], TRUE); 
    ******************************************************/

    (...)
 
}

 

 

三.禁忌&注意事項:

  爲了提升程序魯棒性,我在VM_basis++.h中加了一些防爆措施:

  • 一個線路有且只能鏈接到一個元件上(包括邏輯門,線路,輸入端)。
  • 邏輯門入口數限制:非門爲1,與門或門爲2;出口數限制:都爲1。不容許接入數超出限制。      

  若是檢測到有以上錯誤,程序會報錯,並指出錯誤類型。

 

  另外還有以下一些不建議使用的方法:

  • 與門或門只接入一根線路。(這種狀況下會變成一根帶延遲的導線,或者中繼器)
  • 邏輯門沒有出口。

  若是檢測到有以上操做,程序會警告,並指出不建議的類型。

 

  另外還存在這樣的一些錯誤,程序能夠運行,可是電路可能紊亂。例如:存在環形脈衝電路。這須要開發者本身意識到這些錯誤。

 

  此外VM_basis++.h中還提供了開發者選項:

/*******  developer options  *******/
#define CANCEL_SUCCESS() SHOW_SUCCESS = FALSE
void SHOW_CIRCUT() {
    printf("===============   SHOW CIRCUT   ===============\n"); 
    _line* _line_iterator = _line__ALLOC_SPACE+1; 
    _logic_gate* _gate_iterator = _logic_gate__ALLOC_SPACE+1; 
    while(_line_iterator <= LAS_ptr) {
        if((*_line_iterator).remove == FALSE)
            printf("Line:    Name:%d    Level:%d\n", (*_line_iterator).name, (*_line_iterator).level); 
        _line_iterator++; 
    }
    printf("===============================================\n\n"); 
}

 

 

能夠在外部調用CANCEL_SUCCESS()函數來取消創建成功提示。

經過SHOW_CIRCUT()函數,能夠打印出當前全部線路的值。(其中Name爲線路在內存池的下標,或者能夠理解爲物理層面上真正的線路編號)

 

四.   具體代碼:(按理說頭文件不該該定義變量。固然也無所謂)

VM_basis.h:

#include <stdio.h>
typedef char BOOL; 
#define TRUE 1
#define FALSE 0
#define PIN -1
#define ATT_NULL 0

struct _LINE; 
struct _LOGIC_GATE; 
struct _LOGIC_GATE_LIST; 

typedef struct _LINE {
    BOOL level; //electric level
    BOOL remove; //be removed or not?
    struct _LOGIC_GATE_LIST* list_head; 
    int name; //convenience && acculation
    char attach_name; //-1:pin   0:ATT_NULL   >0:logic_gate's name(1,2,3....)
} _line; 
typedef struct _LOGIC_GATE {
    char gate; //and or not
    struct _LINE *incomeA_ptr, *incomeB_ptr, *outcome_ptr; //only allow 2 income argvs
    int name; 
} _logic_gate; 
typedef struct _LOGIC_GATE_LIST {
    struct _LOGIC_GATE* gate_ptr; 
    struct _LOGIC_GATE_LIST* next; 
} _logic_gate_list; 
struct _LINE* LINE_NULL = (struct _LINE*)123456789; 
struct _LOGIC_GATE_LIST* GATE_NULL = (struct _LOGIC_GATE_LIST*)987654321; 



/*******  circut fundamental structures  *******/
#define MAXN 50000 //numbers of lines and logic_gates
#define MAXM 50000 //numbers of interactions between lines and logic_gates
_line _line__ALLOC_SPACE[MAXN]; 
_line* LAS_ptr = _line__ALLOC_SPACE; 
_logic_gate _logic_gate__ALLOC_SPACE[MAXN]; 
_logic_gate* LGAS_ptr = _logic_gate__ALLOC_SPACE; 
_logic_gate_list _logic_gate_list__ALLOC_SPACE[MAXN]; 
_logic_gate_list *LGLAS_ptr = _logic_gate_list__ALLOC_SPACE; 

//change the units' framework structure 
void _line_create(_line **ptr_addr) { //_line's pointer's address
    (*ptr_addr) = ++LAS_ptr; 
    (**ptr_addr).level = FALSE; 
    (**ptr_addr).remove = FALSE; 
    (**ptr_addr).name = LAS_ptr-_line__ALLOC_SPACE; //pointer's sub = (addr's D-value)/sizeof(var)
    (**ptr_addr).attach_name = ATT_NULL; 
    (**ptr_addr).list_head = GATE_NULL; //logic_gate_list' head points to GATE_NULL
}
void _line_free(_line **ptr_addr) {
    (**ptr_addr).remove = TRUE; //in this case, a space in LAS[] will be wasted, but it worthed
}
void _logic_gate_create(_logic_gate **ptr_addr, char value) {
    (*ptr_addr) = ++LGAS_ptr; 
    (**ptr_addr).gate = value; 
    (**ptr_addr).name = LGAS_ptr-_logic_gate__ALLOC_SPACE; 
    (**ptr_addr).incomeA_ptr = (**ptr_addr).incomeB_ptr = (**ptr_addr).outcome_ptr = LINE_NULL; 
}

//change the units' interaction structure
BOOL _logic_gate_income_attach(_logic_gate *gate_ptr, _line *income_ptr) {
    //Rule:Only allow 2 incomes when gate is or/and gate; Only allow 1 income when gate is not gate.
    if((*gate_ptr).incomeB_ptr != LINE_NULL || 
    ((*gate_ptr).incomeA_ptr != LINE_NULL) && (*gate_ptr).gate == 3) return FALSE; //attach fail
    
    LGLAS_ptr++; //allocate new node into the list table "line's logic_gates"
    (*LGLAS_ptr).gate_ptr = gate_ptr; 
    (*LGLAS_ptr).next = (*income_ptr).list_head; 
    (*income_ptr).list_head = LGLAS_ptr; 
    if((*gate_ptr).incomeA_ptr == LINE_NULL)
        (*gate_ptr).incomeA_ptr = income_ptr; 
    else (*gate_ptr).incomeB_ptr = income_ptr; 
    return TRUE; //attach success
}
BOOL _logic_gate_outcome_attach(_logic_gate *gate_ptr, _line *outcome_ptr) {
    if((*outcome_ptr).attach_name != ATT_NULL) return FALSE; //line have been attached, attach fail
    (*outcome_ptr).attach_name = (*gate_ptr).name; 
    (*gate_ptr).outcome_ptr = outcome_ptr; 
    return TRUE; 
}
BOOL _pin_attach(_line *line_ptr, BOOL pin_value) {
    if((*line_ptr).attach_name != ATT_NULL) return FALSE; 
    (*line_ptr).attach_name = PIN; 
    (*line_ptr).level = pin_value; 
    return TRUE; 
}

//merge lines, lineA <- lineB, including all the logic gates in B
BOOL _line_merge(_line **lineA_ptr_addr, _line **lineB_ptr_addr) {
    if((**lineB_ptr_addr).attach_name != ATT_NULL) return FALSE;
    
    //merge lineB's logic gates into lineA   P.S: maybe a gate will connect to a line twice.
    _logic_gate_list* list_ptr = (**lineB_ptr_addr).list_head; 
    while(list_ptr != GATE_NULL) {
        _logic_gate_income_attach((*list_ptr).gate_ptr, *lineA_ptr_addr); 
        list_ptr = (*list_ptr).next; //get next logic_gate
    }
    
    _line_free(lineB_ptr_addr); //delete
    (*lineB_ptr_addr) = (*lineA_ptr_addr); 
    //in fact, pysically _lineA and _lineB are the same _line, so there's no need to update attached
    return TRUE; 
}


/*******  units' states && circut transition  *******/
BOOL ACCULATE_OPTIMIZATION_FLAG;  
_line* _line_ptr_stack[MAXN]; //store ptr, acculate copy operations (equels to store names)
_logic_gate* _logic_gate_ptr_stack[MAXN]; //LPS -> LGPS -> next LPS -> ...
BOOL _logic_gate_outcome_update_level[MAXN]; 
int LPS_top, LGPS_top; 
BOOL _logic_gate_vis[MAXN]; 
//package _line_ptr_stack && line's value operation
#define LPS_push(lptr) _line_ptr_stack[LPS_top++] = lptr
#define LPS_clear() LPS_top = 0
void CST() { //Circut_state_transition
    _line now_line; 
    _logic_gate now_gate; 
    _logic_gate_list* list_ptr; 
    
    //enumerate all the lines and logic_gates
    while(LPS_top) {
        now_line = *(_line_ptr_stack[--LPS_top]); 
        list_ptr = now_line.list_head; 
        while(list_ptr != GATE_NULL) {
            now_gate = (*(*list_ptr).gate_ptr); //get now_gate's informations
            if(_logic_gate_vis[now_gate.name] == 0) { //LGV[X] == 0: havn't been visited
                _logic_gate_ptr_stack[LGPS_top++] = (*list_ptr).gate_ptr; //entry ptr
                _logic_gate_vis[now_gate.name] = TRUE; //mark, in case of gates repeat entry
            }
            list_ptr = (*list_ptr).next; //get next logic_gate
        }
    }
    
    //calcaulate logic_gates
    int i; 
    for(i = 0; i <= LGPS_top-1; i++) {
        now_gate = *(_logic_gate_ptr_stack[i]); 
        
        if(now_gate.outcome_ptr == LINE_NULL) continue; //Warning: no output. no need to calculate
        if(now_gate.incomeB_ptr == LINE_NULL && now_gate.gate != 3) { //Warning: default input
            _logic_gate_outcome_update_level[i] = (*(now_gate.incomeA_ptr)).level; 
            continue; 
        }
        
        if(now_gate.gate == 1) {
            if((*(now_gate.incomeA_ptr)).level == TRUE && ((*now_gate.incomeB_ptr).level) == TRUE)
                _logic_gate_outcome_update_level[i] = TRUE; 
            else _logic_gate_outcome_update_level[i] = FALSE; 
        }
        if(now_gate.gate == 2) {
            if((*(now_gate.incomeA_ptr)).level == FALSE && (*(now_gate.incomeB_ptr)).level == FALSE)
                _logic_gate_outcome_update_level[i] = FALSE; 
            else _logic_gate_outcome_update_level[i] = TRUE; 
        }
        if(now_gate.gate == 3) {
            if((*(now_gate.incomeA_ptr)).level == TRUE)
                _logic_gate_outcome_update_level[i] = FALSE; 
            else _logic_gate_outcome_update_level[i] = TRUE; 
        }
    }
    
    //update LPS[]:
    LPS_clear(); 
    while(LGPS_top) {
        now_gate = *(_logic_gate_ptr_stack[--LGPS_top]); 
        if(now_gate.outcome_ptr == LINE_NULL) continue; //Warning: no output. 
        if(ACCULATE_OPTIMIZATION_FLAG == FALSE || 
            (*now_gate.outcome_ptr).level != _logic_gate_outcome_update_level[LGPS_top])
                    LPS_push(now_gate.outcome_ptr); 
        
        (*(now_gate.outcome_ptr)).level = _logic_gate_outcome_update_level[LGPS_top]; 
        _logic_gate_vis[now_gate.name] = FALSE; //reset vis[]
    }
}

 

VM_basis++.h:

#include "VM_basis.h"
#include <stdlib.h>
#include <stdarg.h>
#include <conio.h>

/*******  package objects and functions  *******/
int ERROR_cnt, WARNING_cnt; 
//package _line & _logic_gate
BOOL SHOW_SUCCESS = TRUE; 
typedef _line* line; 
typedef _logic_gate* gate; 
char chs[10][10] = {"", "Or", "And", "Not", "(TRUE)", "(FALSE)"}; 
#define line_create(lptr) do { \
    _line_create(&lptr); \
    if(SHOW_SUCCESS == TRUE) printf("Create Line \""#lptr"\"(Name: %d): Succeed\n", (*lptr).name); \
} while(0)
#define gate_create(gptr, value) do { \
    _logic_gate_create(&gptr, value); \
    if(SHOW_SUCCESS == TRUE) printf("Create %s Gate \""#gptr"\"(Name: %d): Succeed\n", chs[value], (*gptr).name); \
} while(0)
#define attin(gptr, inptr) do { \
    if(_logic_gate_income_attach(gptr, inptr) == FALSE) { \
        printf(">>>ERROR: Line \""#inptr"\" cannot attach to \""#gptr"\"'s input:"); \
        printf("    \""#gptr"\"'s input ports is full...\n"); \
        ERROR_cnt++; \
    } \
    else if(SHOW_SUCCESS == TRUE) \
        printf("Attach Line \""#inptr"\" to \""#gptr"\"'s input: Succeed\n"); \
} while(0)
#define attout(gptr, outptr) do { \
    if(_logic_gate_outcome_attach(gptr, outptr) == FALSE) { \
        printf(">>>ERROR: Line \""#outptr"\" cannot attach to \""#gptr"\"s output:"); \
        printf("    \""#outptr"\"have been attached to another unit...\n"); \
        ERROR_cnt++; \
    }\
    else if(SHOW_SUCCESS == TRUE) \
        printf("Attach Line \""#outptr"\" to \""#gptr"\"'s output: Succeed\n"); \
} while(0)
#define line_merge(lmge, lmged) do { \
    if(_line_merge(&lmge, &lmged) == FALSE) { \
        printf(">>>ERROR: Line \""#lmged"\" cannot attach to \""#lmge"\":"); \
        printf("    \""#lmged"\"have been attached to another unit...\n"); \
        ERROR_cnt++; \
    }\
    else if(SHOW_SUCCESS == TRUE) \
        printf("Attach Line \""#lmged"\" to \""#lmge"\": Succeed\n"); \
} while(0)
#define pin_attach(lptr, value) do { \
    if(_pin_attach(lptr, value) == FALSE) { \
        printf(">>>ERROR: Line \""#lptr"\" cannot attach to pin%s", chs[4]); \
        printf(":    \""#lptr"\" have been attached to another unit...\n"); \
        ERROR_cnt++; \
    }\
    else if(SHOW_SUCCESS == TRUE) \
        printf("Attach Line \""#lptr"\" to pin%s: Succeed\n", chs[5]); \
} while(0)

//package gate operation
#define and_create(gptr, inptr1, inptr2, outptr) do { \
    gate_create(gptr, 1); \
    attin(gptr, inptr1); \
    attin(gptr, inptr2); \
    attout(gptr, outptr); \
} while(0) 
#define or_create(gptr, inptr1, inptr2, outptr) do { \
    gate_create(gptr, 2); \
    attin(gptr, inptr1); \
    attin(gptr, inptr2); \
    attout(gptr, outptr); \
} while(0) 
#define not_create(gptr, inptr, outptr) do { \
    gate_create(gptr, 3); \
    attin(gptr, inptr); \
    attout(gptr, outptr); \
} while(0) 
//Build lines in a quick way
#define line_array_create(array) do { \
    BOOL flag_reg = SHOW_SUCCESS; \
    SHOW_SUCCESS = FALSE; \
    int i, siz = sizeof(array)/sizeof(line); \
    for(i = 1; i < siz; i++) { \
        line_create(array[i]); \
        if(flag_reg == TRUE) \
            printf("Create Line \""#array"[%d]\"(Name: %d): Succeed\n", i, (*array[i]).name); \
    } \
    SHOW_SUCCESS = flag_reg; \
} while(0)
void pins_attach(int argn, ...) {
    va_list(pointer); 
    va_start(pointer, argn); 
    line line_buf; 
    BOOL value_buf; 
    int i; 
    BOOL flag_reg = SHOW_SUCCESS; 
    SHOW_SUCCESS = FALSE; 
    for(i = 1; i <= argn; i++) {
        line_buf = va_arg(pointer, line); 
        value_buf = va_arg(pointer, int); 
        pin_attach(line_buf, value_buf); 
        if(flag_reg == TRUE) 
            printf("Attach Line(name:%d) to pin%s: Succeed\n", (*line_buf).name, chs[5-value_buf]); 
    }
    va_end(pointer); 
    SHOW_SUCCESS = flag_reg; 
}


/*******  check && circut power on  *******/
#define POWER_ON_TIME 1000
void SHOW_CIRCUT(); 
void POWER_ON() { //check circut, init circut, insert pins into LPS[] for CST
    LPS_clear(); 
    _line* _line_iterator = _line__ALLOC_SPACE+1; //_line store from LAS[1].
    _logic_gate* _gate_iterator = _logic_gate__ALLOC_SPACE+1; 
    //check lines
    while(_line_iterator <= LAS_ptr) {
        if((*_line_iterator).remove == FALSE) {
            if((*_line_iterator).attach_name == ATT_NULL) {
                printf(">>>ERROR: Line(name:%d) didn't attached to any unit...\n", 
                    (*_line_iterator).name); 
                ERROR_cnt++; 
            }
            if((*_line_iterator).attach_name == PIN)
                LPS_push(_line_iterator); 
        }
        _line_iterator++; 
    }
    //check logic_gates
    while(_gate_iterator <= LGAS_ptr) {
        if((*_gate_iterator).outcome_ptr == LINE_NULL) {
            printf(">>>WARNING: Gate(name:%d) output default...\n", (*_gate_iterator).name); 
            WARNING_cnt++; 
        }
        
        int cnt = 0, should_be = 2; 
        if((*_gate_iterator).gate == 3) should_be = 1; 
        if((*_gate_iterator).incomeA_ptr != LINE_NULL) cnt++; 
        if((*_gate_iterator).incomeB_ptr != LINE_NULL) cnt++; 
        if(cnt < should_be) {
            printf(">>>WARNING: Gate(name:%d) input default(now %d, should be %d)...\n", 
                (*_gate_iterator).name, cnt, should_be); 
            WARNING_cnt++; 
        }
        _gate_iterator++; 
    }
    //tips UI
    printf("-----------------------------------------------"); 
    printf("\n\nInitializ finished. %d ERRORs, %d WARNINGs.\n\n", ERROR_cnt, WARNING_cnt); 
    if(ERROR_cnt != 0 || WARNING_cnt != 0) {
        printf(">>>Circut may not work properly. Power_on circut anyway?(Y/N)"); 
        char ans = getch(); 
        while(ans != 'y' && ans != 'Y' && ans != 'n' && ans != 'N') ans = getch(); 
        if(ans == 'n' || ans == 'N') exit(0); 
    }
    else printf("Circut Power_on...\n"); 
    
    /***POWER_ON: a long period of high-level current. To simulate this operate, we 
    cancel the acculate-optimization in CST, calculate every unit in the circut.***/
    /***WHY we need to POWER_ON? The reason is when the circut was built, all the 
    levels and values in it is originnaly default(FALSE), so we need to init. ***/
    ACCULATE_OPTIMIZATION_FLAG = FALSE; 
    int i; 
    for(i = 1; i <= POWER_ON_TIME; i++)
        CST(); 
    ACCULATE_OPTIMIZATION_FLAG = TRUE; 
}



/*******  (mannul) update circut input  *******/
inline void pin_update(line lpin, BOOL value) { //still pin, no need to change name's value
    if(value != (*lpin).level) {
        (*lpin).level = value; 
        LPS_push(lpin); //in many situation, this operation will wake-up this circut.
    }
}


/*******  developer options  *******/
#define CANCEL_SUCCESS() SHOW_SUCCESS = FALSE
void SHOW_CIRCUT() {
    printf("===============   SHOW CIRCUT   ===============\n"); 
    _line* _line_iterator = _line__ALLOC_SPACE+1; 
    _logic_gate* _gate_iterator = _logic_gate__ALLOC_SPACE+1; 
    while(_line_iterator <= LAS_ptr) {
        if((*_line_iterator).remove == FALSE)
            printf("Line:    Name:%d    Level:%d\n", (*_line_iterator).name, (*_line_iterator).level); 
        _line_iterator++; 
    }
    printf("===============================================\n\n"); 
}

 

順便再帶一個示例程序:

 要實現這樣一個電路(注:4號線鏈接在了2號線上面)

咱們打這樣一個程序:

#include "VM_basis++.h"
#define SHOW_SUCCESS_UI_FLAG 1
int main() {
    if(SHOW_SUCCESS_UI_FLAG != 1) CANCEL_SUCCESS(); 
    
    line L[9]; 
    gate A, B, C, D; 
    
    line_array_create(L); 
    pins_attach(3, L[1], FALSE, L[2], TRUE, L[3], FALSE); 
    line_merge(L[2], L[4]); 
    
    and_create(A, L[1], L[2], L[6]); 
    or_create(B, L[3], L[4], L[5]); 
    not_create(C, L[6], L[7]); 
    and_create(D, L[5], L[7], L[8]); 
    
    POWER_ON(); 
    
    SHOW_CIRCUT(); 
        
        return 0; 
}

 運行結果:

以後,咱們改變輸入端,造出三個測試數據:

相對應地咱們有了以下的代碼:

 做爲對應三組數據的三個輸入端電路。咱們把計算次數設爲4,也就是說對於每個輸入數據,咱們把廣搜四次的結果做爲最終結果。(能夠發現數電模塊做爲一個層次網絡的深度只有3,因此廣搜4次是顯然可行的)

三次結果以下:

結果徹底正確,測試樣例經過。

 

五.   下一層的實現目標:

  經過VM_basis++.h,咱們已經能夠比較方便地創建虛擬化的數電模塊,好比鎖存器,T觸發器等等模塊。

  下一步的任務是如何在創建完各自的模塊以後,將不一樣模塊的接口鏈接。以及時序控制系統是否能夠正常地控制各個模塊的計算。

相關文章
相關標籤/搜索