Trong bài viết trước, nguyên lý và cách thức hoạt động của chế độ lập trình bộ nhớ trên chip đã được trình bày qua một ví dụ cụ thể. Thông qua ví dụ này, bạn có thể hiểu làm thế nào một bộ nhớ trên chip có thể được đọc và ghi thông qua giao thức JTAG. Bài viết này sẽ trình bày cụ thể cách thức hoạt động thông qua một testbench cơ bản. Waveform của từng lệnh cũng sẽ được phân tích chi tiết.
Danh sách bài viết trước đó:
1) Mô tả testbench
Testbench này được sử dụng với mục đích tạo ra các trường hợp kiểm tra cơ bản và minh họa hoạt động của JTAG trong chế độ programming. Testbench gồm các thành phần cơ bản như sau:
- jtag_top (instance) là DUT cần kiểm tra
- clock_reset_jtag (initial) là bộ tạo reset là clock cho giao tiếp JTAG. TCK có chu kỳ là 6ns
- clock_reset_sys (initial) là bộ tạo reset là clock cho logic hệ thống. TCK có chu kỳ là 20ns
- capIr[3:0] là thanh ghi lưu lại giá trị được dịch từ thanh ghi IR trong DUT rs TDO
- capAddr[7:0] là thanh ghi lưu lại giá trị địa chỉ nhận được từ TDO trong lệnh SET_ADDR
- capData[17:0] là thanh ghi lưu lại dữ liệu nhận được từ TDO trong lệnh SET_DATA
- main (initial) là chương trình chính thực thi các nhiệm vụ:
- Chọn lệnh và dữ liệu mong muốn.
- Gọi các task để dịch lệnh và dữ liệu vào JTAG controller thông qua TDI
- Các task chức năng
- goto_IDLE()
- Lái FSM của TAP đến trạng thái RUN_TEST_IDLE sau khi reset
- In trạng thái hiện tại của FSM sau khi thực thi
- send_IR()
- Nạp lệnh cho JTAG
- In trạng thái của FSM theo từng bước hoạt động
- In trạng thái hiện tại của FSM, các giá trị nhận được trên TDO và giá trị thanh ghi lệnh, địa chỉ và dữ liệu sau khi thực thi.
- send_DR()
- Nạp dữ liệu cho JTAG
- In trạng thái của FSM theo từng bước hoạt động
- In trạng thái hiện tại của FSM, các giá trị nhận được trên TDO và giá trị thanh ghi lệnh, địa chỉ và dữ liệu sau khi thực thi.
- checkStatus()
- Gửi mã yêu cầu CHECK khi JTAG đang thực thi lệnh SET_DATA
- Yêu cầu CHECK được gửi liên tục cho đến khi nhận được mã trạng thái OKAY từ JTAG controller
- printState() In trạng thái hiện tại của FSM
- printRegTdo() In giá trị các thanh ghi capIR, capAddr và capData. Đây là các thanh ghi lưu lại giá trị nhận được từ TDO
- printReg() In giá trị các thanh ghi ir_reg (lệnh hiện tại), addr_reg (địa chỉ truy xuất bộ nhớ hiện tại), wdata_reg (dữ liệu của lệnh ghi gần nhất) và rdata_reg (dữ liệu của lệnh đọc gần nhất)
- shiftIr() thực thi quá trình nạp mã lệnh JTAG
- shiftDr() thực thi quá trình nạp dữ liệu
Hình 1: Cấu trúc của testbench cơ bản (simple testbench) |
2) Cấu hình định thời truy xuất bộ nhớ
Các thông số định thời của mô hình bộ nhớ mem_model được cấu hình như sau:
Chu kỳ clock nội inClk dùng để mô hình hóa định thời của bộ nhớ là 2ns
TWRITE = 16’d43 - ứng với Twrite = 44*2 = 88 (ns)Như vậy độ trễ lớn nhất là Twrite=88ns. Từ tần số clk=6ns, số chu kỳ cần thiết để đảm bảo mem_ctrl truy xuất đúng định thời bộ nhớ là:
TTRANS = 16’d35 - ứng với Ttrans = 36*2 = 72 (ns)
88/6 > 14.667 (chu kỳ clk)
Như vậy, độ trễ của một truy xuất được cấu hình trong mem_ctrl là:
ACC_DELAY = 16’d15
Với thông số này thời gian truy xuất bộ nhớ (mem_model) thực tế là:
Taccess = 15*6 = 90ns > Twrite > Ttrans
Thời gian này đáp ứng cho cả yêu cầu ghi và đọc.3) Mô tả trường hợp test của testbench
Testbench chứa hai biến dùng để gán lệnh và dữ liệu muốn gửi đến JTAG.
- ir[3:0] – biến lưu mã lệnh
- dr[17:0] – biến lưu dữ liệu
Testbench thực thi một trình tự các hoạt động được mô tả trong initial main như sau:
- Trình tự 1 – Kiểm tra hoạt động lệnh BYPASS
- goto_IDLE() – Đưa FSM của JTAG controller về trạng thái RUN_TEST_IDLE sau khi reset
- Gán mã lệnh BYPASS cho biến ir
- send_IR() – Gửi mã lệnh chứa trong ir đến JTAG controller
- Gán giá trị mong muốn cho dr=18'b01111111_11111010_10, giá trị này sẽ được dịch trên TDI trong hoạt động BYPASS
- Khai báo số bit muốn dịch cho BIT_NUM=5
- send_DR() – Gửi chuỗi bit chứa trong dr đến TDI của JTAG với số bit dịch là BIT_NUM. Thứ tự dịch là từ LSB đến MSB với bit đầu tiên được dịch là bit dr[0]
- Trình tự 2 – Kiểm tra hoạt động lệnh SET_ADDR
- Gán lệnh SET_ADDR đến ir
- send_IR() – gửi lệnh trong ir đến JTAG
- Gán địa chỉ cần truy xuất đến dr[7:0]=8’b000000_11, các bit dr[17:8] là giá trị tùy ý vì không sử dụng
- Gán số bit muốn dịch là 8 cho BIT_NUM
- send_DR() – gửi địa chỉ muốn truy xuất đến JTAG
- Trình tự 3 – Kiểm tra hoạt động lệnh SET_DATA với mã yêu cầu WRITE
- Gán lệnh SET_DATA đến ir
- send_IR() – gửi lệnh trong ir đến JTAG
- Gán dữ liệu ghi dr[17:2] và mã yêu cầu ghi đến dr[1:0], dr[17:0] = 18'b01111110_10000001_10
- Gán số bit muốn dịch là 18 cho BIT_NUM
- send_DR() – dữ liệu ghi và yêu cầu ghi bộ nhớ đến JTAG
- Trình tự 4 – Kiểm tra hoạt động lệnh SET_DATA với mã yêu cầu READ
- checkStatus() – Vì trước đó là một yêu cầu ghi nên cần gửi yêu cầu CHECK để kiểm tra trạng thái hiện tại của JTAG. Mã yêu cầu đọc chỉ được gửi nếu trạng thái JTAG là OKAY, ứng với việc nhận được một giá trị 2’b10 trên TDO
- Gán mã yêu cầu đọc dr[1:0]=2’b01, các bit dr[17:2] có thể gán tùy ý
- Khai báo số bit cần dịch là 18 cho BIT_NUM
- send_DR() – Gửi yêu cầu đọc bộ nhớ cho JTAG
- checkStatus() – Kiểm tra trạng thái JTAG và đọc dữ liệu. Task này sẽ gửi mã lệnh CHECK liên tục đến JTAG, mỗi lần gửi sẽ nhận được 18 bit dữ liệu trên TDO. Nếu hai bit đầu tiên nhận được là 2’b10, ưng với trạng thái OKAY thì 16 bit tiếp theo chính là dữ liệu đọc
Hình 2: Trình tự thực thi của main trong testbench |
Lưu ý, đây chỉ là một testbench ví dụ được dùng để giải thích hoạt động của JTAG trong chế độ programming chứ không phải là một phương pháp giúp kiểm tra đầy đủ chức năng của thiết kế. Thông qua mô tả này, bạn đọc có thể tự viết các testbench đơn giản tương tự để điều khiển thiết kế JTAG theo ý muốn.
4) Mô tả waveform của task goto_IDLE()
goto_IDLE() thực hiện lái TMS=0 theo cạnh xuống TCK sau khi reset để lái FSM của JTAG đến trạng thái RUN_TEST_IDLE. Sau đó, trạng thái hiện tại của FSM được in ra.
# [goto_IDLE] TAP state : RUN_TEST_IDLE
# ----------------------------------------
Hình 3: Hoạt động của task goto_IDLE() |
5) Mô tả waveform của lệnh BYPASS
5.1) Nạp lệnh BYPASS
Quá trình nạp lệnh được thực hiện thông qua các trạng thái:
- SELECT_DR_SCAN
- SELECT_IR_SCAN
- CAPTURE_IR
- SHIFT_IR
- EXIT1_IR
- UPDATE_IR
Thông tin được hiển thị trên terminal hoặc cửa sổ transcript của QuestaSim.
# [send_IR] TAP state : SELECT_IR_SCAN
# [IR] TAP state : SHIFT_IR
# Load instruction: BYPASS
# [IR] TAP state : UPDATE_IR
# [IR] TAP state : RUN_TEST_IDLE
# [IR] capIr from TDO : 0101
# [IR] capAddr from TDO : xxxxxxxx
# [IR] capData from TDO : xxxxxxxxxxxxxxxxxx
# [IR] tapIr : 1111
# [IR] tapAddr : 00000000
# [IR] tapWData : 0000000000000000
# [IR] tapRData : 0000000000000000
# [END IR] ----------------------------------------
Thông tin cần chú ý là:
- Load instruction – Cho biết lệnh nào vừa được nạp cho JTAG
- [IR] capIr from TDO – Giá trị nhận được trên TDO
- [IR] tapir – Giá trị của thanh ghi lệnh ir_reg trong JTAG controller
Hình 4: Quá trình nạp lệnh BYPASS |
Lưu ý, thanh ghi ir_reg có giá trị là 4’hf (mã lệnh BYPASS) sau khi reset nên tại trạng thái UPDATE_IR, giá trị thanh ghi trên waveform không thay đổi.
5.2) Dịch dữ liệu thông qua thanh ghi BYPASS
Trong testbench này, 5 bit dữ liệu sẽ được dịch vào từ TDI, dữ liệu này sẽ được truyền đến TDO sau một chu kỳ xung clock TCK và theo cạnh xuống TCK.
Bit 17 của thanh ghi shift_dr_reg được sử dụng làm thanh ghi BYPASS. Số lượng bit được chọn dịch vào từ TDI là BIT_NUM=5 nên trên TDO chỉ nhận được 4 bit từ TDI, bit đầu tiên trên TDO là giá trị mặc định của thanh ghi BYPASS.
Hình 5: Quá trình dịch dữ liệu từ TDI đến TDO thông qua thanh ghi BYPASS, shift_dr_reg[17] |
Kết quả hiện thị trên terminal:
# [send_DR] TAP state : SELECT_DR_SCAN# [DR] TAP state : SHIFT_DR# Shift DATA in BYPASS# [DR] TAP state : UPDATE_DR# [DR] TAP state : RUN_TEST_IDLE
# [DR] capIr from TDO : 0101
# [DR] capAddr from TDO : xxxxxxxx# [DR] capData from TDO : 10100xxxxxxxxxxxxx# [DR] tapIr : 1111# [DR] tapAddr : 00000000# [DR] tapWData : 0000000000000000# [DR] tapRData : 0000000000000000# [END DR] ----------------------------------------
Thông tin cần chú ý là:
- Shift DATA in BYPASS – cho biết quá trình dịch dữ liệu đang thực hiện trong lệnh BYPASS
- [DR] capData from TDO – các giá trị nhận được từ TDO. Trong chuỗi 10100 thì chỉ 4 bit MSB 1010 là các bit từ TDI, còn bit LSB là giá trị mặc định của thanh ghi BYPASS.
- [DR] tapIr - Cho biết mã lệnh hiện tại trong thanh ghi lệnh ir_reg là BYPASS
6.1) Nạp lệnh SET_ADDR
Mã lệnh 4’b1110 được nạp vào thanh ghi lệnh ir_reg. Từng bit lệnh được dịch vào trong trạng thái SHIFT_IR và lệnh được cập nhật vào thanh ghi ir_reg ở trạng thái UPDATE_IR.
Thông tin được hiện thị trên terminal khi quá trình này thực thi xong gồm:
# [send_IR] TAP state : SELECT_IR_SCAN
# [IR] TAP state : SHIFT_IR
# Load instruction: SET_ADDR
# [IR] TAP state : UPDATE_IR
# [IR] TAP state : RUN_TEST_IDLE
# [IR] capIr from TDO : 0101
# [IR] capAddr from TDO : xxxxxxxx
# [IR] capData from TDO : 10100xxxxxxxxxxxxx
# [IR] tapIr : 1110
# [IR] tapAddr : 00000000
# [IR] tapWData : 0000000000000000
# [IR] tapRData : 0000000000000000
# [END IR] ----------------------------------------
Các thông tin cần chú ý là:
- Load instruction – thông báo lệnh SET_ADDR vừa được nạp cho JTAG controller
- [IR] capIr from TDO – giá trị nhận được từ TDO đúng như mô tả thiết kế
- [IR] tapIr – Mã lệnh hiện tại trong thanh ghi lệnh ir_reg của JTAG controller
Hình 6: Quá trình nạp mã lệnh SET_ADDR |
6.2) Nạp địa chỉ cần truy xuất
Địa chỉ 8’h03 sẽ được gửi đến JTAG thông qua TDI. Địa chỉ này sẽ được dịch vào shift_dr_reg[17:10], nhóm bit này được tách riêng thành tín hiệu shift_addr[7:0] để dễ quan sát.
Tại trạng thái UPDATE_DR, giá trị địa chỉ từ thành ghi dịch sẽ được nạp vào thanh ghi địa chỉ addr_reg.
Hình 7: Nạp địa chỉ truy xuất bộ nhớ cho JTAG |
Kết quả hiển thị trên terminal:
# [send_DR] TAP state : SELECT_DR_SCAN
# [DR] TAP state : SHIFT_DR
# Shift Address in SET_ADDR
# [DR] TAP state : UPDATE_DR
# [DR] TAP state : RUN_TEST_IDLE
# [DR] capIr from TDO : 0101
# [DR] capAddr from TDO : 00000000
# [DR] capData from TDO : 10100xxxxxxxxxxxxx
# [DR] tapIr : 1110
# [DR] tapAddr : 00000011
# [DR] tapWData : 0000000000000000
# [DR] tapRData : 0000000000000000
# [END DR] ----------------------------------------
Thông tin cần chú ý gồm:
- Shift Address in SET_ADDR – Thông báo đã thực hiện quá trình nạp địa chỉ trong lệnh SET_ADDR
- [DR] capAddr from TDO – Giá trị nhận được từ TDO, trong lần đầu tiên (sau khi reset), giá trị nhận được là 8’h00 nhưng từ lần nạp địa chỉ tiếp theo, đây sẽ là giá trị địa chỉ đã được dùng trước đó. Ví dụ, lần nạp địa chỉ mới tiếp theo, giá trị nhận được trên TDO sẽ là 8’h03.
- [DR] tapAddr – Địa chỉ đã được nạp trong thanh ghi addr_reg của JTAG
7) SET_DATA
7.1) Gửi lệnh SET_DATA
Tương tự như BYPASS và SET_ADDR, lệnh SET_DATA được gửi trong quy trình xử lý lệnh của FSM.
Trong waveform, 4 bit mã lệnh 4’b1100 được lấy mẫu từ TDI vào thanh ghi dịch shift_ir_reg trong trạng thái SHIFT_IR trước khi lưu đến thanh ghi lệnh ir_reg trong trạng thái UPDATE_IR.
Hình 8: Quá trình gửi mã lệnh SET_DATA |
Kết quả hiện thị trên terminal
# [send_IR] TAP state : SELECT_IR_SCAN
# [IR] TAP state : SHIFT_IR
# Load instruction: SET_DATA
# [IR] TAP state : UPDATE_IR
# [IR] TAP state : RUN_TEST_IDLE
# [IR] capIr from TDO : 0101
# [IR] capAddr from TDO : 00000000
# [IR] capData from TDO : 10100xxxxxxxxxxxxx
# [IR] tapIr : 1100
# [IR] tapAddr : 00000011
# [IR] tapWData : 0000000000000000
# [IR] tapRData : 0000000000000000
# [END IR] ----------------------------------------
Thông tin cần chú ý:
- Load instruction – Mã lệnh đã được gửi cho JTAG
- [IR] capIr from TDO – Giá trị nhận được từ TDO phải là 4’b0101 như yêu cầu thiết kế
- [IR] tapIr – Giá trị mã lệnh trong thanh ghi ir_reg là 4'b1100
7.2) Gửi yêu cầu ghi (WRITE)
Yêu cầu ghi bộ nhớ được gửi trong quy trình xử lý dữ liệu của FSM. Đối với một yêu cầu ghi, 18 bit dữ liệu gồm 16 bit dữ liệu ghi và 2 bit mã yêu cầu ghi (2’b10) phải được gửi trên TDI. Testbench này sẽ gửi chuỗi dữ liệu sau cho JTAG:
dr = 18'b01111110_10000001_10
Trong trạng thái SHIFT_DR, hai bit của mã yêu cầu WRITE sẽ được nhận đầu tiên từ TDI. Tiếp theo, 16 bit dữ liệu ghi được nhận.
Hai tín hiệu shift_wdata=shift_dr_reg[17:2] và shift_req_code=shift_dr_reg[1:0] được tạo ra để giúp dễ quan sát kết quả.
Trong trạng thái UPDATE_DR, dữ liệu ghi được lưu vào thanh ghi wdata_reg. Đồng thời, jtag_ctrl tích cực tín hiệu sel=1 và lái các tín hiệu điều khiển we=1, addr và wdata để yêu cầu mem_ctrl thực thi ghi bộ nhớ.
Sau khi phát hiện yêu cầu ghi từ jtag_ctrl, mem_ctrl sẽ kéo ready=0 và bắt đầu quá trình ghi bộ nhớ. Chú ý, ready hoạt động theo clock clk, bất đồng bộ với clock TCK.
Hình 9: Quá trình nhận yêu cầu WRITE và tích cực các tín hiệu điều khiển mem_ctrl |
# [send_DR] TAP state : SELECT_DR_SCANThông tin cần quan tâm
# [DR] TAP state : SHIFT_DR
# Load request WRITE in SET_DATA
# [DR] TAP state : UPDATE_DR
# [DR] TAP state : RUN_TEST_IDLE
# [DR] capIr from TDO : 0101
# [DR] capAddr from TDO : 00000000
# [DR] capData from TDO : 000000000000000010
# [DR] tapIr : 1100
# [DR] tapAddr : 00000011
# [DR] tapWData : 0111111010000001
# [DR] tapRData : 0000000000000000
# [END DR] ----------------------------------------
- Load request WRITE – yêu cầu ghi được gửi đến JTAG
- [DR] capData from TDO – Nếu 2 bit cuối là 2’b10, ứng với mã OKAY thì yêu cầu ghi chắc chắn sẽ được thực hiện. Nếu 2 bit cuối là 2’b01, ứng với mã BUSY, thì yêu cầu ghi chưa chắc được thực hiện.
- [DR] tapAddr – Địa chỉ của yêu cầu WRITE
- [DR] tapWData – Dữ liệu ghi trong thanh ghi wdata_reg
Sau khi nhận một yêu cầu ghi, cuối trạng thái UPDATE_DR, hoạt động ghi được thực thi như sau:
1. jtag_ctrl gửi yêu cầu ghi cho mem_ctrl thôn qua các tín hiệu sel, we, addr và wdata
2. mem_ctrl nhận yêu cầu từ jtag_ctrl sẽ lái ready=0 và gửi yêu cầu ghi đến bộ nhớ thông qua các tín hiệu mem_sel, mem_we, mem_addr và mem_wdata.
3. mem_model sẽ sẽ tích cực tín hiệu inWe sau khoảng thời gian Twrite để lưu lại dữ liệu ghi
4. mem_ctrl thôi tích cực mem_sel sau một số chu kỳ xung clock clk đã được thiết lập trong ACC_DELAY
5. jtag_ctrl lái sel=0 để kết thúc một quá trình bắt tay giữa jtag_ctrl và mem_ctrl cho một yêu cầu ghi
Trong khi sel=1, quá trình ghi bộ nhớ đang được thực thi, một yêu cầu CHECK được gửi đến JTAG trong lúc quá trình ghi đang được thực hiện nên thanh ghi shift_dr_reg sẽ cập nhật mã BUSY vào shift_dr_reg[1:0]=2’b01 và 16 bit dữ liệu ghi vào shift_dr_reg[17:2]=16’b 0111111010000001 để gửi ra TDO.
Hình 10: Quá trình ghi bộ nhớ |
# [send_DR] TAP state : SELECT_DR_SCANThông tin cần chú ý
# [DR] TAP state : SHIFT_DR
# Load request CHECK in SET_DATA
# [DR] TAP state : UPDATE_DR
# [DR] TAP state : RUN_TEST_IDLE
# [DR] capIr from TDO : 0101
# [DR] capAddr from TDO : 00000000
# [DR] capData from TDO : 011111101000000101
# [DR] tapIr : 1100
# [DR] tapAddr : 00000011
# [DR] tapWData : 0111111010000001
# [DR] tapRData : 0000000000000000
# [END DR] ----------------------------------------
- Load request CHECK – Một yêu cầu CHECK đã được gửi đến JTAG
- [DR] capData from TDO – Dữ liệu nhận được từ JTAG, 16 bit MSB là dữ liệu ghi gần nhất, 2 bit LSB là mã trạng thái. “01” ứng với BUSY.
Kết quả hiện thị trên terminal khi JTAG trả về mã OKAY cho một yêu cầu ghi.
# [send_DR] TAP state : SELECT_DR_SCANThông tin cần chú ý
# [DR] TAP state : SHIFT_DR
# Load request CHECK in SET_DATA
# [DR] TAP state : UPDATE_DR
# [DR] TAP state : RUN_TEST_IDLE
# [DR] capIr from TDO : 0101
# [DR] capAddr from TDO : 00000000
# [DR] capData from TDO : 011111101000000110
# [DR] tapIr : 1100
# [DR] tapAddr : 00000011
# [DR] tapWData : 0111111010000001
# [DR] tapRData : 0000000000000000
# [END DR] ----------------------------------------
- Load request CHECK – Yêu cầu kiểm tra trạng thái
- [DR] capData from TDO – Hai bit LSB “10” ứng với mã trạng thái là OKAY
Trong lệnh SET_DATA, một yêu cầu đọc được gửi bằng cách dịch 18 bit với 2 bit LSB chứa mã lệnh READ (2’b01). 16 bit MSB là giá trị bất kỳ vì đây là các bit không sử dụng.
Trong trạng thái SHIFT_DR, hai bit mã yêu cầu READ được nhận trên TDI đầu tiên. Sau 18 lần dịch, mã yêu cầu READ sẽ lưu ở 2 bit LSB của thanh ghi dịch shift_dr_reg. Mã này có thể được quan sát qua tín hiệu trung gian shift_req_code.
Trong trạng thái UPDATE_DR, yêu cầu READ được xác nhận và thực thi. jtag_ctrl tích cực sel=1 và we=0 để yêu cầu mem_ctrl đọc bộ nhớ.
Hình 11: Quá trình gửi một yêu cầu READ |
Kết quả hiện thị
trên terminal
# [send_DR] TAP state : SELECT_DR_SCAN
# [DR] TAP state : SHIFT_DR
# Load request READ in SET_DATA# [DR] TAP state : UPDATE_DR
# [DR] TAP state : RUN_TEST_IDLE
# [DR] capIr from TDO : 0101
# [DR] capAddr from TDO : 00000000
# [DR] capData from TDO : 011111101000000110# [DR] tapIr : 1100
# [DR] tapAddr : 00000011
# [DR] tapWData : 0111111010000001
# [DR] tapRData : 0000000000000000
# [END DR] ----------------------------------------
Thông tin cần chú ý
- Load request READ – Thông báo một yêu cầu READ vừa được gửi đến JTAG
- [DR] capData from TDO – Nếu hai bit LSB là “10”, ứng với mã trạng thái OKAY, thì READ đã được nhận và chắc chắn được thực thi. Nếu hai bit LSB là “01”, ứng với mã trạng thái BUSY, thì READ chưa chắc được thực thi.
7.5) Quá trình đọc bộ nhớ
Sau khi gửi mã yêu cầu READ, các yêu cầu CHECK phải được gửi đến JTAG để lấy dữ liệu cần đọc. Dữ liệu đọc chỉ hợp lệ khi mã trạng thái trả về từ JTAG là OKAY.
Quá trình đọc bộ nhớ thực thi như sau:
1. jtag_ctrl gửi yêu cầu đọc cho mem_ctrl với sel=1, we=0
2. mem_ctrl nhận yêu cầu READ, lái ready=0 và gửi yêu đọc đến mem_model bằng cách lái mem_sel=1, mem_we=0
3. Sau thời gian Ttrans, mem_model trả dữ liệu đọc trên mem_rdata=16’h7e81
4. Sau ACC_DELAY chu kỳ xung clock clk, mem_ctrl kết thúc quá trình đọc bằng cách lái mem_sel=0. Dữ liệu đọc được lưu lại và đưa đến rdata=16’h7e81 khi ready=1.
5. jtag_ctrl phát hiện ready=1 sẽ lái sel=0, kết thúc một yêu cầu READ. Đồng thời, dữ liệu đọc được lưu lại trong thanh ghi rdata_reg=16’h7e81
Khi quá trình đọc đang được thực thi, một yêu cầu CHECK được gửi đến JTAG. Mã trạng thái BUSY (2’b01) và giá trị thanh ghi rdata_reg hiện tại được nạp cho thanh ghi dịch shift_dr_reg để dịch ra TDO.
Sau khi gửi mã yêu cầu READ, các yêu cầu CHECK phải được gửi đến JTAG để lấy dữ liệu cần đọc. Dữ liệu đọc chỉ hợp lệ khi mã trạng thái trả về từ JTAG là OKAY.
Quá trình đọc bộ nhớ thực thi như sau:
1. jtag_ctrl gửi yêu cầu đọc cho mem_ctrl với sel=1, we=0
2. mem_ctrl nhận yêu cầu READ, lái ready=0 và gửi yêu đọc đến mem_model bằng cách lái mem_sel=1, mem_we=0
3. Sau thời gian Ttrans, mem_model trả dữ liệu đọc trên mem_rdata=16’h7e81
4. Sau ACC_DELAY chu kỳ xung clock clk, mem_ctrl kết thúc quá trình đọc bằng cách lái mem_sel=0. Dữ liệu đọc được lưu lại và đưa đến rdata=16’h7e81 khi ready=1.
5. jtag_ctrl phát hiện ready=1 sẽ lái sel=0, kết thúc một yêu cầu READ. Đồng thời, dữ liệu đọc được lưu lại trong thanh ghi rdata_reg=16’h7e81
Khi quá trình đọc đang được thực thi, một yêu cầu CHECK được gửi đến JTAG. Mã trạng thái BUSY (2’b01) và giá trị thanh ghi rdata_reg hiện tại được nạp cho thanh ghi dịch shift_dr_reg để dịch ra TDO.
Hình 12: Quá trình đọc bộ nhớ và kiểm tra trạng thái đọc |
# [send_DR] TAP state : SELECT_DR_SCANThông tin cần chú ý
# [DR] TAP state : SHIFT_DR
# Load request CHECK in SET_DATA
# [DR] TAP state : UPDATE_DR
# [DR] TAP state : RUN_TEST_IDLE
# [DR] capIr from TDO : 0101
# [DR] capAddr from TDO : 00000000
# [DR] capData from TDO : 000000000000000001
# [DR] tapIr : 1100
# [DR] tapAddr : 00000011
# [DR] tapWData : 0111111010000001
# [DR] tapRData : 0111111010000001
# [END DR] ----------------------------------------
- Load request CHECK – Một yêu cầu CHECK đã gửi cho JTAG
- [DR] capData from TDO – Giá trị 2 bit LSB, mã trạng thái quyết định tính hợp lệ của dữ liệu đọc. Trường hợp này, hai bit LSB bằng “01” (BUSY) nên 16 bit MSB là giá trị không hợp lệ
- [DR] tapRData – Dữ liệu đọc chứa trong thanh ghi rdata_reg của JTAG. Trường hợp này, rdata_reg=16’b0111111010000001=16’h7e81 là dữ liệu đọc đúng nhưng chưa được dịch ra TDO ở yêu cầu CHECK hiện tại
Trong waveform dưới đây, tại CAPTURE_DR, JTAG nạp 16 bit dữ liệu từ rdata_reg và 2 bit trạng thái OKAY đến shift_dr_reg để dịch ra TDO.
Hình 13: Một yêu cầu CHECK có mã trạng thái là OKAY |
# [send_DR] TAP state : SELECT_DR_SCANThông tin cần chú ý
# [DR] TAP state : SHIFT_DR
# Load request CHECK in SET_DATA
# [DR] TAP state : UPDATE_DR
# [DR] TAP state : RUN_TEST_IDLE
# [DR] capIr from TDO : 0101
# [DR] capAddr from TDO : 00000000
# [DR] capData from TDO : 011111101000000110
# [DR] tapIr : 1100
# [DR] tapAddr : 00000011
# [DR] tapWData : 0111111010000001
# [DR] tapRData : 0111111010000001
# [END DR] ----------------------------------------
- Load request CHECK – Một yêu cầu CHECK đã gửi cho JTAG
- [DR] capData from TDO – Dữ liệu đọc và mã trạng thái gửi từ JTAG. Trong trường hợp này 2 bit LSB là “10” thể hiện trạng thái OKAY. Điều này nghĩa là 16 bit MSB “0111111010000001”là dữ liệu đọc hợp lệ.
Bài viết này đã giải thích hoạt động của thiết kế ở bài 5 trên waveform cụ thể với một testbench đơn giản. Bạn đọc có thể tải source code trên Github dưới bài viết đề tham khảo.
Dữ liệu có thể tải:
Lịch sử cập nhật:
1) 2019.11.20 - Tạo lần đầu
0 bình luận:
Đăng nhận xét