計算機構成 第8回 POCOの構造とVerilog記述 テキスト第5章-第6章 情報工学科 天野英晴 今日の目標はPOCOのVerilog記述 の理解 • 論理合成と性能評価に入る前に、POCOの プログラム、Verilog記述について確認してお く • 今までのPOCO関係の演習で出してないの があれば、今日中にやっておこう • フルスクラッチシリーズは後に機会を設ける ので今日やらなくて良い POCOの全体構成 ‘0’ 2:0 00 01 10 extext11 pcsel THB ADD 00 01 10 S Y A + zero ‘1’ + 0 1 zero 7:0 comsel 10:0 00 7:0 pcjr B rf_a rf_b alu_bsel 01 10 ext ext0 aadr 10:8 PC ‘7’ 0 1 badr cadr rf_c casel rf_csel 00 01 rwe 10 7:5 idatain ddatain iaddr … 命令メモリ ddataout データメモリ … daddr we もう決まっちゃってる所 ‘0’ 2:0 00 01 10 + zero ‘1’ + 1 0 PC extext11 pcsel zero 7:0 THB ADD 10:0 00 01 10 S Y rfile rfile_1(.clk(clk), A .a(rf_a), B .aadr(rd), .b(rf_b), .badr(rs), alu_bsel comsel 00 .we(rwe)); 01 10 .c(rf_c), .cadr(cadr), 7:0 pcjr rf_a assign {opcode,rd,rs,func} = idatain; 10:8 assign imm=idatain[7:0]; ‘7’ rf_b ext ext0 aadr 0 1 badr cadr rf_c casel rf_csel assign ddataout = rf_a; 00 01 rwe 10 assign daddr = rf_b; 7:5 idatain ddatain assign we = st_op; iaddr … assign iaddr = pc; 命令メモリ ddataout データメモリ … daddr we データパスの記述 ‘0’ assign com = (addi_op|laddiu_op) ? `ALU_ADD: (ldi_op|ldiu_op)?`ALU_LD: func[2:0]; 2:0 00 01 10 extext11 pcsel THB ADD 00 01 10 S Y A + zero ‘1’ + alu_b pcjr 1 0 assign zero 7:0 comsel 10:0 = (addi_op|addiu_op)? { {8{imm[7]}},imm} : PC (addiu_opldiu_op)? {8’b0,imm}: rf_b; B 00 7:0 rf_a rf_b alu_bsel 01 10 ext ext0 aadr 10:8 ‘7’ 0 1 badr cadr rf_c casel rf_csel 00 01 rwe 10 7:5 idatain= assign cadr jal_op? 3’b111 : rd; ddatain assign rwe = ld_op | alu_op | ldi_op | ldiu_op | addi_op | addiu_op..|jal_op; iaddr … 命令メモリ assign rf_c = ld_op ? ddatin: ddataout jal_op ? pc+1: alu_y; データメモリ … daddr we pc周辺 ‘0’ 2:0 00 01 10 pcsel extext11 THB ADD 00 01 10 S Y A + ‘1’ + 0 1 pcjr PC B always @(posedge clk or negedge rst_n) alu_bsel comsel zero begin 7:0 10:0 00 01 10 zero if(!rst_n) pc <= 0; else if ((bez_op & rf_a == 16’b0) | (bnz_op & rf_a !=ext 16’b0) | ext0 7:0 rf_a rf_b (bpl_op & ~rf_a[15]) | (bmi_op & rf_a[15])) pc<=pc+{{8imm[7]}},imm}+1; aadr 10:8 else if (jmp_op| jal_op) badr 0 cadr pc <= pc +{{5{idatain[10]}},idatain[10:0]}}+1; 1 ‘7’ else if(jr_op) rf_c rwe pc <= rf_a; rf_csel casel 00 01 10 else pc<=pc+1; 7:5 end idatain ddatain iaddr … 命令メモリ ddataout データメモリ … daddr we なぜPC周辺のみ図とマッチしないか? • always文の中はif文やcase文が使えて便利なの でなるべく中で判断までやってしまう • 他の部分でも、マルチプレクサの制御信号などは明 示的に書いていない →今回の書き方は、テキストの図に忠実に、しかし以 下を例外とした マルチプレクサの制御信号は明示的に書かない → 書いても面倒なだけなので、、 レジスタに対する書き込み制御は always文内に書く → 無理に外に出すより読みやすいので、、 pocoz.v:図に完全に忠実に書いた 記述(decode.vの後半) assign we = st_op; assign rwe = ld_op | alu_op | ldi_op | ldiu_op | addi_op | addiu_op | ldhi_op | jal_op ; assign rf_csel = ld_op ? 2'b01 : jal_op ? 2'b10: 2'b00 ; assign alu_bsel = (addi_op | ldi_op) ? 2'b01 : (addiu_op | ldiu_op) ? 2'b10 : ldhi_op? 2'b11 : 2'b00; assign comsel = (addi_op | addiu_op) ? 2'b01 : (ldi_op | ldiu_op | ldhi_op) ? 2'b10 : 2'b00; assign casel = jal_op; assign pcjr = jr_op; assign pcsel = (bez_op & zero | bnz_op & ~zero | bpl_op & ~mi | bmi_op & mi) ? 2'b01 : jmp_op | jal_op ? 2'b10 : 2'b00; endmodule pocoz.v:図に完全に忠実に書いた 記述 モジュール decode.v include "def.h" module decode( input [`OPCODE_W-1:0] opcode, input [`OPCODE_W-1:0] func, input zero, mi, output [1:0] alu_bsel, comsel, rf_csel, pcsel, output we, rwe, casel, pcjr); wire st_op, bez_op, bnz_op, bmi_op, bpl_op, addi_op, ld_op, alu_op; wire ldi_op, ldiu_op, ldhi_op, addiu_op, jmp_op, jal_op, jr_op, jalr_op; assign st_op = (opcode == `OP_REG) & (func == `F_ST); assign ld_op = (opcode == `OP_REG) & (func == `F_LD); assign jr_op = (opcode == `OP_REG) & (func == `F_JR); assign jalr_op = (opcode == `OP_REG) & (func == `F_JALR); assign alu_op = (opcode == `OP_REG) & (func[4:3] == 2'b00); assign ldi_op = (opcode == `OP_LDI); assign ldiu_op = (opcode == `OP_LDIU); assign addi_op = (opcode == `OP_ADDI); assign addiu_op = (opcode == `OP_ADDIU); assign ldhi_op = (opcode == `OP_LDHI); assign bez_op = (opcode == `OP_BEZ); assign bnz_op = (opcode == `OP_BNZ); assign bpl_op = (opcode == `OP_BPL); assign bmi_op = (opcode == `OP_BMI); assign jmp_op = (opcode == `OP_JMP); assign jal_op = (opcode == `OP_JAL); pocoz.vの本体 assign {opcode, rd, rs, func} = idatain; assign imm = idatain[`IMM_W-1:0]; decode decode_1 (.opcode(opcode), .func(func), .zero(zero), .mi(mi), マルチプレクサの記述が .alu_bsel(alu_bsel), .comsel(comsel), .rf_csel(rf_csel), .pcsel(pcsel), .we(we), .rwe(rwe), .casel(casel), .pcjr(pcjr)); 完全に図とマッチしている assign alu_b = alu_bsel==2'b01 ? {{8{imm[7]}},imm} : alu_bsel == 2'b10 ? {8'b0,imm} : alu_bsel == 2'b11 ? {imm, 8'b0} : rf_b; assign com = comsel==2'b01 ? `ALU_ADD: comsel==2'b10 ? `ALU_THB: func[`SEL_W-1:0]; assign rf_c = rf_csel==2'b01 ? ddatain : rf_csel==2'b10 ? pc+1 : alu_y; assign cadr = casel ? 3'b111 : rd; alu alu_1(.a(rf_a), .b(alu_b), .s(com), .y(alu_y)); rfile rfile_1(.clk(clk), .a(rf_a), .aadr(rd), .b(rf_b), .badr(rs), .c(rf_c), .cadr(cadr), .we(rwe)); pocoz.vの本体 assign zero = rf_a == 16'b0; assign mi = rf_a[15]; assign pcadd = pcsel == 2'b01 ? {{8{imm[7]}},imm} : pcsel == 2'b10 ? {{5{idatain[10]}},idatain[10:0]}: 0; assign pcnext = pcjr ? rf_a: pc+pcadd+1; always @(posedge clk or negedge rst_n) begin if(!rst_n) pc <= 0; else pc <= pcnext; end pc周辺も分離して書くこと は可能だが見やすいとは いえない 今回の記述の特徴 • 出力信号依存の書き方 • 全ての出力を分離して記述している モジュールA モジュールA・B モジュールB まとめて書ければ可読性が向上する (かもしれない) AとBに共通性があっても 分離して書かなければならない function文 • うまく使うと非常に分かりやすく書ける • しかし、落とし穴がある – 変数スコープが曖昧 – 代入文は前後関係が生じる – 出力をまとめる必要がある • この授業では使わないが興味があればどう ぞ pocof.vを参照 function [7:0] decode( input [`OPCODE_W-1:0] op, 内部変数をregで定義 input [`OPCODE_W-1:0] fu); reg [1:0] alu_bsel, comsel, rf_csel; reg rwe, casel; begin デフォルトの値を最初に書 alu_bsel = 2'b00; comsel = 2'b00; いてしまう rf_csel = 2'b00; rwe = 1'b0; casel = 1'b0; case (op) `OP_REG: if(fu==`F_LD) begin rwe = 1'b1; rf_csel = 2'b01; end その後は後に書いたものが else if(fu[4:3] == 2'b00) 前のを打ち消す rwe = 1'b1; … pocof.vを参照 `OP_LDI: begin rwe = 1'b1; comsel = 2'b10; alu_bsel = 2'b01; end `OP_LDIU: begin rwe = 1'b1; comsel = 2'b10; alu_bsel = 2'b10; end `OP_ADDI: begin rwe = 1'b1; 命令毎に特徴的な出力の comsel = 2'b01; 動きをまとめて書ける alu_bsel = 2'b01; end `OP_ADDIU: begin rwe = 1'b1; comsel = 2'b01; alu_bsel = 2'b10; end `OP_LDHI: begin rwe = 1'b1; comsel = 2'b10; alu_bsel = 2'b11; end `OP_JAL: begin rwe = 1'b1; casel = 1'b1; rf_csel = 2'b10; end endcase decode = {alu_bsel, comsel, rf_csel, rwe, casel}; end 最後に全体の信号をくっつ endfunction けて出力 pocof.vを参照 `OP_LDI: begin rwe = 1'b1; comsel = 2'b10; alu_bsel = 2'b01; end `OP_LDIU: begin rwe = 1'b1; comsel = 2'b10; alu_bsel = 2'b10; end `OP_ADDI: begin rwe = 1'b1; 命令毎に特徴的な出力の comsel = 2'b01; 動きをまとめて書ける alu_bsel = 2'b01; end `OP_ADDIU: begin rwe = 1'b1; comsel = 2'b01; alu_bsel = 2'b10; end `OP_LDHI: begin rwe = 1'b1; comsel = 2'b10; alu_bsel = 2'b11; end `OP_JAL: begin rwe = 1'b1; casel = 1'b1; rf_csel = 2'b10; end endcase decode = {alu_bsel, comsel, rf_csel, rwe, casel}; end 最後に全体の信号をくっつ endfunction けて出力 pocof.vの本体 assign {alu_bsel, comsel, rf_csel, rwe, casel} = decode(opcode,func); 外部の信号線に 関係付けを行う • always文をレジスタ以外にも使う書き方でも 同様の多入力、多出力的な書き方が可能 • 一時、論理合成の効率が良かったため FPGAベンダーが推奨したため、広がった • しかし入門者は使わないほうが良い ディスプレースメント付きレジスタ 間接指定 LDD rd,n(ra): rd ← (n+ra) 01110 ddd aaa nnnnn STD rd,n(ra): (n+ra) ← rd 01111 ddd aaa nnnnn • レジスタ間接指定の一種 • レジスタとn(ディスプレースメント)を加えた値が実効 アドレスになる • ループアンローリングができるので、RISCではこの 方式が一般的 • POCOの今までのタイプと異なる 演習 LDDとSTDを実装せよ。 • eximem.datにテストプログラムがあるのでこ れをimem.datにコピーして用いよ • shapaは対応していないので注意! • def.hには加えてある • 変更箇所が多く構造とVerilog記述の関係を 良く理解しないとできない • gtkwaveを使って論理的にバグを追い詰める こと
© Copyright 2024 ExpyDoc