代码之家  ›  专栏  ›  技术社区  ›  MahlerFive

如何在“NAND to Tetris”课程中为ALU设置输出标志?[关闭]

  •  17
  • MahlerFive  · 技术社区  · 17 年前

    虽然我给这个作业贴上了标签,但实际上这是一门我自己免费做的课程。不管怎样,这个课程叫做“从南德到俄罗斯方块”,我希望这里有人看过或参加了这个课程,这样我可以得到一些帮助。我正处于使用所提供的HDL语言构建ALU的阶段。我的问题是我的芯片不能正确编译。当我尝试为ALU设置输出标志时,会出错。我认为问题在于我不能为任何中间变量下标,因为当我只是根据某个随机变量(比如输入标志)将标志设置为“真”或“假”时,我不会得到错误。我知道问题不在于我尝试使用的芯片,因为我使用的是所有内置芯片。

    这是目前为止我的ALU芯片:

    /**
     * The ALU.  Computes a pre-defined set of functions out = f(x,y)
     * where x and y are two 16-bit inputs. The function f is selected 
     * by a set of 6 control bits denoted zx, nx, zy, ny, f, no.
     * The ALU operation can be described using the following pseudocode:
     *     if zx=1 set x = 0       // 16-bit zero constant
     *     if nx=1 set x = !x      // Bit-wise negation
     *     if zy=1 set y = 0       // 16-bit zero constant
     *     if ny=1 set y = !y      // Bit-wise negation
     *     if f=1  set out = x + y // Integer 2's complement addition
     *     else    set out = x & y // Bit-wise And
     *     if no=1 set out = !out  // Bit-wise negation
     *
     * In addition to computing out, the ALU computes two 1-bit outputs:
     *     if out=0 set zr = 1 else zr = 0 // 16-bit equality comparison
     *     if out<0 set ng = 1 else ng = 0 // 2's complement comparison
     */
    
    CHIP ALU {
    
    IN  // 16-bit inputs:
        x[16], y[16],
        // Control bits:
        zx, // Zero the x input
        nx, // Negate the x input
        zy, // Zero the y input
        ny, // Negate the y input
        f,  // Function code: 1 for add, 0 for and
        no; // Negate the out output
    
    OUT // 16-bit output
        out[16],
    
        // ALU output flags
        zr, // 1 if out=0, 0 otherwise
        ng; // 1 if out<0, 0 otherwise
    
    PARTS:
    // Zero the x input
    Mux16( a=x, b=false, sel=zx, out=x2 );
    
    // Zero the y input
    Mux16( a=y, b=false, sel=zy, out=y2 );
    
    // Negate the x input
    Not16( in=x, out=notx );
    Mux16( a=x, b=notx, sel=nx, out=x3 );
    
    // Negate the y input
    Not16( in=y, out=noty );
    Mux16( a=y, b=noty, sel=ny, out=y3 );
    
    // Perform f
    Add16( a=x3, b=y3, out=addout );
    And16( a=x3, b=y3, out=andout );
    Mux16( a=andout, b=addout, sel=f, out=preout );
    
    // Negate the output
    Not16( in=preout, out=notpreout );
    Mux16( a=preout, b=notpreout, sel=no, out=out );
    
    // zr flag
    Or8way( in=out[0..7], out=zr1 );   // PROBLEM SHOWS UP HERE
    Or8way( in=out[8..15], out=zr2 );
    Or( a=zr1, b=zr2, out=zr );
    
    // ng flag
    Not( in=out[15], out=ng );
    
    }
    

    因此,当我试图将订阅版本的“out”发送到OR8Way芯片时,问题就出现了。我尝试使用不同于“out”的变量,但有相同的问题。然后我读到你不能给中间变量下标。我想如果我把中间变量发送到另一个芯片上,而该芯片为它下标,它就可以解决这个问题,但它有相同的错误。不幸的是,我只是想不出一种方法来设置ZR和NG标志,而不订阅一些中间变量,所以我真的卡住了!

    正如您所知,如果我用以下内容替换有问题的行,它将编译(但不会给出正确的结果,因为我只是使用一些随机输入):

    // zr flag
    Not( in=zx, out=zr );
    
    // ng flag
    Not( in=zx, out=ng );
    

    有人有什么想法吗?

    编辑: 这里是 appendix of the book for the course 它指定了HDL的工作方式。具体来说,看看第5节中关于总线的内容,它说:“内部的插脚(如上面的V)可能不会被订阅。”

    编辑: 这是我得到的确切错误:“第68行,无法将栅极的输出引脚连接到部件”。不过,错误消息有点令人困惑,因为这似乎不是实际问题。如果我只是将“or8way(in=out[0..7],out=zr1);”替换为“or8way(in=false,out=zr1);”它将不会生成此错误,这正是导致我在附录中查找并发现out变量(因为它是作为中间变量派生的)无法订阅的原因。

    5 回复  |  直到 10 年前
        1
  •  21
  •   Martin Thompson    13 年前

    对于其他感兴趣的人,Emulator支持的解决方案是使用多个输出 类似:

    Mux16( a=preout, b=notpreout, sel=no, out=out,out=preout2,out[15]=ng);
    
        2
  •  5
  •   MahlerFive    17 年前

    按照pax的建议,解决方案是使用一个中间变量作为另一个芯片的输入,如or16way。以下是我修复问题并调试后的代码:

    CHIP ALU {
    
    IN  // 16-bit inputs:
        x[16], y[16],
        // Control bits:
        zx, // Zero the x input
        nx, // Negate the x input
        zy, // Zero the y input
        ny, // Negate the y input
        f,  // Function code: 1 for add, 0 for and
        no; // Negate the out output
    
    OUT // 16-bit output
        out[16],
    
        // ALU output flags
        zr, // 1 if out=0, 0 otherwise
        ng; // 1 if out<0, 0 otherwise
    
    PARTS:
    // Zero the x input
    Mux16( a=x, b=false, sel=zx, out=x2 );
    
    // Zero the y input
    Mux16( a=y, b=false, sel=zy, out=y2 );
    
    // Negate the x input
    Not16( in=x2, out=notx );
    Mux16( a=x2, b=notx, sel=nx, out=x3 );
    
    // Negate the y input
    Not16( in=y2, out=noty );
    Mux16( a=y2, b=noty, sel=ny, out=y3 );
    
    // Perform f
    Add16( a=x3, b=y3, out=addout );
    And16( a=x3, b=y3, out=andout );
    Mux16( a=andout, b=addout, sel=f, out=preout );
    
    // Negate the output
    Not16( in=preout, out=notpreout );
    Mux16( a=preout, b=notpreout, sel=no, out=preout2 );
    
    // zr flag
    Or16Way( in=preout2, out=notzr );
    Not( in=notzr, out=zr );
    
    // ng flag
    And16( a=preout2, b=true, out[15]=ng );
    
    // Get final output
    And16( a=preout2, b=preout2, out=out );
    }
    
        3
  •  5
  •   mudgen    16 年前

    我就是这样做的:

    CHIP ALU {
    IN  // 16-bit inputs:
        x[16], y[16],
        // Control bits:
        zx, // Zero the x input
        nx, // Negate the x input
        zy, // Zero the y input
        ny, // Negate the y input
        f,  // Function code: 1 for add, 0 for and
        no; // Negate the out output
    OUT // 16-bit output
        out[16],
        // ALU output flags
        zr, // 1 if out=0, 0 otherwise
        ng; // 1 if out<0, 0 otherwise
    PARTS:      
        Mux16(a=x, b=false, sel=zx, out=M16x);
        Not16(in=M16x, out=Nx);
        Mux16(a=M16x, b=Nx, sel=nx, out=M16M16x);
    
        Mux16(a=y, b=false, sel=zy, out=M16y);
        Not16(in=M16y, out=Ny);
        Mux16(a=M16y, b=Ny, sel=ny, out=M16M16y);
    
        And16(a=M16M16x, b=M16M16y, out=And16);
        Add16(a=M16M16x, b=M16M16y, out=Add16);
        Mux16(a=And16, b=Add16, sel=f, out=F16);
    
        Not16(in=F16, out=NF16);
        Mux16(a=F16, b=NF16, sel=no, out=out, out[15]=ng, out[0..7]=zout1, out[8..15]=zout2);
    
        Or8Way(in=zout1, out=zr1);
        Or8Way(in=zout2, out=zr2);
        Or(a=zr1, b=zr2, out=zr3);
        Not(in=zr3, out=zr);
    }
    
        4
  •  1
  •   paxdiablo    17 年前

    你试过了吗?

    // zr flag
    Or8way(
        in[0]=out[ 0], in[1]=out[ 1], in[2]=out[ 2], in[3]=out[ 3],
        in[4]=out[ 4], in[5]=out[ 5], in[6]=out[ 6], in[7]=out[ 7],
        out=zr1);
    Or8way(
        in[0]=out[ 8], in[1]=out[ 9], in[2]=out[10], in[3]=out[11],
        in[4]=out[12], in[5]=out[13], in[6]=out[14], in[7]=out[15],
        out=zr2);
    Or( a=zr1, b=zr2, out=zr );
    

    我不知道这样行不行,但看这份文件似乎很有意义 here .

    我也会三思而后行 out 作为一个变量名,因为试图找出它和关键字之间的区别会让人困惑 外面的 (如“ out=... “”。

    在编辑之后,如果您不能为中间值下标,那么您必须实现一个单独的“芯片”,例如 IsZero16 它将以16位值作为输入(您的中间 外面的 )返回一位,指示可以加载到的零度 zr . 或者你可以做一个 IsZero8 但是你必须称之为两个阶段,就像你现在所做的那样 Or8Way .

    这似乎是一个有效的解决方案,因为你 可以 将输入值下标到芯片。

    而且,仅仅看一下这个错误,这可能是一个不同于您建议的问题。短语“can't connect gate's output pin to part”(无法将栅极的输出引脚连接到部件)对我来说意味着无法将输出参数的信号连接回芯片处理区域。从电学的角度看,这是有道理的。

    您可能会发现必须将输出存储到一个临时变量中,并将其用于 外面的 (因为一旦信号被“发送”到芯片输出引脚,它们可能就不再可用)。

    我们可以尝试一下:

    CHIP SetFlags16 {
        IN  inpval[16];
        OUT zflag,nflag;
        PARTS:
            Or8way(in=inpval[0.. 7],out=zr0);
            Or8way(in=inpval[8..15],out=zr1);
            Or(a=zr0,b=zr1,out=zflag);
            Not(in=inpval[15],out=nflag);
    }
    

    然后,在您的ALU芯片中,最后使用这个:

    // Negate the output
    Not16( in=preout, out=notpreout );
    Mux16( a=preout, b=notpreout, sel=no, out=tempout );
    
    // flags
    SetFlags16(inpval=tempout,zflag=zr,nflag=ng);
    
    // Transfer tempout to out (may be a better way).
    Or16(a=tempout,b=tempout,out=out);
    
        5
  •  1
  •   Dinah SLaks    16 年前

    这还有一个带新芯片的,但感觉更干净

    /**
     * Negator16 - negates the input 16-bit value if the selection flag is lit
     */
    CHIP Negator16 {
      IN sel,in[16];
      OUT out[16];
    
      PARTS:
      Not16(in=in, out=negateIn);
      Mux16(a=in, b=negateIn, sel=sel, out=out);
    }
    
    CHIP ALU {
      // IN and OUT go here...
      PARTS:
      //Zero x and y if needed
      Mux16(a=x, b[0..15]=false, sel=zx, out=x1);
      Mux16(a=y, b[0..15]=false, sel=zy, out=y1);
    
      //Create x1 and y1 negations if needed
      Negator16(in=x1, sel=nx, out=x2);
      Negator16(in=y1, sel=ny, out=y2);
    
      //Create x&y and x+y
      And16(a=x2, b=y2, out=andXY);
      Add16(a=x2, b=y2, out=addXY);
    
      //Choose between And/Add according to selection
      Mux16(a=andXY, b=addXY, sel=f, out=res);
    
      // negate if needed and also set negative flag
      Negator16(in=res, sel=no, out=res1, out=out, out[15]=ng);
    
      // set zero flag (or all bits and negate)
      Or16Way(in=res1, out=nzr);
      Not(in=nzr, out=zr);
    }
    
    推荐文章