NPU 프론트엔드 모듈

GitHub RTL 원본

이 페이지가 참조하는 SystemVerilog 원본 파일:

역할

NPU 프론트엔드는 PS↔PL 경계의 AXI-Lite 진입점이다. 호스트 드라이버 HAL은 0x000 주소에 ISA 워드를 기록하고 0x008에 kick을 기록하며, 완료 상태는 같은 인터페이스의 읽기 채널로 폴링한다. AXIL_CMD_IN은 호스트 write 트랜잭션을 FIFO에 수신하고, AXIL_STAT_OUT은 엔진 완료 상태를 FIFO를 통해 호스트 읽기로 반환한다. 계층적으로 ctrl_npu_frontend의 상위는 AXI-Lite 버스, 하위는 컨트롤러의 디코더/디스패처(NPU 컨트롤러 모듈)이다.

AXIL_CMD_IN

호스트 write 트랜잭션을 수신하여 명령어를 CMD_IN FIFO에 저장한다. 파라미터 FIFO_DEPTH(기본값 8)가 FIFO 깊이를 결정한다. FIFO가 가득 차면 s_awready가 자동으로 디어서트되어 호스트에 백프레셔를 건다. 등록 주소는 두 곳이다: 0x000은 ISA 명령어 워드를 직접 FIFO에 삽입하고, 0x008bit63 = 1인 kick 마커를 삽입한다. kick 마커는 하위 디스패처가 배치 경계를 감지하는 데 사용된다. OUT_valid && IN_decoder_ready 핸드셰이크가 성립하는 사이클마다 FIFO에서 팝이 일어난다.

리스팅 18 hw/rtl/NPU_Controller/NPU_frontend/AXIL_CMD_IN.sv (AXI4-Lite Write Path)
  /*─────────────────────────────────────────────
  Register Address Map
  ───────────────────────────────────────────────*/
  localparam ADDR_INST = 12'h000;
  localparam ADDR_KICK = 12'h008;

AXIL_STAT_OUT

엔진 완료 시 상위 모듈이 IN_valid를 어서트하여 상태 워드를 STAT_OUT FIFO에 푸시한다. 파라미터 FIFO_DEPTH(기본값 8)가 적용된다. FIFO가 가득 차면 IN_valid가 무시된다. 완료 워드는 엔진에서 동일한 값으로 재전송되므로 누락은 재폴링으로 복구된다. 호스트가 AR 채널로 읽기를 요청하면 FIFO 헤드를 rdata_r에 래치하고 s_rvalid를 어서트한다. s_rready가 도착하면 rvalid를 해제한다. s_arready는 FIFO가 비어 있거나 R 응답이 아직 진행 중일 때 디어서트된다.

리스팅 19 hw/rtl/NPU_Controller/NPU_frontend/AXIL_STAT_OUT.sv (AXI4-Lite Read Path)
  /*─────────────────────────────────────────────
  FIFO  (simple synchronous, FIFO_DEPTH entries)
  Push : IN_valid from upper module
  Pop  : AXI4-Lite read handshake with CPU
  ───────────────────────────────────────────────*/
  localparam PTR_W = $clog2(FIFO_DEPTH);

  logic [`ISA_WIDTH-1:0] mem[0:FIFO_DEPTH-1];
  logic [PTR_W:0] wr_ptr, rd_ptr;
  logic fifo_empty, fifo_full;

  assign fifo_empty = (wr_ptr == rd_ptr);
  assign fifo_full  = (wr_ptr[PTR_W] != rd_ptr[PTR_W]) && (wr_ptr[PTR_W-1:0] == rd_ptr[PTR_W-1:0]);

  logic fifo_ren;

  always_ff @(posedge clk) begin
    if (!rst_n || IN_clear) begin
      wr_ptr <= '0;
      rd_ptr <= '0;
    end else begin
      // push : upper module feeds status continuously
      if (IN_valid && !fifo_full) begin
        mem[wr_ptr[PTR_W-1:0]] <= IN_data;
        wr_ptr <= wr_ptr + 1'b1;
      end
      // pop : CPU consumed the data
      if (fifo_ren && !fifo_empty) rd_ptr <= rd_ptr + 1'b1;
    end
  end

  /*─────────────────────────────────────────────
  AXI4-Lite Read Path
  Wait for AR, then pop one entry from FIFO and return it.
  Hold rvalid until CPU acknowledges with rready.
  ───────────────────────────────────────────────*/
  logic [`ISA_WIDTH-1:0] rdata_r;
  logic                  rvalid_r;

  assign s_rdata   = rdata_r;
  assign s_rresp   = 2'b00;
  assign s_rvalid  = rvalid_r;
  assign s_arready = ~rvalid_r && ~fifo_empty;  // ready only when FIFO has data
  assign fifo_ren  = s_arvalid && s_arready;  // pop on AR handshake

  always_ff @(posedge clk) begin
    if (!rst_n || IN_clear) begin
      rdata_r  <= '0;
      rvalid_r <= 1'b0;
    end else begin
      // AR handshake → latch FIFO head and assert rvalid
      if (s_arvalid && s_arready) begin
        rdata_r  <= mem[rd_ptr[PTR_W-1:0]];
        rvalid_r <= 1'b1;
      end
      // R handshake → CPU consumed data, release
      if (rvalid_r && s_rready) rvalid_r <= 1'b0;
    end
  end

ctrl_npu_frontend

ctrl_npu_frontendaxil_if.slave 인터페이스를 통해 AXI-Lite 신호를 AXIL_CMD_IN(write 채널)과 AXIL_STAT_OUT(read 채널)에 배선하는 wrapper 모듈이다. CMD_IN의 출력(cmd_data, cmd_valid)은 OUT_RAW_instructionOUT_kick으로 컨트롤러에 전달된다. OUT_kickcmd_valid & IN_fetch_ready의 조합논리로 생성된다. STAT_OUT 방향은 IN_enc_stat / IN_enc_valid를 인코더 FSM으로부터 직접 수신한다. ctrl_npu_interface.sv는 향후 코어별 인터페이스 집계를 위한 플레이스홀더다.

리스팅 20 hw/rtl/NPU_Controller/NPU_frontend/ctrl_npu_frontend.sv (인스턴스 배선)
  AXIL_CMD_IN #(
      .FIFO_DEPTH(8)
  ) u_cmd_in (
      .clk     (clk),
      .rst_n   (rst_n),
      .IN_clear(IN_clear), // FIXED: Typo i_clear -> IN_clear

      // AXI4-Lite Write channels directly routed from the interface
      .s_awaddr (S_AXIL_CTRL.awaddr),
      .s_awvalid(S_AXIL_CTRL.awvalid),
      .s_awready(S_AXIL_CTRL.awready),
      .s_wdata  (S_AXIL_CTRL.wdata),
      .s_wvalid (S_AXIL_CTRL.wvalid),
      .s_wready (S_AXIL_CTRL.wready),
      .s_bresp  (S_AXIL_CTRL.bresp),
      .s_bvalid (S_AXIL_CTRL.bvalid),
      .s_bready (S_AXIL_CTRL.bready),

      .OUT_data(cmd_data),
      .OUT_valid(cmd_valid),
      .IN_decoder_ready(IN_fetch_ready)
  );

  /*─────────────────────────────────────────────
  [1-2] Communication OUT : NPU -> CPU (Using Read Channels)
  ───────────────────────────────────────────────*/
  AXIL_STAT_OUT #(
      .FIFO_DEPTH(8)
  ) u_stat_out (
      .clk     (clk),
      .rst_n   (rst_n),
      .IN_clear(IN_clear), // FIXED: Typo i_clear -> IN_clear

      .IN_data (IN_enc_stat),  // FIXED: Typo i_enc_stat -> IN_enc_stat
      .IN_valid(IN_enc_valid), // FIXED: Typo i_enc_valid -> IN_enc_valid

      // AXI4-Lite Read channels directly routed from the interface
      .s_araddr (S_AXIL_CTRL.araddr),
      .s_arvalid(S_AXIL_CTRL.arvalid),
      .s_arready(S_AXIL_CTRL.arready),
      .s_rdata  (S_AXIL_CTRL.rdata),
      .s_rresp  (S_AXIL_CTRL.rresp),
      .s_rvalid (S_AXIL_CTRL.rvalid),
      .s_rready (S_AXIL_CTRL.rready)
  );

인터페이스 명세

npu_interfaces.svhaxil_ifaxis_if 두 인터페이스가 정의된다. axil_if는 ADDR_W=12, DATA_W=64 기본값으로 AW/W/B/AR/R 5개 채널을 모두 포함하고, slavemaster modport를 제공한다. ctrl_npu_frontendaxil_if.slave modport를 사용한다. axis_if는 tdata/tvalid/tready/tlast/tkeep의 AXI-Stream 인터페이스로, 데이터 경로 모듈이 사용한다.

리스팅 21 hw/rtl/NPU_Controller/npu_interfaces.svh (axis_if)
interface axis_if #(
    parameter DATA_WIDTH = 128
) ();
  logic [    DATA_WIDTH-1:0] tdata;
  logic                      tvalid;
  logic                      tready;
  logic                      tlast;
  logic [(DATA_WIDTH/8)-1:0] tkeep;

  // Slave Side (NPU Perspective: Input)
  modport slave(input tdata, tvalid, tlast, tkeep, output tready);

  // Master Side (NPU Perspective: Output)
  modport master(output tdata, tvalid, tlast, tkeep, input tready);
endinterface
리스팅 22 hw/rtl/NPU_Controller/npu_interfaces.svh (axil_if)
// axil_if.sv
interface axil_if #(
    parameter int ADDR_W = 12,
    parameter int DATA_W = 64
) (
    input logic clk,
    input logic rst_n
);
  // AW Channel
  logic [ADDR_W-1:0] awaddr;
  logic [       2:0] awprot;
  logic awvalid, awready;

  // W Channel
  logic [    DATA_W-1:0] wdata;
  logic [(DATA_W/8)-1:0] wstrb;
  logic wvalid, wready;

  // B Channel
  logic [1:0] bresp;
  logic bvalid, bready;

  // AR Channel
  logic [ADDR_W-1:0] araddr;
  logic [       2:0] arprot;
  logic arvalid, arready;

  // R Channel
  logic [DATA_W-1:0] rdata;
  logic [       1:0] rresp;
  logic rvalid, rready;

  modport slave(
      input awaddr, awprot, awvalid, wdata, wstrb, wvalid, bready,
      input araddr, arprot, arvalid, rready,
      output awready, wready, bresp, bvalid, arready, rdata, rresp, rvalid
  );

  modport master(
      output awaddr, awprot, awvalid, wdata, wstrb, wvalid, bready,
      output araddr, arprot, arvalid, rready,
      input awready, wready, bresp, bvalid, arready, rdata, rresp, rvalid
  );
endinterface

마지막 검증 대상

커밋 8c09e5e @ pccxai/pccx-FPGA-NPU-LLM-kv260 (2026-04-29).