コンピュータアーキテクチャ 第 5 回 割 り 込 み その2 天 野 hunga@am.ics.keio.ac.jp ac
割 り 込 み(Interrupt) I/O 側 からCPUに 対 して 割 り 込 みを 要 求 CPUはこれを 受 け 付 けると 自 動 的 にPCを 割 り 込 み 処 理 ルーチンの 先 頭 に 変 更 戻 り 番 地 はどこかに 保 存 割 り 込 み 処 理 ルーチンを 実 行 終 了 後 リター ン 命 令 で 元 のルーチンに 戻 る 元 のルーチンは 割 り 込 みが 起 きたことがな かったかのように 実 行 しなければならない
割 り 込 みの 実 行 メインルーチン EI (Enable Interrupt) 割 り 込 み 処 理 ルーチン 割 り 込 み 要 求 信 号 RTI (Return from Interrupt) サブルーチンコールとの 違 いは どこで 呼 ばれるか 分 からない 点 にある
割 り 込 みの 実 現 方 法 割 り 込 み 処 理 のとび 先 番 地 固 定 番 地 POCOではff00とした 割 り 込 み 処 理 ルーチンの 先 頭 でどのI/Oが 要 求 を 出 し たか 調 べる 必 要 がある テーブル 引 き I/O 毎 に 飛 び 先 を 変 えることができる 戻 り 番 地 の 格 納 手 法 特 殊 なレジスタ POCOではIAR(Interrupt Address Register) ハードウェアスタック
割 り 込 みのシミュレーション 8ビットデータを 入 力 するI/Oモジュールが 接 続 されている データを 外 部 から 入 力 すると 割 り 込 みが 発 生 CPUは0x9001 番 地 から 読 むとそのデータを 読 むことができ る 読 むと 割 り 込 み 要 求 は 解 除 される 例 題 :1 文 字 読 み 込 み それを 出 力 する./shapa main.asm o imem.dat./shapa int.asm o imemint.dat でアセンブルの 後 実 行 してみよう
EINT END: JMP END メインルーチン 今 回 は 空 回 りだが ここに 色 々なプログラムを 入 れることができる LDHI r0,#0x80 ADDIU r0,#1 LOOP: LB r2,(r0) BEZ r2,loop LDHI r4,#0x90 ADDIU r4,#1 LB r5,(r4) SB r5,(r0) RTI 割 り 込 み 処 理 ルーチン 0x8001( 出 力 装 置 )が 空 いているかをチェックし 0x9001( 入 力 装 置 )から 読 み 込 んで 出 力 する 割 り 込 み 処 理 ルーチンで 長 く 走 りすぎ 後 ほど 検 討 する
割 り 込 み 関 係 の 命 令 EINT Enable Interrupt 00000 XXXXXX 01110 Xはdon t care 割 り 込 みを 許 可 する DINT Disable Interrupt 00000 XXXXXX 10000 Xはdon t care 割 り 込 みを 禁 止 する RTI Return from Interrupt 00000 XXXXXX 01111 PC IARにし 割 り 込 みを 許 可 する
割 り 込 みの 実 装 intreq VDD 割 り 込 み 要 求 線 オープンドレイン どれかがLならばL CPU I/O I/O I/O オープンドレインの 割 り 込 み 線 を 使 って 割 り 込 み 要 求 を 発 生 する 割 り 込 み 処 理 ルーチンに 飛 ぶときに 割 り 込 みを 禁 止 割 り 込 み 処 理 ルーチンに 飛 ぶときに 割 り 込 みを 禁 止 割 り 込 みが 掛 かり 続 けることを 防 止
割 り 込 みのVerilogコード module poco( input clk, rst_n, input [`DATA_W-1:0] idatain, input [`DATA_W-1:0] ddatain, input intreq, output [`DATA_W-1:0] iaddr, daddr, output [`DATA_W-1:0] ddataout, output we0, we1); IAR: 戻 り 番 地 保 存 用 レジスタ reg g[ [`DATA_ W-1:0] ]p pc, iar; reg int_enable; 割 り 込 み 許 可 フラグ assign eint_op = (opcode == `OP_REG) & (func == `F_EINT); assign dint_op = (opcode == `OP_REG) & (func == `F_DINT); assign rti_op = (opcode == `OP_REG) & (func == `F_RTI);
pcの 記 述 always @(posedge clk or negedge rst_n) begin 割 り 込 み 許 可 で 要 求 があれば 割 if(!rst_n) pc <= 0; り 込 み 処 理 ルーチンへ else if(int_enable & intreq) pc <= `INTAD; else if ((bez_op & rf_a == 16'b0 ) (bnz_op & rf_a!= 16'b0) (bpl_op & ~rf_a[15]) (bmi_op & rf_a[15])) pc <= pc +{{8{imm[7]}},imm}+1 ; else if (jmp_op jal_op) pc <= pc + {{5{idatain[10]}},idatain[10:0]}+1; else if(jr_op) pc <= rf_a; else if(rti_op) RTI 命 令 でIARの 中 身 をPCに 戻 pc <= iar; す else pc <= pc+1; end
always @(posedge clk or negedge rst_n) begin if(!rst_n) int_enable <= `DISABLE; else if(eint_op rti_op) int_enable <= `ENABLE; else if(int_enable & intreq dint_op) int_enable <= `DISABLE; end always @(posedge clk) if(int_enable & intreq) iar <= pc; EINT 命 令 か RTI 命 令 で 割 り 込 み 許 可 割 り 込 みに 飛 ぶときと DINT 命 令 で 割 り 込 み 禁 止 割 り 込 みに 飛 ぶときに 飛 PCの 値 をIARに 保 存
割 り 込 みが 二 重 に 掛 かったら? メインルーチン EI (Enable Interrupt) 割 り 込 み 処 理 ルーチン 割 り 込 み 要 求 信 号 from I/O1 禁 止 割 り 込 み 要 求 信 号 from I/O2 禁 止 なので 無 視 される I/O1の 要 求 は 満 足 される RTI (Return from Interrupt) 割 り 込 み 処 理 中 は 基 本 的 に 割 り 込 み 禁 止 で 走 る
割 り 込 みが 二 重 に 掛 かったら? メインルーチン EI (Enable Interrupt) 割 り 込 み 処 理 ルーチン 再 び 割 り込 み 処 理 ルーチンへ メインルーチンに 戻 ったらすぐ I/O2の 割 り 込 みが 掛 かる 許 可 今 度 はI/O2の 要 求 が 満 足 される RTI (Return from Interrupt) 割 り 込 み 要 求 がなくなるまで 割 り 込 み 処 理 ルーチンに 飛 び 続 ける いつかは 要 求 がなくなりメインルーチンを 実 行 可 能 になる
多 重 割 り 込 み メインルーチン EI (Enable Interrupt) 割 り 込 み 処 理 ルーチン 優 先 順 位 の 高 い 割 り 込 み 処 理 ルーチン 割 り 込 み 要 求 信 号 from I/O1 禁 止 優 先 順 の 高 い 割 り 込 み 要 求 信 号 from I/O2 RTI RTHI (Return From High level Interrupt ) 割 り 込 み 処 理 中 に 優 先 順 位 の 高 い 割 り 込 みを 許 す
多 重 割 り 込 みは 必 要 か? 割 り 込 み 処 理 時 間 が 長 いと 緊 急 事 態 に 対 処 できな い 多 くのCPUでは 通 常 の 割 り 込 みと 禁 止 できないノンマ スカブル 割 り 込 み(NMI)を 設 ける PC 退 避 用 の 専 用 レジスタ リターン 用 専 用 命 令 が 必 要 割 り 込 み 処 理 中 でもNMIは 受 け 付 ける NMIは 緊 急 事 態 のみ 優 先 順 位 がマルチレベルの 割 り 込 み ハードウェアスタックが 必 要 になる DSP 以 外 最 近 のCPUでは 使 われない
CPUによる 入 力 CPU LB SB I/O メモリ LBで 一 度 レジスタにとってきて SBでメモリにしまう
CPUによる 出 力 CPU SB LB I/O メモリ LBで 一 度 レジスタにとってきて SBでI/Oのデータレジスタへ 出 力
Direct Memory Access(DMA) CPU DMA 要 求 許 可 バスを 開 放 I/O I/Oがアドレスを 指 定 し 直 接 メモリとデータをやりとり メモリ 終 了 後 はバスを 開 放 し CPUに 割 り 込 みを 掛 ける CPUはDMAが が 掛 かったことを 知 らない
入 力 を 取 り 逃 がさないプログラム 割 り 込 みが 掛 かったらメモリ 中 のバッファに 入 力 データを 取 り 込 む メインルーチンで バッファから 入 力 データを 取 り 出 して 出 力 メインルーチン 内 にビジーウェイトを 作 らない
メモリ 中 のバッファの 作 り 方 r3 r4 r3==r4の 時 は バッファは 空
メモリ 中 のバッファの 作 り 方 r3 r4 ポインタを 先 に 進 めて データを 入 力 r3!= r4の 時 ポインタを 先 に 進 めてデータを 出 力 本 当 はどこかで 一 巡 させる サイクリックバッファ
メモリ 中 のバッファの 作 り 方 r3 r4 ポインタを 先 に 進 めて データを 入 力 r3!= r4の 時 ポインタを 先 に 進 めてデータを 出 力 本 当 はどこかで 一 巡 させる サイクリックバッファ
メモリ 中 のバッファの 作 り 方 r3 r4 ポインタを 先 に 進 めて データを 入 力 r3!= r4の 時 ポインタを 先 に 進 めてデータを 出 力 本 当 はどこかで 一 巡 させる サイクリックバッファ
メインルーチン LDHI r0,#0x80 初 期 化 :r0 0x8000: 0 0 出 力 装 置 ADDIU r0,#1 r1 0x9000: 入 力 装 置 LDHI r1,#0x90 r3: 入 力 ポインタ ADDIU r1,#1 r4: 出 力 ポインタ LDI r3,#0 LDI r4,#0 EINT LOOP: MV r5,r3 割 り 込 み 処 理 ルーチンでバッファへ SUB r5,r4 入 力 したかどうかをチェック BEZ r5,loop LOOP2: LB r2,(r0) BEZ r2,loop2 出 力 装 置 が 空 いていることを ADDIU r4,#1 チェックして バッファの 中 身 を 出 力 LB r2,(r4) SB r2,(r0) JMP LOOP
演 習 このプログラムの 割 り 込 み 処 理 ルーチンを 書 いてシミュレーションで 動 作 を 確 認 せよ 割 り 込 みが 掛 かったらバッファにしまうだけでよい