Giới thiệu dự án

Trong kỷ nguyên vi điện tử hiện đại, xu hướng tích hợp hệ thống trên chip (System on Chip - SoC) với mật độ hàng triệu transistor và công nghệ đóng gói mật độ cao như BGA (Ball Grid Array) hay PGA (Pin Grid Array) đã khiến việc kiểm thử vật lý bằng đầu dò truyền thống (bed-of-nails probing) trở nên bất khả thi. Theo các nghiên cứu công nghiệp bán dẫn, chi phí kiểm tra và phát hiện lỗi (Design for Testability - DFT & On-Chip Debug) hiện chiếm tới 30% - 50% tổng thời gian và ngân sách của chu kỳ thiết kế vi mạch. Do đó, việc xây dựng một hệ thống gỡ lỗi phần cứng trực tiếp (Hardware In-Circuit Debugger) tiêu chuẩn hóa trên vi xử lý là yêu cầu sống còn nhằm rút ngắn chu kỳ đưa sản phẩm ra thị trường (Time-to-Market).

Đề tài khóa luận tập trung giải quyết bài toán: Thiết kế và hiện thực lõi IP JTAG (IEEE Std 1149.1) tích hợp khối điều khiển gỡ lỗi phần cứng (On-Chip Debug Module) cho bộ vi xử lý MIPS 32-bit kiến trúc đơn chu kỳ (Single-Cycle Architecture). Giải pháp cho phép can thiệp trực tiếp vào tiến trình thực thi của lõi vi xử lý, đọc/ghi tập thanh ghi, nạp lệnh vào bộ nhớ, kiểm soát điểm dừng (hardware breakpoint) và quét biên (boundary scan) mà không làm suy giảm hiệu năng hoạt động thực của hệ thống.

+-------------------------------------------------------------------------------+
|                                  HOST PC                                      |
|            [Python Debug CLI / ftd2jtag Script / Testbench]                   |
+---------------------------------------+---------------------------------------+
                                        | (USB 2.0 High-Speed Packets)
                                        v
+-------------------------------------------------------------------------------+
|                    FTDI FT232H (USB to JTAG MPSSE Engine)                     |
+---------------------------------------+---------------------------------------+
                                        | (3.3V LVCMOS Logic)
                                        v
+-------------------------------------------------------------------------------+
|                  TI TXB0108 (Bidirectional Level Shifter)                     |
+---------------------------------------+---------------------------------------+
                                        | (1.8V FPGA I/O Voltage Domain)
                                        v
+-------------------------------------------------------------------------------+
|               XILINX VIRTEX-7 VC707 FPGA (XC7VX485T EVAL BOARD)               |
|                                                                               |
|   +-----------------------------------------------------------------------+   |
|   |                        JTAG TAP CONTROLLER                            |   |
|   |  - 16-State FSM (IEEE 1149.1 Standard)                                |   |
|   |  - 4-bit Instruction Register (IR) with Opcode Decoder                |   |
|   |  - Data Registers: BSR, BYPASS (1b), DIDR (32b), UDRs (32-43b)        |   |
|   +-------------------+-----------------------------------+---------------+   |
|                       | Control Signals                   | Scan / Control    |
|                       v                                   v                   |
|   +---------------------------------------+   +---------------------------+   |
|   |             DEBUG MODULE              |   |    CORE MIPS 32-BIT       |   |
|   |  - Hardware Breakpoint Unit (Max 15)  |   |  - 25 Instructions Core   |   |
|   |  - Execution Controller (Halt/Step)   |<->|  - Single-Cycle Datapath  |   |
|   |  - Direct Instruction Injection Logic |   |  - Register File & PC     |   |
|   +---------------------------------------+   +---------------------------+   |
+-------------------------------------------------------------------------------+

Mục tiêu cụ thể của dự án

  1. Thiết kế vi xử lý MIPS 32-bit đơn chu kỳ: Hiện thực tập 25 lệnh cơ bản bao gồm các nhóm lệnh số học/logic (ADD, ADDI, SUB, ADDU, SUBU, ADDIU, AND, OR, XOR, NOR, ANDI, ORI, XORI), dịch bit (SLT, SLTU, SRL, SLL, SLTI, SLTIU), truy xuất bộ nhớ (SW, LW) và rẽ nhánh/nhảy (J, JAL, BEQ, BNE).
  2. Hiện thực lõi IP JTAG TAP chuẩn IEEE 1149.1: Xây dựng TAP Controller với máy trạng thái 16 trạng thái, thanh ghi lệnh IR 4-bit hỗ trợ các lệnh chuẩn (BYPASS, IDCODE, SAMPLE, PRELOAD, EXTEST) và các lệnh mở rộng người dùng (User-Defined Instructions).
  3. Phát triển khối On-Chip Debug Module: Hỗ trợ lưu trữ và giám sát tối đa 15 điểm dừng phần cứng (Hardware Breakpoints), cơ chế thực thi từng bước (Single-step / RUNSTEP), ép dừng cưỡng bức (FORCE_BREAK) và thực thi lệnh trực tiếp (RUN_DIRECT).
  4. Hiện thực hệ thống trên phần cứng FPGA và phần mềm Host: Triển khai tổng hợp trên kit FPGA Xilinx Virtex-7 VC707, kết nối qua IC cầu chuyển đổi FTDI FT232H USB-to-JTAG và phát triển chương trình điều khiển gỡ lỗi tự động bằng Python.

Phạm vi và giới hạn

  • Phạm vi: Kiến trúc MIPS32 đơn chu kỳ, giao diện JTAG 5 chân chuẩn (TCK, TMS, TDI, TDO, TRST), hệ thống gỡ lỗi dừng tại lệnh (cycle/instruction-based stopping).
  • Giới hạn: Chưa tích hợp bộ nhớ Cache (I-Cache/D-Cache) và khối quản lý bộ nhớ (MMU); chưa hỗ trợ cơ chế ngắt thời gian thực không đồng bộ (asynchronous real-time trace).

Phân tích và thiết kế giải pháp

Phân tích hiện trạng

Tiêu chí Phương pháp Bed-of-Nails Software In-Circuit Monitor Lõi IP JTAG On-Chip Debug (Đề tài)
Yêu cầu chân tiếp xúc vật lý Rất cao (yêu cầu tiếp xúc tất cả trace) Thấp (sử dụng UART/Serial port) Tối thiểu (4 - 5 chân chuẩn TAP)
Ảnh hưởng tài nguyên CPU Không Cao (chiếm bộ nhớ và chu kỳ ngắt CPU) Không xâm lấn (Non-intrusive on-chip hardware)
Hỗ trợ vi mạch đóng gói BGA Không khả thi Khả thi Hoàn toàn tối ưu nhờ Boundary Scan Cell
Khả năng dừng phần cứng Không hỗ trợ Giới hạn phần mềm Chính xác tại chu kỳ xung nhịp (Hardware Breakpoint)
Chi phí phần cứng kiểm thử Rất đắt (hàng chục nghìn USD) Thấp Thấp (chỉ cần module USB-JTAG FT232H)

Phân loại yêu cầu hệ thống theo mô hình MoSCoW

  • Must have (Bắt buộc):
    • Máy trạng thái TAP Controller 16 trạng thái theo đúng đồ hình IEEE 1149.1.
    • Thanh ghi IR 4-bit tự động nạp mẫu 2'b01 tại 2-bit LSB khi ở trạng thái Capture-IR để kiểm tra toàn vẹn đường truyền.
    • Các lệnh gỡ lỗi: CORE_RESET, RUNSTEP, READ_REGS, FORCE_BREAK, SET_BREAK, RUN, RUN_DIRECT.
    • Bộ so sánh địa chỉ thanh ghi bộ đếm chương trình (Program Counter - PC) để kích hoạt tín hiệu Halt_signl.
  • Should have (Nên có):
    • Khối dịch mức điện thế hai chiều TXB0108 bảo vệ cổng I/O FPGA.
    • Đọc Device Identification Code (DIDR 32-bit) chuẩn hóa.
  • Could have (Có thể có):
    • Giao diện dòng lệnh tự động hóa kịch bản kiểm thử bằng Python.
  • Won't have (Chưa thực hiện ở pha này):
    • Khối gỡ lỗi nâng cao ARM CoreSight Embedded Trace Macrocell (ETM).

Thiết kế hệ thống

Danh mục mã lệnh thanh ghi IR (Instruction Register Opcode Map)

+---------------+---------------+---------------------------------------------------------------+
| Tên lệnh IR   | Opcode [3:0]  | Chức năng chi tiết & Cơ chế phần cứng                         |
+---------------+---------------+---------------------------------------------------------------+
| BYPASS        | 4'h0          | Nối tắt TDI sang TDO qua thanh ghi BR 1-bit, bỏ qua lõi chip  |
| IDCODE        | 4'h1          | Truy xuất DIDR 32-bit chứa Version, Part Number, Manufacturer |
| SAMPLE/PRELOAD| 4'h2          | Lấy mẫu tín hiệu chân I/O vào BSR hoặc nạp trước dữ liệu      |
| EXTEST        | 4'h3          | Kiểm thử kết nối liên kết hở mạch/ngắn mạch giữa các chip     |
| PRG_COMMANDS  | 4'h4          | Ghi dữ liệu lệnh vào bộ nhớ lệnh Core (DR: 43-bit)            |
| CORE_RESET    | 4'h5          | Thiết lập lại trạng thái ban đầu của vi xử lý MIPS            |
| RUNSTEP       | 4'h6          | Cho phép vi xử lý chạy chính xác 1 chu kỳ lệnh đơn            |
| READ_REGS     | 4'h7          | Đọc PC, thanh ghi R1-R6, Memory Data qua chuỗi quét (DR: 35b) |
| FORCE_BREAK   | 4'h8          | Cưỡng bức dừng hoạt động của Core MIPS ngay lập tức (DR: 1b)  |
| SET_BREAK     | 4'h9          | Ghi địa chỉ điểm dừng vào Breakpoint Unit (DR: 36-bit)        |
| RUN           | 4'hA          | Kích hoạt vi xử lý chạy liên tục từ vị trí PC hiện tại        |
| RUN_DIRECT    | 4'hB          | Tiêm và ép thực thi trực tiếp 1 lệnh từ JTAG (DR: 32-bit)     |
+---------------+---------------+---------------------------------------------------------------+

Kiến trúc thanh ghi dữ liệu mở rộng (User Data Registers - UDR)

  • Thanh ghi PRG_COMMANDS (43-bit): Chứa Instruction_i[31:0] (32-bit mã máy lệnh) + Addr_Wr[10:0] (11-bit địa chỉ bộ nhớ lệnh).
  • Thanh ghi SET_BREAK (36-bit): Chứa BrkPnt_Addr[31:0] (32-bit địa chỉ cần dừng) + Addr[3:0] (4-bit chỉ số ô nhớ điểm dừng từ 0 đến 14).
  • Thanh ghi READ_REGS (35-bit): Chứa Data[31:0] (32-bit dữ liệu đọc ra từ Core) + Reg_addr[2:0] (3-bit mã chọn thanh ghi).
  • Thanh ghi DIDR (32-bit): Cấu trúc theo định dạng IEEE: Version[31:28] (4-bit) | PartNumber[27:12] (16-bit) | Manufacturer[11:1] (11-bit) | LSB[0] = 1'b1.
stateDiagram-v2
    [*] --> Test_Logic_Reset
    Test_Logic_Reset --> Run_Test_Idle: TMS = 0
    Test_Logic_Reset --> Test_Logic_Reset: TMS = 1
    
    Run_Test_Idle --> Select_DR_Scan: TMS = 1
    Run_Test_Idle --> Run_Test_Idle: TMS = 0
    
    state "Data Register (DR) Branch" as DR_Branch {
        Select_DR_Scan --> Capture_DR: TMS = 0
        Capture_DR --> Shift_DR: TMS = 0
        Capture_DR --> Exit1_DR: TMS = 1
        Shift_DR --> Shift_DR: TMS = 0
        Shift_DR --> Exit1_DR: TMS = 1
        Exit1_DR --> Pause_DR: TMS = 0
        Exit1_DR --> Update_DR: TMS = 1
        Pause_DR --> Pause_DR: TMS = 0
        Pause_DR --> Exit2_DR: TMS = 1
        Exit2_DR --> Shift_DR: TMS = 0
        Exit2_DR --> Update_DR: TMS = 1
        Update_DR --> Run_Test_Idle: TMS = 0
        Update_DR --> Select_DR_Scan: TMS = 1
    }
    
    Select_DR_Scan --> Select_IR_Scan: TMS = 1
    
    state "Instruction Register (IR) Branch" as IR_Branch {
        Select_IR_Scan --> Capture_IR: TMS = 0
        Select_IR_Scan --> Test_Logic_Reset: TMS = 1
        Capture_IR --> Shift_IR: TMS = 0
        Capture_IR --> Exit1_IR: TMS = 1
        Shift_IR --> Shift_IR: TMS = 0
        Shift_IR --> Exit1_IR: TMS = 1
        Exit1_IR --> Pause_IR: TMS = 0
        Exit1_IR --> Update_IR: TMS = 1
        Pause_IR --> Pause_IR: TMS = 0
        Pause_IR --> Exit2_IR: TMS = 1
        Exit2_IR --> Shift_IR: TMS = 0
        Exit2_IR --> Update_IR: TMS = 1
        Update_IR --> Run_Test_Idle: TMS = 0
        Update_IR --> Select_DR_Scan: TMS = 1
    }

Phương pháp luận (Methodology)

Quy trình phát triển tuân thủ mô hình chữ V (V-Model) kết hợp kiểm thử vòng lặp phần cứng (Hardware-in-the-Loop - HIL):

  1. Thiết kế mức RTL: Mô tả phần cứng bằng Verilog-2001/SystemVerilog trên công cụ thiết kế vi mạch.
  2. Mô phỏng chức năng logic (Functional Verification): Viết testbench kiểm tra từng góc trạng thái (corner cases) của máy trạng thái TAP Controller và hành vi nạp lệnh của MIPS Datapath.
  3. Tổng hợp và Hiện thực hóa phần cứng (Synthesis & Implementation): Thực hiện trên phần mềm Xilinx Vivado Design Suite 2021.2 nhắm tới dòng FPGA Virtex-7 XC7VX485T.
  4. Kiểm thử trên bo mạch thực tế: Kết nối Host PC qua module USB FT232H, sử dụng chip đệm TXB0108 chuyển đổi mức logic từ 3.3V (FTDI) sang 1.8V (FPGA Bank), chạy các kịch bản kiểm thử điều khiển bằng Python.

Implementation và kết quả

Quá trình phát triển phần cứng (Hardware Implementation)

Hiện thực máy trạng thái TAP Controller 16 trạng thái

Khối TAP Controller điều phối toàn bộ luồng dữ liệu kiểm thử. Ngõ vào được lấy mẫu tại cạnh lên của xung TCK, trong khi ngõ ra TDO được lái tại cạnh xuống của TCK để đảm bảo chu kỳ thiết lập và giữ (Setup/Hold Time) khi ghép tầng nhiều chip.

// Module: tap_controller.v
// Chuc nang: FSM dieu khien JTAG TAP 16 trang thai chuan IEEE Std 1149.1
module tap_controller (
    input  wire tck,
    input  wire trst_n,
    input  wire tms,
    output reg  capture_dr,
    output reg  shift_dr,
    output reg  update_dr,
    output reg  capture_ir,
    output reg  shift_ir,
    output reg  update_ir,
    output reg  reset_n,
    output reg  enable_tdo
);

    // Dinh nghia ma hoa 16 trang thai
    localparam TEST_LOGIC_RESET = 4'hF,
               RUN_TEST_IDLE    = 4'hC,
               SELECT_DR_SCAN   = 4'h7,
               CAPTURE_DR       = 4'h6,
               SHIFT_DR         = 4'h2,
               EXIT1_DR         = 4'h1,
               PAUSE_DR         = 4'h3,
               EXIT2_DR         = 4'h0,
               UPDATE_DR        = 4'h5,
               SELECT_IR_SCAN   = 4'h4,
               CAPTURE_IR       = 4'hE,
               SHIFT_IR         = 4'hA,
               EXIT1_IR         = 4'h9,
               PAUSE_IR         = 4'hB,
               EXIT2_IR         = 4'h8,
               UPDATE_IR        = 4'hD;

    reg [3:0] current_state, next_state;

    // Chuyen trang thai tai canh len TCK hoac Reset bat dong bo
    always @(posedge tck or negedge trst_n) begin
        if (!trst_n)
            current_state <= TEST_LOGIC_RESET;
        else
            current_state <= next_state;
    end

    // Logic chuyen trang thai tiep theo dua tren tin hieu TMS
    always @(*) begin
        case (current_state)
            TEST_LOGIC_RESET: next_state = tms ? TEST_LOGIC_RESET : RUN_TEST_IDLE;
            RUN_TEST_IDLE:    next_state = tms ? SELECT_DR_SCAN   : RUN_TEST_IDLE;
            SELECT_DR_SCAN:   next_state = tms ? SELECT_IR_SCAN   : CAPTURE_DR;
            CAPTURE_DR:       next_state = tms ? EXIT1_DR         : SHIFT_DR;
            SHIFT_DR:         next_state = tms ? EXIT1_DR         : SHIFT_DR;
            EXIT1_DR:         next_state = tms ? UPDATE_DR        : PAUSE_DR;
            PAUSE_DR:         next_state = tms ? EXIT2_DR         : PAUSE_DR;
            EXIT2_DR:         next_state = tms ? UPDATE_DR        : SHIFT_DR;
            UPDATE_DR:        next_state = tms ? SELECT_DR_SCAN   : RUN_TEST_IDLE;
            SELECT_IR_SCAN:   next_state = tms ? TEST_LOGIC_RESET : CAPTURE_IR;
            CAPTURE_IR:       next_state = tms ? EXIT1_IR         : SHIFT_IR;
            SHIFT_IR:         next_state = tms ? EXIT1_IR         : SHIFT_IR;
            EXIT1_IR:         next_state = tms ? UPDATE_IR        : PAUSE_IR;
            PAUSE_IR:         next_state = tms ? EXIT2_IR         : PAUSE_IR;
            EXIT2_IR:         next_state = tms ? UPDATE_IR        : SHIFT_IR;