MacでVerilogのシミュレーションをしてみる4

MacでVerilogのシミュレーションをしてみる1 - k-igrsの日記

MacでVerilogのシミュレーションをしてみる2 - k-igrsの日記

MacでVerilogのシミュレーションをしてみる3 - k-igrsの日記

の続き

メモリへの読み書きを行うために、レジスタを実装しメモリーレジスタ間の命令を追加する。

レジスタは16ビットのレジスタR0,R1,R2,R3の4本でR0をアキュームレータに使用する。

parameter OP_MOV_RM = 8'h02;
reg [15:0] R0,R1,R2,R3;

オペランド指定により、

B7 B6 B5
0  0  0    メモリからR0に読み込み
0  0  1    メモリからR1に読み込み
0  1  0    メモリからR2に読み込み
0  1  1    メモリからR3に読み込み
1  0  0    R0からメモリに書き込み
1  0  1    R1からメモリに書き込み
1  1  0    R2からメモリに書き込み
1  1  1    R3からメモリに書き込み

 を行う。

Fetch → Decode → アクセスするメモリアドレスの読み込み → Read/Write → PCを更新してFetchに戻るといった処理を追加する。

f:id:k_igrs:20210704115931j:plain

MOVE命令への分岐を記述する。

wire [2:0] state_sel;
wire [2:0] path_jump,path_movrm;

assign path_jump = (op_code == OP_JMP ) ? 3'b001 : 3'b000;
assign path_movrm = (op_code == OP_MOV_RM ) ? 3'b010 : 3'b000;

assign state_sel = path_jump | path_movrm;

 ステートマシンにMOVE命令のパスを追加する。

                        4'b0001:begin
                                if ( STATE_SEL == 3'b000 )
                                        Q <= 4'b0010;
                                else if ( STATE_SEL == 3'b001 ) begin
                                        Q <= 4'b0011;
                                        PC <= PC + 1;
                                end
                                else if ( STATE_SEL == 3'b010 ) begin
                                        Q <= 4'b0101;
                                        PC <= PC + 1;
                                end
                        end
                        4'b0101: begin
                                Q <= 4'b0110;
                        end
                        4'b0110: begin
                                Q <= 4'b0111;
                        end
                        4'b0111: begin
                                Q <= 4'b0000;
                                PC <= PC + 1;
                        end

 RDBはステート0101b,オペコードbit7が0の時の0110bと最後のステートでアクティブにする。

assign pre_rdb =
〜略〜
    ((Q == 4'b0001) && (op_code == OP_MOV_RM)) ? 1'b0 :
    ((Q == 4'b0101) && (op_rand[7] == 1'b0))   ? 1'b0 :
    ( Q == 4'b0111)                            ? 1'b0 : 1'b1;

 メモリへの書き込みが必要なため、ステート0110bでWRBがアクティブになるようにする。

assign pre_wrb =
   ((Q == 4'b0101) && (op_rand[7] == 1'b1)) ? 1'b0 : 1'b1;

always @( posedge CK, negedge RB )
    if ( RB == 1'b0 )
            WRB <= 1'b1;
    else
            WRB <= pre_wrb;

 リード/ライトをメモリへのアドレスをラッチして出力する。

always @( posedge CK, negedge RB )
    if ( RB == 1'b0 )
            mem_adrs <= 10'h000;
    else
        if ( Q == 4'b0101 )
            mem_adrs = DI[9:0];
assign ADR =
    ( Q == 4'b0110 ) ? mem_adrs :
    ( Q == 4'b0111 ) ? mem_adrs : PC;

内部レジスタへメモリデータを読み込む処理を記述する。

always @( posedge CK, negedge RB )
    if ( RB == 1'b0 ) begin
            R0 <= 16'h0000;
            R1 <= 16'h0000;
            R2 <= 16'h0000;
            R3 <= 16'h0000;
    end
    else
        if ( ( Q == 4'b0110 ) && ( RDB == 1'b0 ) ) begin
            case ( op_rand[6:5] )
                2'b00: R0 <= DI;
                2'b01: R1 <= DI;
                2'b10: R2 <= DI;
                2'b11: R3 <= DI;
            endcase
        end

 オペランドで指定したレジスタのデータをメモリに書き込むため、Data Outに出力する。

wire [15:0] sel_reg;
assign sel_reg =
  (op_rand[6:5]==2'b00) ? R0 :
  (op_rand[6:5]==2'b01) ? R1 :
  (op_rand[6:5]==2'b10) ? R2 : R3;
assign DO = sel_reg;

 メモリからレジスタへのリードと、レジスタの値をメモリへ書き込むプログラムを書いてシミュレーションを実行して確認する。

0000
0001
0220 <- レジスタR1へ100h番地のデータを読み込む。
0100
02a0 <- レジスタR1の値を101h番地のメモリに書き込む。
0101
0240 <- レジスタR2へ101h番地のデータを読み込む。
0101
0009
0010
@100 55aa
@101 0000
 

実行結果

f:id:k_igrs:20210704132709p:plain