数电课程模型机设计:多路开关、移位逻辑和控制信号产生逻辑(Verilog 实现)

以下代码虽经本人检查,但仅移位逻辑经过仔细验收,仅供参考

多路开关

多路开关做起来还是很简单的,一个 case 语句就能搞定。记得加 default,防止生成锁存器。

verilog
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
module mux (MADD,A,B,C,OUT);
    input[1:0] MADD;
    input[7:0] A,B,C;
    output[7:0] OUT;

    reg[7:0] OUT;

    always @(MADD,A,B,C) begin
        case (MADD) 
            2'b00: OUT=A;
            2'b01: OUT=B;
            2'b10: OUT=C;
            default: OUT=8'b0;
        endcase
    end
endmodule //mux

移位逻辑

这个应该也不算很难。我将输入的三个 FBUS、FLBUS 和 FRBUS 合成一个 BUS,这样用 case 语句一起处理或许优雅一些(?)

可以参考下面这张图进行设计。其他情况直接全输出高阻,不用管别的,以防多路输出冲突。

移位逻辑引脚关系

verilog
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
module Shift_Register (F_BUS,FL_BUS,FR_BUS,a,W,Cf);
    input F_BUS,FL_BUS,FR_BUS;
    input[7:0] a;
    output[7:0] W;
    output Cf;
    
    reg[7:0] W;
    reg Cf;

    wire[2:0] BUS;
    
    assign BUS = {F_BUS,FL_BUS,FR_BUS};
    
    always @(BUS) begin
        case (BUS)
            3'b100: begin
                W = a;
                Cf = 0;
            end
            3'b010: begin
                W  = {a[6:0],a[7]};
                Cf = a[7];
            end
            3'b001: begin
                W  = {a[0],a[7:1]};
                Cf = a[0];
            end
            default: begin
                W = 8'bZZZZZZZZ;
                Cf = 0;
            end
        endcase
    end
endmodule //Shift_Register

控制信号产生逻辑

正常来说,如果希望用直接 assign 这种比较优雅的写法,你需要逐个摸清控制命令的运行模式,即每种 IR 对应的各个控制信号的值,列个表,然后找每个控制信号在什么命令输入的时候值为 1。

要不然,就用一堆条件语句,只是省掉了反查的过程,还是得分析,也不优雅。

但是,老师把这个表已经列出来了,省下了大把的时间:

控制信号产生逻辑引脚关系

我们只需查找每一列输出信号对应的输入信号就行了。规定的信号针脚和表中的控制信号可能有所不同,可以参阅下面的源代码,我在注释中写了一些对应关系。

但是请注意,这里并没有包含所有的指令,比如 INPUT。

空白的区域不清楚怎么搞,但我是在这部分输出了 0。JZ/JC(T) 指的是 JZ&&Z 或 JC&&C,这两种输出是等效的,虽然判断条件看起来不同;相对的,JZ/JC(F) 就是 JZ&&(~Z) 或 JC&&(~C)。

源代码如下,部分难以使用几个输入或表示的,我才会使用 always 语句。

后面整合的时候会知道,MOVB 和 MOVC 的时候,要指定内存地址,需要将 C 寄存器中的数值输出,所以 REG_RA(RAA)的 always 块中,不能因为 MOVB 中有一个固定的 11 就不作为条件;相反,为了将 C 忠实地输出,需要将三个 MOV 全都加进去;REG_WA(RWBA)也一样。

此外,上表没有包含 NOP 的指令输出,经测试只需要 REG_WE=1 即禁止读写即可,防止总线上数据污染寄存器。

verilog
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
module control_signal (MOVA,MOVB,MOVC,ADD,SUB,AND1,NOT1,RSR,RSL,JMP,JZ,Z,JC,C,IN1,OUT1,NOP,HALT,IR,SM,REG_RA,REG_WA,MADD,ALU_S,PC_LD,PC_INC,REG_WE,RAM_XL,RAM_DL,ALU_M,SHI_FBUS,SHI_FLBUS,SHI_FRBUS,IR_LD,CF_EN,ZF_EN,SM_EN,IN_EN,OUT_EN);
    input MOVA,MOVB,MOVC,ADD,SUB,AND1,NOT1,RSR,RSL,JMP,JZ,Z,JC,C,IN1,OUT1,NOP,HALT,SM;
    //    MOVA,MOVB,MOVC,ADD,SUB,AND, NOT, RSR,RSL,JMP,JZ-T,JC-T,IN, OUT, NOP,HALT,SM
    input[7:0] IR;
    output[1:0] REG_RA,REG_WA,MADD;
    //          RAA,   RWBA,  MADD
    output[3:0] ALU_S;
    //          S
    output PC_LD,PC_INC,REG_WE,RAM_XL,RAM_DL,ALU_M,SHI_FBUS,SHI_FLBUS,SHI_FRBUS,IR_LD,CF_EN,ZF_EN,SM_EN,IN_EN,OUT_EN;
    //     LD PC,IN PC, /WE,   XL,    DL,    M,    F-BUS,   FL-BUS,   FR-BUS,   LD IR,            SM,

    reg[1:0] MADD,REG_RA,REG_WA;
    reg[3:0] ALU_S;
    
    assign RAM_DL = (~SM)||MOVC||JMP||(JZ&&Z)||(JC&&C); // 取指, MOVC,JMP,JZT,JCT
    assign RAM_XL = MOVB&&(~SM); //MOVB
    assign PC_LD = JMP||(JZ&&Z)||(JC&&C); //JMP,JZT,JCT
    assign PC_INC = (~SM)||(JZ&&~Z)||(JC&&~C); // 取指, JZF,JCF
    assign IR_LD = (~SM); // 取指
    assign SHI_FBUS = ADD||SUB||AND1||NOT1||OUT1||MOVA||MOVB; //ADD,SUB,AND,NOT,OUT,MOVA,MOVB
    assign SHI_FLBUS = RSL; //RSL
    assign SHI_FRBUS = RSR; //RSR
    assign ALU_M = ADD||SUB||AND1||NOT1||RSR||RSL||OUT1;
    assign REG_WE = (~SM)||OUT1||MOVB||JMP||JZ||JC||HALT||NOP;
    assign CF_EN = ADD||SUB||RSR||RSL;
    assign ZF_EN = ADD||SUB;
    assign SM_EN = ~HALT;
    assign IN_EN = IN1;
    assign OUT_EN = OUT1;
    
    always @(SM,MOVB,MOVC) begin //MADD
        if(~SM) MADD=2'b0;
        else if(MOVB) MADD=2'b10;
        else if(MOVC) MADD=2'b01;
        else MADD=2'b0; // 不锁存只能这样了吧?
    end

    always @(ADD,SUB,AND1,NOT1,RSR,RSL,OUT1,MOVA,MOVB) begin //ALU_S
        if(ADD||SUB||AND1||NOT1||RSR||RSL||OUT1||MOVA||MOVB) ALU_S[3:0]=IR[7-:4];
        else ALU_S=4'b0;
    end

    always @(ADD,SUB,AND1,MOVA,MOVB,MOVC) begin //RAA
        if(ADD||SUB||AND1||MOVA||MOVB||MOVC) REG_RA=IR[1-:2];
        else REG_RA=2'b0;
    end

    always @(ADD,SUB,AND1,NOT1,RSR,RSL,IN1,OUT1,MOVA,MOVB,MOVC) begin//RWBA
        if(ADD||SUB||AND1||NOT1||RSR||RSL||IN1||OUT1||MOVA||MOVB||MOVC) REG_WA=IR[3-:2];
        else REG_WA=2'b0;
    end
    
endmodule

照例,下面提供三个部件仿真时使用的波形文件,使用 Quartus Prime 21.1 生成:下载链接