Swift中的16位逻辑/计算机仿真 [英] 16 bit logic/computer simulation in Swift

查看:64
本文介绍了Swift中的16位逻辑/计算机仿真的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I’m trying to make a basic simulation of a 16 bit computer with Swift. The computer will feature


  • ALU

  • 2个寄存器

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

That’s all. I have enough knowledge to create these parts visually and understand how they work, but it has become increasingly difficult to make larger components with more inputs while using my current approach.

我的当前的方法是将每个组件包装在 struct 中。这项工作很早就起作用了,但是在不遵循计算机科学原理的情况下管理多个输入变得越来越困难。

My current approach has been to wrap each component in a struct. This worked early on, but is becoming increasingly difficult to manage multiple inputs while staying true to the principles of computer science.

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

The primary issue is that the components aren’t updating with the clock signal. I have the output of the component updating when get is called on the output variable, c. This, however, neglects the idea of a clock signal and will likely cause further problems later on.

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

It’s also difficult to make getters and setters for each variable without getting errors about mutability. Although I have worked through these errors, they are annoying and slow down the development process.

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

The last big issue is updating the output. The output doesn’t update when the inputs change; it updates when told to do so. This isn’t accurate to the qualities of real computers and is a fundamental error.

这是一个示例。这是我前面提到的ALU。它需要两个16位输入并输出16位。它有两个一元ALU,可以将16位数字设为零,取反或取反。最后,它根据 f 标志进行添加或比较明智的比较,如果 no ,则将输出反转

This is an example. It is the ALU I mentioned earlier. It takes two 16 bit inputs and outputs 16 bits. It has two unary ALUs, which can make a 16 bit number zero, negate it, or both. Lastly, it either adds or does a bit wise and comparison based on the f flag and inverts the output if the no flag is selected.

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 用作输出变量,将具有多个位的值存储在<$中c $ c> Int 数组,并将单个位存储在 Int 值中。

I use c for the output variable, store values with multiple bits in Int arrays, and store single bits in Int values.

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

I’m doing this on Swift Playgrounds 3.0 with Swift 5.0 on a 6th generation iPad. I’m storing each component or set of components in a separate file in a module, which is why some variables and all structs are marked public. I would greatly appreciate any help. Thanks in advance.

推荐答案

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

So, I’ve completely redone my approach and have found a way to bypass the issues I was facing. What I’ve done is make what I call "tracker variables" for each input. When get is called for each variable, it returns that value of the tracker assigned to it. When set is called it calls an update() function that updates the output of the circuit. It also updates the value of the tracker. This essentially creates a ‘copy’ of each variable. I did this to prevent any infinite loops.

不幸的是,这里需要跟踪器。我将演示为什么

Trackers are unfortunately necessary here. I’ll demonstrate why

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

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

In order to make a setter, Swift requires a getter to be made as well. In this example, calling variable simply calls get again, resulting in a never-ending cascade of calls to get. Tracker variables are a workaround that use minimal extra code.

使用更新方法可确保输出响应任何输入的更改。由于组件本身的体系结构,这也适用于时钟信号。尽管它看起来像是时钟,但它不是。

Using an update method makes sure the output responds to a change in any input. This also works with a clock signal, due to the architecture of the components themselves. Although it appears to act as the clock, it does not.

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

For example, in data flip-flops, the clock signal is passed into gates. All a clock signal does is deactivate a component when the signal is off. So, I can implement that within update() while remaining faithful to reality.

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

Here’s an example of a half adder. Note that the tracker variables I mentioned are marked by an underscore in front of their name. It has two inputs, x and y, which are 1 bit each. It also has two outputs, high and low, also known as carry and sum. The outputs are also one bit.

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 的数组而不是单个值,可以轻松地将其扩展为适合任意数量的位。它尊重时钟信号,在输入改变时更新输出,与真实计算机非常相似。

This is a very clean way, save for the trackers, do accomplish this task. It can trivially be expanded to fit any number of bits by using arrays of Bool instead of a single value. It respects the clock signal, updates the output when the inputs change, and is very similar to real computers.

这篇关于Swift中的16位逻辑/计算机仿真的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆