2011-11-06 144 views
1

我正在創建一個布爾邏輯模擬器。我發佈了一個關於應用程序的組織和一般設置的問題,它位於:Organizing Simple Boolean Logic Simulator - Java。我想這不適用於其他問題,因此可以單獨發佈。請原諒我的代碼,我對Java很陌生。布爾邏輯模擬器 - StackOverflowError

代碼的組織實際上很簡單,但當我嘗試在assign語句中爲自己分配變量時遇到了問題。

例如,我們通常使用的語句是這樣的:

assign input1 * input2 + test3 * input2 to test3; 

當輸入1和輸入2都很高,TEST3會變得很高。那時,input1可能會退出,test3仍然會很高,因爲它在聲明中引用了它自己。 (注意:* => AND,+ => OR)正如你在下面看到的,當我們在上面的賦值語句中引用一個變量時,我遇到了問題。這是因爲當我嘗試獲得語句的值以上我越來越:

輸入1 *輸入2 +(輸入1 *輸入2 +(輸入1 *輸入2 + TEST3 *輸入2)*輸入2)*輸入2

等它只是試圖一遍又一遍地評估它的聲明。

public interface Argument { 
    public boolean evaluate(); 
} 

以下是存儲每個位信息的「位」類。該位可以是「硬連線」真或假,也可以有一個語句分配給它。

public class Bit implements Argument { 

    private String name; 
    private boolean value; 
    private Argument assign; 
    private boolean assigned; 

    Bit(String name, boolean value) { 
     this.name = name; 
     this.value = value; 
    } 

    @Override 
    public boolean evaluate() { 
     if (assigned == true) { 
      return assign.evaluate(); 
     } else { 
      return value; 
     } 
    } 

    public void setValue(boolean value) { 
     this.value = value; 
    } 

    public void setAssign(Argument assign) { 
     this.assign = assign; 
     this.assigned = true; 
    } 

} 

這是Operation類的一個例子;其他人非常相似。

public class OrOperation implements Argument { 

    private Argument argument1, argument2; 

    public OrOperation(Argument arg1, Argument arg2) { 
     this.argument1 = arg1; 
     this.argument2 = arg2; 
    } 

    @Override 
    public boolean evaluate() { 
     return argument1.evaluate() || argument2.evaluate(); 
    } 

} 

解析器類:我只包括了這一部分,因爲實際分析是不是所有的相關性。 請注意,當我爲自己分配一個變量時,會產生錯誤。在下面的第二個測試中,我將test3分配給了test3。我可以推斷這是因爲test3試圖確定自己的價值,一遍又一遍地調用第二個語句。

public class Parser { 

    public HashMap<String, Bit> bits = new HashMap<String, Bit>(); 

    Parser(String file) { 

     bits.put("test1", new Bit("test1", true)); 
     bits.put("test2", new Bit("test2", true)); 
     bits.put("test3", new Bit("test3", false)); 
     bits.put("test4", new Bit("test4", true)); 

     // Works great 
     bits.get("test3").setAssign(parseStatement("test1 * ~test2 + test4 * test2")); 
     System.out.println(bits.get("test3").evaluate()); 

     // Produces error 
     bits.get("test3").setAssign(parseStatement("test1 * test2 + test3 * test2")); 
     System.out.println(bits.get("test3").evaluate()); 

    } 
} 

解析器基本建立像這樣的語句:(從以前的問題採取)

Operand op = new AndOperand(register1, new OrOperand(register2, register3); 
boolean output = op.evaluate(); // this is register1 && (register2 || register3) 

希望這是很清晰。讓我知道是否有問題是什麼問題或我想要做什麼。提前致謝。

回答

1

假設這是模擬器/評估器(而不是方程求解器),那麼您需要將系統建模爲隨時間變化的狀態。因此,語句:

assign test1 * input1 to test1; 

意味着TEST1的狀態噸+ 1被TEST1 * INPUT1

你的代碼是做測試1之間沒有區別和test1的噸+ 1 ...,結果導致無限遞歸。

一種解決方案是將公式與狀態(變量的值)分開表示,並且還使用不同的數據結構來表示時間t處的狀態和時間t + 1處的狀態。

+0

那我什麼時候更新't',什麼時候更新't + 1'? – RyanB

+0

在你的模擬中,時間t和t + 1 ......當然。 OTOH,如果這個邏輯模擬器沒有考慮時間(或者至少有一個「之前」和「之後」的狀態),那麼像'assign test1 * input1 to test1'這樣的東西就是不好的輸入。 –

1

你所描述的是電路中的反饋迴路。它們確實存在於實際中,在較低的水平上它們被用於例如對於存儲器單元(觸發器和鎖存器),在更高級別上,您可以將其用於具有需要確實反饋的操作的電路(例如IIR濾波器)。

在這個更高級別的「應用程序」中,您可以在不同(邏輯)操作之間進行註冊。 這就是你如何進入你的邏輯循環。然後你必須計算你的結果作爲時間的函數。

您從以重置值(通常爲0)循環的寄存器/輸入的內容開始。然後開始計算。您可以在中間的寄存器中斷開循環,並根據前一個循環的值的賦值語句計算循環的值。這也意味着即使輸入不改變,輸出也可以從時間步長變爲時間步長。對於每個輸出也不是單個輸出值,而是輸出序列(隨時間變化)。

另一種選擇(我建議你有一個簡單的模擬器)是禁止這樣的循環,並在你識別它們時拋出錯誤信息。

如果這是生產我只能推薦:到不是再發明輪子。這不是一個新問題。有例如硬件描述語言(例如Verilog或VHDL),其中存在一對模擬器(例如,來自synopsys的vcs或者如果你想要一個免費的vcs)。

+0

感謝您的輸入。這不是真的用於生產,我希望只是將它用作工作中的工具。我們將處理器用於特定的工業應用,並且一旦我將所有的東西都整理出來,我想要有一些特定的功能。現在,爲了將它翻譯成Java,我正在考慮在每個位上都有一個「where used」散列。這樣,當位狀態改變時,就可以重新評估「哪裏使用」位,以確定它們是否已經改變,等等。 – RyanB