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に戻るといった処理を追加する。
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
実行結果