目次
前
次
リアルタイムモニタ移植
自作のリアルタイムモニタであるUSO
(Unvoiced Shadow Operating system)を
Z80に移植してみます。
USOは、すべてC言語で記述可能ですが
10msごとのタイマー割込みが必要と
なるのでモード2割込みを利用。
リアルタイムモニタは、高速なことが求められる
ので、ここではアセンブリ言語で記述します。
リアルタイムモニタは、タスクの状態を切替える
ことが仕事なので、タスクに関係する情報を格納
するエリア=TCBを使わずに処理。
ひとつのタスクに、ブロックエリアを割り当てしないで
3バイトの変数で管理します。
1バイトで管理できるのは8ビットとなるので、最大で
8タスクを管理します。
4タスクや5タスクの場合でも
ダミータスクを用意し8タスクに
します。
USOではタスクは、次の4状態のどれかになります。
- TTS_RUN
- TTS_READY
- TTS_SUSPEND
- TTS_WAIT
これらの状態は、システムコールを利用して
切り替えます。状態遷移は、下図に従います。
USOでは、WAIT状態は「時間待ち」としています。
「時間待ち」でない「待ち」はSUSPENDとします。
「時間待ち」は、10msのN倍(N=1~65535)とします。
ここまで仕様を決めると、ディスパッチャ、スケジューラ
は、次のような単純なアセンブリ言語コードになります。
TSK_ID0 EQU 0
TSK_ID1 EQU 1
TSK_ID2 EQU 2
TSK_ID3 EQU 3
TSK_ID4 EQU 4
TSK_ID5 EQU 5
TSK_ID6 EQU 6
TSK_ID7 EQU 7
call INIT_USR
call INIT_USO
; set pointer
ld hl,READY
ld ix,RUN_TSK
; set first task ID
xor a
ld (ix),a
; enable interrupt
ei
MAIN:
; 10ms handling
ld a,(XFLAGS)
; check WFALG
bit WFLAG,a
jr z,MAIN1
; update WCOUNTER
call THANDLER
; perform task
MAIN1:
; get READY
ld c,(hl)
; TASK0
bit TSK_ID0,c
call nz,TSK0_PROC
inc (ix)
; TASK1
bit TSK_ID1,c
call nz,TSK1_PROC
inc (ix)
; TASK2
bit TSK_ID2,c
call nz,TSK2_PROC
inc (ix)
; TASK3
bit TSK_ID3,c
call nz,TSK3_PROC
inc (ix)
; TASK4
bit TSK_ID4,c
call nz,TSK4_PROC
inc (ix)
; TASK5
bit TSK_ID5,c
call nz,TSK5_PROC
inc (ix)
; TASK6
bit TSK_ID6,c
call nz,TSK6_PROC
inc (ix)
; TASK7
bit TSK_ID7,c
call nz,TSK7_PROC
; return first state
xor a
ld (ix),a
;
jr MAIN
やっていることは、単純。
READYに保存されているタスク番号を取得して
対応するタスクにCPUを使わせます。該当する
タスクがREADYなら、ビット位置で1が入って
いると仕様を決めました。
USOでは、タスクは8個としているので
タスク0から7のタスク状態をスキャンし
READYならCPUを使わせます。
タスク動作は、サブルーチンとして記述。
タスク7の状態を調べ、対応処理を実行したなら
また、タスク0から状態を調べていきます。
タスク状態をスキャンするため、1バイト
の変数領域TSKNUMを利用。
タスク状態を調べる前に、タイマー割込みで10ms経過が
通知されていないかを調べています。
10ms経過は、フラグTFLAGの論理値で判定します。
フラグがセットされていると、10ms経過している
ので、タスクごとに用意してある、カウント値を
デクリメント。
カウント値が0になったタスクは、状態をWAITから
READYに遷移します。
システムコールは、以下の4種を用意。
- RSM_TSK
- SUS_TSK
- SLP_TSK
- WAI_TSK
アセンブリ言語では、コーリングシーケンスを
決めておかないと、CPUの暴走になります。
各システムコールのコーリングシーケンスを
逐次定義してみます。
RSM_TSK
システムコールRSM_TSKは、タスク番号を
指定して、状態をSUSPENDからREADYに遷移。
タスクの番号を与えます。
次のように番号を与えてからコール。
ld a,TSK_ID2
ld (GR0),a
call RSM_TSK
GR0からGR3の4バイトをシステムコールする場合に
使います。4バイトは、以下のように役割を決めて
あります。
- GR0 タスクID指定
- GR1 時間待ちカウンタの下位バイト
- GR2 時間待ちカウンタの上位バイト
- GR3 汎用
SUS_TSK
システムコールSUS_TSKは、タスク番号を
指定して、状態をREADYからSUSPENDに遷移。
タスクの番号を与えます。
次のように番号を与えてからコール。
ld a,TSK_ID4
ld (GR0),a
call SUS_TSK
SLP_TSK
システムコールSLP_TSKは、タスク自身が
状態をREADYからSUSPENDに遷移させます。
パラメータなし。
パラメータなしは、タスクの中でシステムコールを
使う前に設定しないでよいということでディパッチ
の担当部分では、RUN_TSKという変数でタスクIDを
管理します。
SLP_TSK
WAI_TSK
システムコールWAI_TSKは、タスク自身が
状態をREADYからWAITに遷移させます。
10msの倍数を与えます。
次のように番号を与えてからコール。
; set counter
ld de,400h
; lower
ld (GR1),e
; upper
ld (GR2),d
call SUS_TSK
コーリングシーケンスを定義したので、アセンブリ言語の
コードを定義します。
RSM_TSK
タスクIDをビット位置とみなして、変数READYの該当ビットをセット。
変数SUSPEND、WAITQの該当ビットをリセットして実現。
ビット位置でのセット状態は、次の8種。
01h 02h 04h 08h 10h 20h 40h 80h
これらをメモリ上にテーブルで用意しておき、それを
引出してきて、論理演算でREADY、SUSPEND、WAITQの
該当ビットの論理値を操作。
RSM_TSK:
; store
push af
push bc
push de
push hl
; get task ID
ld hl,GR0
ld a,(hl)
ld c,a
; get bit pattern
ld hl,BPAT
ld d,0
ld e,a
add hl,de
ld b,(hl)
; update READY (set target bit)
ld a,(READY)
or b
ld (READY),a
; update SUSPEND (reset target bit)
ld a,(SUSPEND)
xor b
ld (SUSPEND),a
; update WAITQ (reset target bit)
ld a,(WAITQ)
xor b
ld (WAITQ),a
; resume
pop hl
pop de
pop bc
pop af
;
ret
SUS_TSK
タスクIDをビット位置とみなして、変数SUSPENDの該当ビットをセット。
変数READY、WAITQの該当ビットをリセットして実現。
処理としては、RSM_TSKとほぼ同じで、該当ビットのセットを
変数SUSPENDにするだけ。
SUS_TSK:
; store
push af
push bc
push de
push hl
; get task ID
ld a,(GR0)
ld c,a
; get bit pattern
ld hl,BPAT
ld d,0
ld e,a
add hl,de
ld b,(hl)
; update READY (reset target bit)
ld a,(READY)
xor b
ld (READY),a
; update SUSPEND (set target bit)
ld a,(SUSPEND)
or b
ld (SUSPEND),a
; update WAITQ (reset target bit)
ld a,(WAITQ)
xor b
ld (WAITQ),a
; resume
pop hl
pop de
pop bc
pop af
;
ret
SLP_TSK
タスクIDが現在実行中のタスクなので、それを
RUN_TSKから引き出して、SUS_TSKをコールする
だけで実現可能。
すでに定義してあるシステムコールを利用して
手間を省きました。
SLP_TSK:
; store
push af
; get task ID
ld a,(RUN_TSK)
ld (GR0),a
;
call SUS_TSK
; resume
pop af
;
ret
WAI_TSK
タスクIDは、RUN_TSKでわかるので、GR1、GR2の2バイトに
下位、上位の順で入れられている値を、指定のエリアに転送
します。
時間待ちをするので、WCOUNTというエントリーラベルを使い
8ワード=16バイトの中の1ワードに値転送と考えました。
WAI_TSK:
; store
push af
push bc
push de
push hl
; get task ID
ld a,(RUN_TSK)
ld c,a
; get bit pattern
ld hl,BPAT
ld d,0
ld e,a
add hl,de
ld b,(hl)
; update READY (reset target bit)
ld a,(READY)
xor b
ld (READY),a
; update SUSPEND (reset target bit)
ld a,(SUSPEND)
xor b
ld (SUSPEND),a
; update WAITQ (set target bit)
ld a,(WAITQ)
or b
ld (WAITQ),a
; store counter
; get task ID
ld a,(RUN_TSK)
; x2
sla a
; set pointer
ld b,0
ld c,a
ld hl,WCOUNT
add hl,bc
; store
ld a,(GR1)
ld (hl),a
inc hl
ld a,(hl)
ld (hl),a
; resume
pop hl
pop de
pop bc
pop af
;
ret
タスクIDの値を2倍すると、WCOUNTからのオフセット値を
計算できることを使いました。
10msごとに、WCOUNT中の該当ワードをデクリメントする処理は
サブルーチンで、次のように定義。
THANDLER:
; store
push af
push bc
push de
push hl
push ix
; store task ID
xor a
ld (GR3),a
; get information
ld a,(WAITQ)
ld c,a
; set counter
ld b,1
THANDLER0:
; get WAITQ information
ld a,c
; judge
bit 0,a
jr z,THANDLER1
; set pointer
ld hl,WCOUNT
; get task ID and calculate offset
ld a,(GR3)
sla a
ld e,a
ld d,0
; calculate pointer
add hl,de
; exchange value
push hl
pop ix
; get counter value
ld l,(ix)
ld h,(ix+1)
; decrement
dec hl
; store counter value
ld (ix),l
ld (ix+1),h
; judge
ld a,l
cp h
jr nz,THANDLER1
cp 0
jr nz,THANDLER1
; update READY
ld a,(READY)
or b
ld (READY),a
; update SUSPEND
ld a,(SUSPEND)
xor b
ld (SUSPEND),a
; update WAITQ
ld a,(WAITQ)
xor b
ld (WAITQ),a
THANDLER1:
ld a,(GR3)
inc a
ld (GR3),a
srl c
sla b
jr c,THANDLER2
jr THANDLER0
THANDLER2:
; resume
pop ix
pop hl
pop de
pop bc
pop af
;
ret
変数WAITQの中の該当ビットが1かを判断し、1だったときに
変数WAITQの該当ビットを0に。変数READYの該当ビットを1に。
念のため、変数SUSPENDの該当ビットも0にしておきます。
USOは、μITRONのシステムコールを使っているので
タスクの登録と開始で、CRE_TSK、STA_TSKが必要に
なります。
TCB(Task Control Block)を用意していないので、モニタを
初期化するときに、変数READY、SUSPENDの値を指定する方式
で、タスクの登録と開始を代用してみました。
; set task state (READY)
; CRE_TSK , STA_TSK
; TSK7 TSK0
ld a,81h
ld (READY),a
; set task state (SUSPEND)
; CRE_TSK , STA_TSK
; TSK6 TSK5 TSK4 TSK3 TSK2 TSK1
cpl
ld (SUSPEND),a
変数READY、SUSPEND、WAITQの初期化や論理演算に使う
ビットパターンも必要なので、サブルーチンにまとめて
単純にしてあります。
INIT_USO:
; store
push af
push bc
push de
push hl
; clear
xor a
; clear READY
ld (READY),a
; clear SUSPEND
ld (SUSPEND),a
; clear WAITQ
ld (WAITQ),a
; generate bit battern
ld hl,BPAT
ld a,1
ld b,8
INIT_USO1:
ld (hl),a
sla a
inc hl
djnz INIT_USO1
; set task state (READY)
; CRE_TSK , STA_TSK
; TSK7 TSK0
ld a,81h
ld (READY),a
; set task state (SUSPEND)
; CRE_TSK , STA_TSK
; TSK6 TSK5 TSK4 TSK3 TSK2 TSK1
cpl
ld (SUSPEND),a
; resume
pop hl
pop de
pop bc
pop af
;
ret
タスクは、次のように記述します。
TSK3_PROC:
;
; ?
;
ret
USOでは、タスク内で無限ループは禁止です。
無限ループを使うと、他のタスクにCPUを渡せ
なくなります。
このリアルタイムモニタは、Z84C015を使った
ボードに実装することにします。
タイマー割込みは、Z80CTCを使いCTC3を10ms
のインターバル生成に利用します。
Z80ファミリを使うので、モード2割込みで
10msを生成します。
モード2割込みでは、レジスタIに割込み
ハンドラの上位8ビットを、下位8ビット
はZ80ファミリICから出力するので7F80に
割込みハンドラのエントリアドレスを置く
ことにします。
ターゲットのZ80CPUボードは、32kバイトの
ROMを載せられるので、割込みハンドラは
32kバイトの最後の128バイトに格納します。
割込みハンドラを次のように定義しました。
CTCxH:
; store
push af
push hl
; load counter
ld a,(XTIM)
; increment
inc a
; judge
cp 10
jr z,CTCxH1
; store counter
ld (XTIM),a
jr CTCxH2
CTCxH1:
; clear
xor a
; store counter
ld (XTIM),a
; set WFLAG
ld a,(XFLAGS)
set WFLAG,a
ld (XFLAGS),a
CTCxH2:
; resume
pop hl
pop af
;
ei
reti
割込み周期を2msとして、2msx5=10ms
ごとに、TFLAGをセット。
10msごとの判断に、カウンタICNTを
利用しています。
割込み、システムコールを利用した
簡単なRTOS対応のコードを作成して
動作テストしてみます。仕様は以下
としました。
ひとつのスイッチ、2つのLEDを基板に接続
スイッチを押すたびに、2つのLEDは個別周期で点滅
LED_0は、周期2秒で点滅
LED_1は、周期3秒で点滅
タイマー割込みを使えば、リアルタイムモニタを
採用するまでもないファームウエアですが、動作
テストのため、この仕様を決めました。
4つのタスクを用意し、各タスクの担当を
次のように機能割当てしています。
- タスク0 内部状態設定と3つのタスク管理
- タスク1 LED_0を周期2秒で点滅
- タスク2 LED_0を周期3秒で点滅
- タスク3 スイッチのチャタリング除去
ファームウエアのソースコードは、以下です。
;****************************
; USO test code
;****************************
STKT EQU 0a000h
TFLAG EQU 0
UFLAG EQU 1
EFLAG EQU 2
SFLAG EQU 3
WFLAG EQU 4
TSK_ID0 EQU 0
TSK_ID1 EQU 1
TSK_ID2 EQU 2
TSK_ID3 EQU 3
TSK_ID4 EQU 4
TSK_ID5 EQU 5
TSK_ID6 EQU 6
TSK_ID7 EQU 7
PACON EQU 54h
PBCON EQU 55h
PCCON EQU 56h
PDCON EQU 34h
PECON EQU 44h
PADAT EQU 50h
PBDAT EQU 51h
PCDAT EQU 53h
PDDAT EQU 30h
PEDAT EQU 40h
PAINIT EQU 00h ; inputs
PBINIT EQU 0ffh ; outputs
PCINIT EQU 0ffh ; outputs
PDINIT EQU 00h ; inputs
PEINIT EQU 00h ; inputs
CTC0 EQU 10h
CTC1 EQU 11h
CTC2 EQU 12h
CTC3 EQU 13h
;***************************
; startup routine
;***************************
org 0h
; set stack pointer
ld sp,STKT
xor a
ld i,a
im 2
jp START
org 50h
dw CTCxD
dw CTCxD
dw CTCxD
dw CTCxH
;***************************
; dispatch
;***************************
org 100h
START:
call INIT_USR
call INIT_USO
; set pointer
ld hl,READY
ld ix,RUN_TSK
; set first task ID
xor a
ld (ix),a
; enable interrupt
ei
MAIN:
; 10ms handling
ld a,(XFLAGS)
; check WFALG
bit WFLAG,a
jr z,MAIN1
; update WCOUNTER
call THANDLER
; perform task
MAIN1:
; get READY
ld c,(hl)
; TASK0
bit TSK_ID0,c
call nz,TSK0_PROC
inc (ix)
; TASK1
bit TSK_ID1,c
call nz,TSK1_PROC
inc (ix)
; TASK2
bit TSK_ID2,c
call nz,TSK2_PROC
inc (ix)
; TASK3
bit TSK_ID3,c
call nz,TSK3_PROC
inc (ix)
; TASK4
bit TSK_ID4,c
call nz,TSK4_PROC
inc (ix)
; TASK5
bit TSK_ID5,c
call nz,TSK5_PROC
inc (ix)
; TASK6
bit TSK_ID6,c
call nz,TSK6_PROC
inc (ix)
; TASK7
bit TSK_ID7,c
call nz,TSK7_PROC
; return first state
xor a
ld (ix),a
;
jr MAIN
;*****************************
; initialize user environment
;*****************************
INIT_USR:
; store
push af
; initialize CTC
call INIT_CTC
; initialize parallel I/O
ld a,PAINIT
ld c,PACON
out (c),a
;
ld a,PBINIT
ld c,PBCON
out (c),a
;
ld a,PCINIT
ld c,PCCON
out (c),a
;
ld a,PDINIT
ld c,PDCON
out (c),a
;
ld a,PEINIT
ld c,PECON
out (c),a
; clear flags
xor a
ld (XFLAGS),a
; clear counter
ld (XTIM),a
; resume
pop af
;
ret
;*****************************
; initialize CTC
;*****************************
INIT_CTC:
; store
push af
push bc
; put CTC interrupt vector
ld a,50h ; xx50h
out (CTC0),a
; channel 0 control word
ld a,37h
out (CTC0),a
; channel 0 time constant
ld a,128
out (CTC0),a
; channel 1 control word
ld a,37h
out (CTC1),a
; channel 1 time constant
xor a
out (CTC1),a
; update pointer
inc c
; channel 2 control word
ld a,17h
out (CTC2),a
; channel 2 time constant
xor a
out (CTC2),a
; update pointer
inc c
; channel 3 control word
ld a,0b7h
out (CTC3),a
; channel 3 time constant
; generate 1ms interrupt
ld a,15
out (CTC3),a
; resume
pop bc
pop bc
;
ret
;*****************************
; CTCx handler dummy
;*****************************
CTCxD:
ei
reti
;*****************************
; CTCx handler generate 10ms
;*****************************
CTCxH:
; store
push af
push hl
; load counter
ld a,(XTIM)
; increment
inc a
; judge
cp 10
jr z,CTCxH1
; store counter
ld (XTIM),a
jr CTCxH2
CTCxH1:
; clear
xor a
; store counter
ld (XTIM),a
; set WFLAG
ld a,(XFLAGS)
set WFLAG,a
ld (XFLAGS),a
CTCxH2:
; resume
pop hl
pop af
;
ei
reti
;****************************
; initialize USO parameters
;****************************
INIT_USO:
; store
push af
push bc
push de
push hl
; clear
xor a
; clear READY
ld (READY),a
; clear SUSPEND
ld (SUSPEND),a
; clear WAITQ
ld (WAITQ),a
; generate bit battern
ld hl,BPAT
ld a,1
ld b,8
INIT_USO1:
ld (hl),a
sla a
inc hl
djnz INIT_USO1
; set task state (READY)
; CRE_TSK , STA_TSK
; TSK7 TSK0
ld a,81h
ld (READY),a
; set task state (SUSPEND)
; CRE_TSK , STA_TSK
; TSK6 TSK5 TSK4 TSK3 TSK2 TSK1
cpl
ld (SUSPEND),a
; resume
pop hl
pop de
pop bc
pop af
;
ret
;****************************
; USO timer handler
;****************************
THANDLER:
; store
push af
push bc
push de
push hl
push ix
; store task ID
xor a
ld (GR3),a
; get information
ld a,(WAITQ)
ld c,a
; set counter
ld b,1
THANDLER0:
; get WAITQ information
ld a,c
; judge
bit 0,a
jr z,THANDLER1
; set pointer
ld hl,WCOUNT
; get task ID and calculate offset
ld a,(GR3)
sla a
ld e,a
ld d,0
; calculate pointer
add hl,de
; exchange value
push hl
pop ix
; get counter value
ld l,(ix)
ld h,(ix+1)
; decrement
dec hl
; store counter value
ld (ix),l
ld (ix+1),h
; judge
ld a,l
cp h
jr nz,THANDLER1
cp 0
jr nz,THANDLER1
; update READY
ld a,(READY)
or b
ld (READY),a
; update SUSPEND
ld a,(SUSPEND)
xor b
ld (SUSPEND),a
; update WAITQ
ld a,(WAITQ)
xor b
ld (WAITQ),a
THANDLER1:
ld a,(GR3)
inc a
ld (GR3),a
srl c
sla b
jr c,THANDLER2
jr THANDLER0
THANDLER2:
; resume
pop ix
pop hl
pop de
pop bc
pop af
;
ret
;****************************
; system call
;****************************
RSM_TSK:
; store
push af
push bc
push de
push hl
; get task ID
ld a,(GR0)
ld c,a
; get bit pattern
ld hl,BPAT
ld d,0
ld e,a
add hl,de
ld b,(hl)
; update READY (set target bit)
ld a,(READY)
or b
ld (READY),a
; update SUSPEND (reset target bit)
ld a,(SUSPEND)
xor b
ld (SUSPEND),a
; update WAITQ (reset target bit)
ld a,(WAITQ)
xor b
ld (WAITQ),a
; resume
pop hl
pop de
pop bc
pop af
;
ret
SUS_TSK:
; store
push af
push bc
push de
push hl
; get task ID
ld a,(GR0)
ld c,a
; get bit pattern
ld hl,BPAT
ld d,0
ld e,a
add hl,de
ld b,(hl)
; update READY (reset target bit)
ld a,(READY)
xor b
ld (READY),a
; update SUSPEND (set target bit)
ld a,(SUSPEND)
or b
ld (SUSPEND),a
; update WAITQ (reset target bit)
ld a,(WAITQ)
xor b
ld (WAITQ),a
; resume
pop hl
pop de
pop bc
pop af
;
ret
SLP_TSK:
; store
push af
; get task ID
ld a,(RUN_TSK)
ld (GR0),a
;
call SUS_TSK
; resume
pop af
;
ret
WAI_TSK:
; store
push af
push bc
push de
push hl
; get task ID
ld a,(RUN_TSK)
ld c,a
; get bit pattern
ld hl,BPAT
ld d,0
ld e,a
add hl,de
ld b,(hl)
; update READY (reset target bit)
ld a,(READY)
xor b
ld (READY),a
; update SUSPEND (reset target bit)
ld a,(SUSPEND)
xor b
ld (SUSPEND),a
; update WAITQ (set target bit)
ld a,(WAITQ)
or b
ld (WAITQ),a
; store counter
; get task ID
ld a,(RUN_TSK)
; x2
sla a
; set pointer
ld b,0
ld c,a
ld hl,WCOUNT
add hl,bc
; store
ld a,(GR1)
ld (hl),a
inc hl
ld a,(hl)
ld (hl),a
; resume
pop hl
pop de
pop bc
pop af
;
ret
;****************************
; task code
;****************************
TSK0_PROC:
;
ret
TSK1_PROC:
; store
push af
push bc
push de
push hl
; get counter
ld hl,XCNT1
ld e,(hl)
inc hl
ld d,(hl)
; get LSB
ld a,e
and 01h
; counter increment
ld b,h
ld c,l
ld hl,0
add hl,bc
inc hl
; store
ld b,h
ld c,l
ld hl,XCNT1
ld (hl),c
inc hl
ld (hl),b
; get pointer
ld hl,PORTB
; get data
ld b,(hl)
ld a,b
and 01h
; judge
cp 01h
jr z,TSK1_PROC1
res 0,b
jr TSK1_PROC2
TSK1_PROC1:
set 0,b
TSK1_PROC2:
ld (hl),b
; impress
ld c,PBDAT
ld a,b
out (c),a
; period 2000ms
ld hl,GR2
ld de,200
ld (hl),d
dec hl
ld (hl),e
call WAI_TSK
; resume
pop hl
pop de
pop bc
pop af
;
ret
TSK2_PROC:
; store
push af
push bc
push de
push hl
; get counter
ld hl,XCNT2
ld e,(hl)
inc hl
ld d,(hl)
; get LSB
ld a,e
and 01h
; increment
ld hl,0
add hl,de
inc hl
; store
ld e,l
ld d,h
ld hl,XCNT2
ld (hl),e
inc hl
ld (hl),d
; get pointer
ld hl,PORTB
; get data
ld b,(hl)
ld a,b
and 02h
; judge
cp 02h
jr z,TSK2_PROC1
res 1,b
jr TSK2_PROC2
TSK2_PROC1:
set 1,b
TSK2_PROC2:
ld (hl),b
; impress
ld c,PBDAT
ld a,b
out (c),a
; period 3000ms
ld hl,GR2
ld de,300
ld (hl),d
dec hl
ld (hl),e
call WAI_TSK
; resume
pop hl
pop de
pop bc
pop af
;
ret
TSK3_PROC:
;
ret
TSK4_PROC:
;
ret
TSK5_PROC:
;
ret
TSK6_PROC:
;
ret
TSK7_PROC:
;
ret
;****************************
; data area
;****************************
org 8000h
GR0 DS 1
GR1 DS 1
GR2 DS 1
GR3 DS 1
READY DS 1
SUSPEND DS 1
WAITQ DS 1
XFLAGS DS 1
RUN_TSK DS 1
XTIM DS 1
WCOUNT DW 8
BPAT DS 8
PORTB DS 1
XCNT1 DW 1
XCNT2 DW 1
END
アセンブリ言語の場合、Copy and Pasteで内容を更新すると
いろいろなバグが入込むことになるので、コンフィグレータ
を作成した方がよいでしょう。
Tcl/Tkは、UNIX、Windowsを問わずにGUIの
インタフェースを持つアプリケーションを
作成できます。Tcl/Tkでコンフィグレータ
を作成します。
コンフィグレータの動作イメージは、以下。
生成ファイル名、利用タスク数、エントリーアドレス
TCBテーブルの先頭アドレス等を確定してから、make
ボタンをクリックします。
目次
前
次