このアプリケーションノートでは、MAXQ2000用JTAGブートローダマスタの実装に当たって必要になる基本的な手順について説明します。この手順には、JTAGポートへのインタフェース、Test Access Port (TAP)コントローラとの通信、ブートローダモードの有効化、およびROMベースのブートローダへのコマンドの送信が含まれます。JTAGポートの動作は一般的にすべてのMAXQデバイスで同一であり、MAXQブートローダは共通のコマンドセットを使って動作するため、このアプリケーションノートで取り上げる話題のほとんどは(そしてサンプルコードの大部分も)、どのMAXQマイクロコントローラ用にJTAGブートローダマスタを実装する場合にも該当します。
マスタ側のMAXQ2000のEVキットには、試作用エリアに2 x 5ピンのヘッダを装着するという変更を加えました。これによって、JTAGケーブル接続のマスタ側を提供しています。ヘッダ上のピンは標準的なMAXQのJTAGヘッダレイアウトにしたがっており、表1に示した接続になっています。
表1. MAXQ2000のJTAG接続
JTAG Header Pin
JTAG Cable Function
MAXQ2000 JTAG Master Connection
MAXQ2000 JTAG Slave Connection
1
TCK (Test Clock)
P0.0 (Output)
P4.0 (Input)
2
GND
GND
GND
3
TDO (Test Data Out)
P0.1 (Input)
P4.3 (Output)
4
VREF
–
–
5
TMS (Test Mode Select)
P0.2 (Output)
P4.2 (Input)
6
nRESET
P0.4 (Open Drain)
nRESET (Input)
7
Keyed pin
–
–
8
+5V
–
–
9
TDI (Test Data In)
P0.3 (Output)
P4.1 (Input)
10
GND
GND
GND
スレーブ側のMAXQ2000のEVキットには何も変更を加える必要がありません。マスタ側のMAXQ2000のEVキットは、試作用エリアに2 x 5のJTAGヘッダを装着して前述の通りに配線します。そして、2組のEVキットを接続します。マスタ側EVキット上の試作用エリアに装着した2 x 5 JTAGヘッダと、スレーブ側のEVキット上の標準JTAGヘッダ(J4)の間を、標準の2 x 5 JTAGケーブル(一般的にシリアル/JTAG変換ボードとMAXQのEVキットとの接続に使用されるタイプのJTAGケーブル)で接続します。このJTAG 2 x 5コネクタは、MAXQ2000のEVキットに同梱されています。
MAXQマイクロコントローラのJTAGインタフェースは、Test Access Port (TAP)コントローラに対する情報のシフトイン/シフトアウトに使用する4本の信号線で構成されています。そしてこのTAPコントローラが、MAXQのブートローダおよびインサーキットデバッグ機能へのアクセスを提供します(デバッグマスタの実装は、ブートローダマスタの実装と似ていますが、このアプリケーションノートの範囲外のことです)。4本のJTAG信号線を表3に示します。
IR (Instruction Register:命令レジスタ)は、常に3ビット幅です。このレジスタはインデックスレジスタとして機能し、それがさらにDRの機能を制御します(後述)。
DR (Data Register:データレジスタ)は、TAPコントローラ内に複数存在するレジスタの1つに対するアクセスポイントになります。DRに対するビットの入出力に当たって実際にアクセスされるレジスタは、IRの現在の値によって決まります。
図3. TAPコントローラのレジスタアクセス
図3に示すように、DRはIRの値に応じて3個の内部レジスタの1つを指します。
IR = 011bのとき、TAPコントローラはバイパスモードです。このモード(=TAPコントローラのデフォルトのモード)では、(TDIを通して)DRにシフトインされたデータが、単純にTDOを通して再びシフトアウトされます。TAPコントローラを通ってシフトされるデータによって変更される内部レジスタはありません。
IR = 100bにセットすると、TAPコントローラはシステムプログラミングモードになります。このモードでは、DRにシフトインされるデータが3ビットのシステムプログラミングレジスタにシフトインされます。このレジスタ(MAXQマイクロコントローラからはICDFレジスタのビット[3:1]という形でアクセス可能)は、リセット後にMAXQが通常のプログラム実行モードに入るかブートローダモードに入るかを制御します。ブートローダモードを有効化する場合、ブートローダがどのインタフェース(JTAG、シリアル、またはSPI)を使用するかの制御も行います。
IR = 010bにセットすると、TAPコントローラはデバッグモードになります。このモードでは、DRにシフトインされたデータが、ブートローダから読出し可能な内部の10ビットデバッグレジスタにシフトインされます。ブートローダから出力されるデータも(2ビットのステータスビットと一緒に)このレジスタを通してシフトアウトされ、そこからTDOを通して出力されます。このレジスタは、ブートローダモードとインサーキットデバッグモードの両方でデータの転送に使用されます。
;==============================================================================
;=
;= shift
;=
;= In a shift register state, clocks in a TDI bit and clocks out a TDO bit.
;=
;= Inputs : C - Bit to shift in to TDI.
;= Outputs : C - Bit shifted out from TDO.
;= Destroys : PSW, LC[0]
;=
shift:
jump C, shift_bit1
shift_bit0:
move TDI, #0 ; Shift in zero bit
jump shift_bitEnd
shift_bit1:
move TDI, #1 ; Shift in one bit
jump shift_bitEnd
shift_bitEnd:
move LC[0], #JCLOCK
djnz LC[0], $
move TCK, #1 ; Rising edge, TDI is sampled
move LC[0], #JCLOCK
djnz LC[0], $
move TCK, #0 ; Falling edge, TDO is driven out
move LC[0], #JCLOCK
djnz LC[0], $
move C, TDO ; Latch TDO value
ret
;==============================================================================
;=
;= shiftIR3
;= clock0, clock1, shift
;=
;= Shifts a 3-bit value into the IR register.
;=
;= Inputs : A[0] - Low three bits contain value to shift into IR
;= Outputs : None
;= Destroys : AP, APC, A[0], PSW, LC[0]
;=
shiftIR3:
move APC, #80h ; Acc => A[0], turn off auto inc/dec
call clock1 ; (Select DR Scan)
call clock1 ; (Select IR Scan)
call clock0 ; (Capture IR - loads 001b to shift register)
call clock0 ; (Shift IR)
move TMS, #0 ; Drive TMS low
move C, TDO ; xxxxx210 c = s
rrc ; sxxxxx21 c = 0
call shift ; Shift in IR bit 0
rrc ; ssxxxxx2 c = 1
call shift ; Shift in IR bit 1
rrc ; sssxxxxx c = 2
move TMS, #1 ; Drive TMS high for last bit
call shift ; Shift in IR bit 2 (Exit1 IR)
call clock1 ; (Update IR)
call clock0 ; (Run Test Idle)
ret
;==============================================================================
;=
;= shiftDR3
;=
;= Shifts a 3-bit value into the DR register. This operation should only be
;= performed when IR =100b (System Programming Mode).
;=
;= Inputs : A[0] - Low 3 bits contain value to shift into SPB (PSS1:PSS0:SPE)
;= Outputs : None
;= Destroys : AP, APC, A[0], PSW, LC[0]
shiftDR3:
move APC, #80h ; Acc => A[0], turn off auto inc/dec
call clock1 ; (Select DR Scan)
call clock0 ; (Capture DR)
call clock0 ; (Shift DR)
move TMS, #0 ; Drive TMS low
move C, TDO ; xxxxx210 c = s
rrc ; sxxxxx21 c = 0
call shift ; Shift in DR bit 0
rrc ; ssxxxxx2 c = 1
call shift ; Shift in DR bit 1
rrc ; sssxxxxx c = 2
move TMS, #1 ; Drive TMS high for last bit
call shift ; Shift in DR bit 2 (Exit1 DR)
call clock1 ; (Update DR)
call clock0 ; (Run Test Idle)
ret
;==============================================================================
;=
;= shiftDR
;= clock0, clock1, shift
;=
;= Shifts a 10-bit value into and out of the DR register. This operation
;= should only be performed when IR = 010b (Debug/Loader Mode).
;=
;= Inputs : A[0] - Byte value (input) to shift into DR
;= Outputs : A[0] - Byte value (output) shifted out of DR
;= A[1] - Low two bits are status bits 1:0 shifted out of DR
;= A[15] - Byte value shifted in, cached for use by shiftDR_next
;= Destroys : AP, APC, PSW, LC[0]
shiftDR:
move APC, #80h ; Acc => A[0], turn off auto inc/dec
move A[15], A[0] ; Cache input byte value for use by shiftDR_next
sla2 ; Add two empty bits (for status)
call clock1 ; (Select DR Scan)
call clock0 ; (Capture DR)
call clock0 ; (Shift DR)
move TMS, #0 ; Drive TMS low
move C, TDO ; xxxxxxxx76543210 c = s
rrc
call shift ; Shift in DR bit 0
rrc
call shift ; Shift in DR bit 1
rrc
call shift ; Shift in DR bit 2
rrc
call shift ; Shift in DR bit 3
rrc
call shift ; Shift in DR bit 4
rrc
call shift ; Shift in DR bit 5
rrc
call shift ; Shift in DR bit 6
rrc
call shift ; Shift in DR bit 7
rrc
call shift ; Shift in DR bit 8
rrc
move TMS, #1 ; Drive TMS high for last bit
call shift ; Shift in DR bit 9 (Exit1 DR)
call clock1 ; (Update DR)
call clock0 ; (Run Test Idle)
push Acc ; sddd dddd 10xx xxxx
sra4 ; ssss sddd dddd 10xx
sra2 ; ssss sssd dddd dd10
and #0003h ; ---- ---- ---- --10
move A[1], Acc ; Return status bits only in A[1]
pop Acc
and #0FF00h
xch ; Return data bits only in A[0]
ret
;==============================================================================
;=
;= sendCommand
;=
;= Transmits a loader command by shifting bytes through DR.
;=
;= Inputs : DP[0] - Points to area of RAM which stores input bytes
;= for command and which will be filled with output.
;= LC[1] - Number of bytes to transmit/receive
;= Outputs : C - Set on JTAG communication error
;= Destroys : AP, APC, A[0], A[1], A[2], A[15], PSW, LC[0]
;=
sendCommand:
move APC, #80h ; Acc => A[0], turn off auto inc/dec
push LC[1]
call waitForPrompt
pop LC[1]
jump C, sendCommand_fail
move Acc, @DP[0] ; Read first byte to transmit
call shiftDR
push Acc
move Acc, A[1]
cmp #3 ; Should be valid status since we had a prompt
pop Acc
jump NE, sendCommand_fail
move @DP[0], Acc ; Store first received byte
move NUL, @DP[0]++ ; Increment data pointer
djnz LC[1], sendCommand_loop
jump sendCommand_pass
sendCommand_loop:
move A[2], #10 ; Number of retries allowed
sendCommand_retry:
move Acc, @DP[0] ; Get next byte to transmit
call shiftDR_next
push Acc
move Acc, A[1]
cmp #3
pop Acc
jump NE, sendCommand_stall
move @DP[0], Acc ; Store received byte
move NUL, @DP[0]++ ; Increment data pointer
djnz LC[1], sendCommand_loop
jump sendCommand_pass
sendCommand_stall:
move LC[0], #8000 ; About a millisecond
djnz LC[0], $
move Acc, A[2]
sub #1
jump NZ, sendCommand_retry
jump sendCommand_fail
MAXQマイクロコントローラ上のTAPコントローラを使用して、そのマイクロコントローラをJTAGローダモードに移行させたら(この過程はすべてのMAXQマイクロコントローラで同一です)、その後の最初のステップとして、ローダから応答があるかどうかを判定します。これを最も迅速に行う方法は、ブートローダコマンドコード00h (No Operation)を繰り返し転送することです。各ブートローダコマンドの完了後、ブートローダは応答としてプロンプト(「>」、すなわち3Eh)バイトを出力します。00hを転送したときに応答として3Ehが返ってくれば、ブートローダが動作中でありコマンドの受け入れ準備ができていることを示します。
表5. MAXQの全般的なブートローダコマンドファミリ
Bit 7
Bit 6
Bit 5
Bit 4
Bit 3
Bit 2
Bit 1
Bit 0
Code
Family/Command
0
0
0
0
x
x
x
x
0 x h
Family 0—Informational Commands
0
0
0
0
0
0
0
0
00h
No Operation
0
0
0
1
01h
Exit Loader
0
0
1
0
02h
Master Erase
0
0
1
1
03h
Password Match
0
1
0
0
04h
Get Status
0
1
0
1
05h
Get Supported Commands
0
1
1
0
06h
Get Code Memory Size
0
1
1
1
07h
Get Data Memory Size
1
0
0
0
08h
Get Loader Version
1
0
0
1
09h
Get Utility ROM Version
1
0
1
0
0Ah
Set Word/Byte Access Mode
1
1
0
1
0Dh
Get ID Information
0
0
0
1
x
x
x
x
1 x h
Family 1—Variable-Length Load
0
0
0
1
0
0
0
0
10h
Load Code Variable Length
0
0
0
1
0
0
0
1
11h
Load Data Variable Length
0
0
1
0
x
x
x
x
2 x h
Family 2—Variable-Length Dump
0
0
1
0
0
0
0
0
20h
Dump Code Variable Length
0
0
1
0
0
0
0
1
21h
Dump Data Variable Length
0
0
1
1
x
x
x
x
3 x h
Family 3—Variable-Length CRC
0
0
1
1
0
0
0
0
30h
CRC Code Variable Length
0
0
1
1
0
0
0
1
31h
CRC Data Variable Length
0
1
0
0
x
x
x
x
4 x h
Family 4—Variable-Length Verify
0
1
0
0
0
0
0
0
40h
Verify Code Variable Length
0
1
0
0
0
0
0
1
41h
Verify Data Variable Length
0
1
0
1
x
x
x
x
5 x h
Family 5—Variable-Length Load and Verify
0
1
0
1
0
0
0
0
50h
Load/Verify Code Variable Length
0
1
0
1
0
0
0
1
51h
Load/Verify Data Variable Length
0
1
1
0
x
x
x
x
6 x h
Family 6—Variable-Length Erase
0
1
1
0
0
0
0
0
60h
Erase Code Variable Length
0
1
1
0
0
0
0
1
61h
Erase Data Variable Length
0
1
1
1
x
x
x
x
7 x h
Family 7—Reserved (for expansion)
1
0
0
0
x
x
x
x
8 x h
Family 8—Reserved (for expansion)
1
0
0
1
x
x
x
x
9 x h
Family 9—Fixed-Length Load
1
0
0
1
0
0
0
0
90h
Load Code Fixed Length
1
0
0
1
0
0
0
1
91h
Load Data Fixed Length
1
0
1
0
x
x
x
x
A x h
Family A —Fixed-Length Dump
1
0
1
0
0
0
0
0
A0h
Dump Code Fixed Length
1
0
1
0
0
0
0
1
A1h
Dump Data Fixed Length
1
0
1
1
x
x
x
x
B x h
Family B—Fixed-Length CRC
1
0
1
1
0
0
0
0
B0h
CRC Code Fixed Length
1
0
1
1
0
0
0
1
B1h
CRC Data Fixed Length
1
1
0
0
x
x
x
x
C x h
Family C—Fixed-Length Verify
1
1
0
0
0
0
0
0
C0h
Verify Code Fixed Length
1
1
0
0
0
0
0
1
C1h
Verify Data Fixed Length
1
1
0
1
x
x
x
x
D x h
Family D—Fixed-Length Load and Verify
1
1
0
1
0
0
0
0
D0h
Load/Verify Code Fixed Length
1
1
0
1
0
0
0
1
D1h
Load/Verify Data Fixed Length
1
1
1
0
x
x
x
x
E x h
Family E —Fixed-Length Erase
1
1
1
0
0
0
0
0
E0h
Erase Code Fixed Length
1
1
1
0
0
0
0
1
E1h
Erase Data Fixed Length
1
1
1
1
x
x
x
x
F x h
Family F—Reserved (device specific)
JTAGスレーブ側マイクロコントローラの識別
ブートローダが動作を開始したら、次のステップはスレーブ側MAXQマイクロコントローラの識別です。ファミリ0コマンド0Dh (Get ID Information)は、デバイスとユーティリティROMのバージョンを識別する可変長ASCII文字列(ゼロ終端)を返します。
;==============================================================================
;=
;= getBanner
;= waitForPrompt
;= shiftDR
;= clock0, clock1, shift
;=
;= Executes command 0Dh to retrieve the ROM (device ID) banner and prints
;= the banner text out over the serial port.
;=
;= Inputs : None
;= Outputs : C - Set on JTAG communication error
;= Destroys : AP, APC, Acc, PSW, LC[0]
;=
getBanner:
call waitForPrompt
jump C, getBanner_fail
move Acc, #CMD_GET_ROM_BANNER
call shiftDR
move Acc, #00h
call shiftDR
getBanner_loop:
move Acc, #00h
call shiftDR
cmp #0FFh ; The banner is ASCII, so receiving this character
; most likely indicates that the JTAG lines are
; floating high and that no device is connected
jump E, getBanner_fail
jump Z, getBanner_done
call txChar
jump getBanner_loop
getBanner_done:
call txNewline
jump getBanner_pass
getBanner_fail:
move C, #1
ret
getBanner_pass:
move C, #0
ret