Swift中的16位逻辑/计算机仿真

问题描述 投票:0回答:1

我正在尝试使用Swift对16位计算机进行基本仿真。电脑将具有

  • ALU
  • 2个寄存器

就这些。我有足够的知识来直观地创建这些零件并理解它们的工作原理,但是在使用我目前的方法来制作具有更多输入的大型组件方面变得越来越困难。

我目前的方法是将每个组件包装在struct中。这很早就起作用了,但是在保持对计算机科学原理的忠诚度的同时,越来越难以管理多个输入。

主要问题是组件没有随时钟信号更新。当在输出变量get上调用c时,我具有组件更新的输出。但是,这忽略了时钟信号的概念,以后可能会引起其他问题。

同样,在不获取有关可变性的错误的情况下,很难为每个变量创建getter和setter。尽管我已经解决了这些错误,但是它们很烦人并且减慢了开发过程。

最后一个大问题是更新输出。输入更改时,输出不会更新;它会在被告知这样做时更新。这与实际计算机的质量不符,是一个基本错误。

这是一个例子。这是我前面提到的ALU。它需要两个16位输入并输出16位。它有两个一元ALU,可以将16位数字设为零,取反或取反。最后,它会根据f标志进行加法运算或根据比较结果进行比较,如果选择了no标志,则会将输出取反。

struct ALU {
    //Operations are done in the order listed. For example, if zx and nx are 1, it first makes input 1 zero and then inverts it.
    var x : [Int] //Input 1
    var y : [Int] //Input 2
    var zx : Int //Make input 1 zero
    var zy : Int //Make input 2 zero
    var nx : Int //Invert input 1
    var ny : Int //Invert input 2
    var f : Int //If 0, do a bitwise AND operation. If 1, add the inputs
    var no : Int //Invert the output
    public var c : [Int] { //Output
        get {
            //Numbers first go through unary ALUs. These can negate the input (and output the value), return 0, or return the inverse of 0. They then undergo the operation specified by f, either addition or a bitwise and operation, and are negated if n is 1.
            var ux = UnaryALU(z: zx, n: nx, x: x).c //Unary ALU. See comments for more
            var uy = UnaryALU(z: zy, n: ny, x: y).c 
            var fd = select16(s: f, d1: Add16(a: ux, b: uy).c, d0: and16(a: ux, b: uy).c).c //Adds a 16 bit number or does a bitwise and operation. For more on select16, see the line below.
            var out = select16(s: no, d1: not16(a: fd).c, d0: fd).c //Selects a number. If s is 1, it returns d1. If s is 0, it returns d0. d0 is the value returned by fd, while d1 is the inverse.
            return out
        }
    }
    public init(x:[Int],y:[Int],zx:Int,zy:Int,nx:Int,ny:Int,f:Int,no:Int) {
        self.x = x
        self.y = y
        self.zx = zx
        self.zy = zy
        self.nx = nx
        self.ny = ny
        self.f = f
        self.no = no
    }
}

我将c用于输出变量,将具有多个位的值存储在Int数组中,并且将单个位存储在Int值中。

我正在第六代iPad上的Swift Playgrounds 3.0和Swift 5.0上执行此操作。我将每个组件或一组组件存储在模块中的单独文件中,这就是为什么某些变量和所有structs被标记为public的原因。我将不胜感激任何帮助。提前致谢。

ios swift computer-science cpu-architecture swift-playground
1个回答
0
投票

因此,我已经完全重做,并找到了一种绕过我所面临问题的方法。我要做的是为每个输入创建所谓的“跟踪器变量”。当为每个变量调用get时,它将返回分配给它的跟踪器的值。调用set时,它将调用update()函数来更新电路的输出。它还会更新跟踪器的值。本质上,这将为每个变量创建一个“副本”。我这样做是为了防止任何无限循环。

不幸的是,这里需要跟踪器。我将说明原因

var variable : Type {
    get {
        return variable //Calls the getter again, resulting in an infinite loop
    }
    set {
        //Do something
    }
}

为了创建一个setter,Swift也需要创建一个getter。在此示例中,调用variable只是再次调用get,从而导致对get的调用永无休止。跟踪器变量是一种使用最少的额外代码的解决方法。

使用更新方法可确保输出响应任何输入的更改。由于组件本身的体系结构,这也适用于时钟信号。尽管它似乎起着时钟的作用,但事实并非如此。

例如,在数据触发器中,时钟信号传递到门。当时钟关闭时,所有时钟信号都将停用组件。因此,我可以在update()内实现该目标,同时忠实于现实。

这里是一个半加法器的例子。请注意,我提到的跟踪器变量在其名称前均带有下划线。它有两个输入xy,每个输入均为1位。它还有两个输出,highlow,也称为进位和求和。输出也是一位。

struct halfAdder {
    private var _x : Bool //Tracker for x
    public var x: Bool { //Input 1
        get {
            return _x //Return the tracker’s value
        }
        set {
            _x = x //Set the tracker to x
            update() //Update the output
        }
    }
    private var _y : Bool //Tracker for y
    public var y: Bool { //Input 2
        get {
            return _y
        }
        set {
            _y = y
            update()
        }
    }
    public var high : Bool //High output, or ‘carry’
    public var low : Bool //Low output, or ‘sum’
    internal mutating func update(){ //Updates the output
        high = x && y //AND gate, sets the high output
        low = (x || y) && !(x && y) //XOR gate, sets the low output
    }
    public init(x:Bool, y:Bool){ //Initializer
        self.high = false //This will change when the variables are set, ensuring a correct output. 
        self.low = false //See above
        self._x = x //Setting trackers and variables
        self._y = y
        self.x = x
        self.y = y
    }
}

这是一种非常干净的方法,除了跟踪器之外,请务必完成此任务。通过使用Bool数组而不是单个值,可以轻松地将其扩展为适合任意数量的位。它尊重时钟信号,在输入改变时更新输出,与真实计算机非常相似。

© www.soinside.com 2019 - 2024. All rights reserved.