Posts Issued on November 12, 2026

posted by sakurai on November 12, 2026 #1148

Pipeline部分のソースの部分を示します。

(* synthesize *)
module mkProcessor(Proc);
   // 段間FIFO(図の段間レジスタ)
   PipeQ#(PC2IF) pc2if <- mkPipeQ(PC2IF { pc: resetVector - 4, epoch: False, sn: '1 });  // PCの箱
   FIFO#(IF2ID)  if2id <- mkPipelineFIFO;
   FIFO#(ID2EX)  id2ex <- mkPipelineFIFO;
   FIFO#(EX2MA)  ex2ma <- mkPipelineFIFO;
   FIFO#(MA2WB)  ma2wb <- mkPipelineFIFO;
   FIFO#(Commit) commitQ <- mkFIFO;

   // 取り消し:<EX>が書き、同じサイクルの<ID>, <IF>, <PC>が後ろのポートで読む
   Reg#(Bool)         exEpoch[3]  <- mkCReg(3, False);           // [0]:EX, [1]:ID, [2]:IF
   Reg#(Maybe#(Addr)) redirect[2] <- mkCReg(2, tagged Invalid);  // [0]:EX, [1]:PC

   IMem imem <- mkIMem("prog.mem");   // <PC>でreq、<IF>でdata
   Wire#(Stall) stallW <- mkDWire(unpack(0));
   Kanata log <- mkKanata("kanata.log");

   // <WB>
   rule wb_stage (!stallW.wb);
      let x = ma2wb.first; ma2wb.deq;
      commitQ.enq(Commit { pc: x.pc, inst: x.inst, wen: False, rd: 0, wdata: 0,
                           sten: False, saddr: 0, ssize: 0, sdata: 0 });
      log.wbStage.pass(x.sn);
   endrule

   // <MA>
   rule ma_stage (!stallW.ma);
      let x = ex2ma.first; ex2ma.deq;
      ma2wb.enq(MA2WB { pc: x.pc, sn: x.sn, inst: x.inst });
      log.maStage.pass(x.sn);
   endrule

  // <EX>  分岐が成立したら exEpoch を反転し、分岐先を redirect に書く
   Bool exKill = id2ex.first.epoch != exEpoch[0];
   rule ex_kill (exKill);
      id2ex.deq;
      log.exStage.kill(id2ex.first.sn);
   endrule
   rule ex_stage (!exKill && !stallW.ex);
      let x = id2ex.first; id2ex.deq;
      let br = stubBranch(x.pc, x.inst);
      if (br.taken) begin
         exEpoch[0]  <= !exEpoch[0];
         redirect[0] <= tagged Valid br.target;
      end
      ex2ma.enq(EX2MA { pc: x.pc, sn: x.sn, inst: x.inst });
      log.exStage.pass(x.sn);
   endrule

   // <ID>
   Bool idKill = if2id.first.epoch != exEpoch[1];
   rule id_kill (idKill);
      if2id.deq;
      log.idStage.kill(if2id.first.sn);
   endrule
   rule id_stage (!idKill && !stallW.id);
      let x = if2id.first; if2id.deq;
      id2ex.enq(ID2EX { pc: x.pc, epoch: x.epoch, sn: x.sn, inst: x.inst });
      log.idStage.pass(x.sn);
      log.decoded(x.sn, x.pc, x.inst);   // 逆アセンブルをKanataの左の欄に出す
   endrule

   // <IF>  前のサイクルに<PC>がreqした命令をIMemから受け取る
   Bool ifKill = pc2if.first.epoch != exEpoch[2];
   rule if_kill (ifKill);
      pc2if.deq;
      log.ifStage.kill(pc2if.first.sn);
   endrule
   rule if_stage (!ifKill && !stallW.if_);
      let x = pc2if.first; pc2if.deq;
      let inst = imem.data;
      if2id.enq(IF2ID { pc: x.pc, epoch: x.epoch, sn: x.sn, inst: inst });
      log.ifStage.pass(x.sn);
      log.fetched(x.sn, inst);
   endrule

   // <PC>  PCの箱(last) → +4 → Mux(redirectが優先) → PCの箱、同じPCでIMemにreq
   rule pc_stage (!stallW.pc);
      let cur = pc2if.last;
      Addr pc    = cur.pc + 4;
      Bool epoch = cur.epoch;
      if (redirect[1] matches tagged Valid .target) begin
         pc    = target;
         epoch = !cur.epoch;
         redirect[1] <= tagged Invalid;
      end
      pc2if.enq(PC2IF { pc: pc, epoch: epoch, sn: cur.sn + 1 });
      imem.req(pc);
      log.pcStage(cur.sn + 1, pc);
   endrule

左矢前のブログ 次のブログ右矢