記事1では、「ディスプレイ」の例(実験バージョン)の内部構造がレビューされました。 本日の記事では、特定の技術的ソリューションの選択方法に焦点を当てて、作業オプションの自動開発プロセスについて説明します。 言及された記事の内容を繰り返すことはせず、問題の簡単な説明にとどまります。
問題の声明
b / wグラフィックディスプレイがあります。 そのビデオメモリには、各ビットが1ピクセルを表す標準のバイト構成があります。 データは、次のタイプのプロトコルを使用して、パラレルインターフェイスまたはSPIを介してディスプレイビデオメモリをバイト単位でストリーミングすることにより出力されます。
- Write_byteコマンドを送信します(byte_ordinates_on_display)
- 確認を受信した後、情報を送信できます
- データは、連続したバイトストリームで、ビデオメモリに行ごとに連続して送信されます。
テキスト出力は、等幅フォントではなく、異なるフォントで行う必要があります。
a)
b)
c)
図1.ディスプレイモジュールの要件
フォント内のすべての文字は同じ高さですが、フォントは同じ行を表示するプロセスで「オンザフライ」で変更できます。 同様に、属性を変更できます-太字、斜体、下線。 パラメーターを制御するには、 esc-sequencesを使用します 。これには、制御文字「\ n」、改行、つまり 1行のテキストをディスプレイの複数の行に表示できます。 たとえば、テキスト:
"Text 1 \033[7m Text 2 \033[27m \033[1m Text 3 \033[21m \n Text 42"
図1(b)の図のように表示されます
テキストは、図1(c)の長方形で囲まれた領域に表示され、オフセットx_shift
、 y_shift
持つ場合があります。 出力領域の座標はピクセル単位で指定され、座標は負になる場合があります。これは、出力領域を超えることを意味します。 出力領域の境界を越えるテキストは切り取られます、図1(c)。
ユーザーインターフェイス-プロトタイプを使用した機能
void Out_text(int x0, int y0, int x1, int y1, int x_shift, int y_shift, char * Text);
開発の開始、テキストブロックの自動出力の要件の取得
オートマトンのコンパイルは、 操作および制御オートマトンへの分解から始まり、再帰的に繰り返すことができます。各段階で、OAを低レベル OAとそのUAのペアに分割できます。
図2.機械の操作と制御への再帰的分解
分解は、解決される問題にとって自然なはずです。そのためには、タスクを明確に描写する、つまり、問題を詳細に調べる必要があります 。 多くの場合、実行する必要があるプロセスの有能なイメージは、一般的な方法で問題の解決策を得ることに相当します。これは、OAを選択した場合の成功のほぼ半分です。
意味を説明させてください。 問題の条件から次のように、一般的な場合の最初の文字シーケンスは次のようになります。Text1 control1 Text2 control2 Text3 control3 Text4 control4 Text5 \ 0
ここで、escシーケンス、改行、タブを制御します。
この図で、エスケープシーケンスで区切られたモノリシックテキストブロックがあることを確認するために、追加の作業は必要ありません。 したがって、一般的なタスクは、元のシーケンスをブロックに分割する段階と、これらのブロックの出力に分割されます。
図3.初期パーティション
これは最も単純なケースであり、元の問題のそのような内訳は明らかでしたが、他のケースではそれほど明白ではないため、シリーズ「ワークショップ」では元の問題の客観的な視点に注意を払い、例についてアドバイスします。
重要な場所は部品間の通信で占められています。レベルの1つを変更しても他のレベルに影響を与えないようにできる場合、これは大きなプラスになります。 各テキストブロックは、テキストブロックx_block, y_block
(出力ウィンドウに対する)の座標によって特徴付けられます。 フォントと属性(反転または非反転、点滅、太字、斜体、下線など)は変更されないため、すべてのテキストブロックに不要な情報を提供するのではなく、属性を管理するための個別のチャネル( 自動テキストブロック出力マシンメソッド)を作成する必要があります。 このような分割スキームとパーツ間の通信により、残りのパーツに触れることなく、テキストブロック出力マシンの OAを最も便利な方法で実装できます 。これは、OA「A1」回路とOA「A2」回路では、一般的な分割スキームは同じままです同じ。
したがって、 テキストブロックの自動出力の要件は次のとおりです。
テキストブロック出力機
テキストブロックの自動出力の要件は、グラフィカルに表すことができます。
図4.テキストブロックの自動出力の要件
各テキストブロックにはエスケープシーケンスが含まれなくなり、位置x_block, y_block
からブロックの末尾または画面の末尾までの変更されていない属性で表示されます。 x_shift, y_shift
の値は、ブロックのグループ全体の位置に影響し、単一のブロックを表示するときには、 x_block, y_block
値ですでに補正されています。 テキストブロックの右上隅は、出力ウィンドウの右上隅に対してカウントされます。高さはフォントの高さであり、幅はテキストが完全に収まらない場合のテキストまたは出力ウィンドウの幅です。
プロセスとしての自動設計
図に示す 2分解の再帰性は無期限に継続しません。この場合、これらは2つのレベルの分解です。 多くのタスクには、同じレベルのペア、または1つのレベルがあります。 大きなマルチステージは、モジュールではなくシステムの特性です。
その後、分割不可能なOA + UAのペア、下位レベルのペア、およびOAからUAへのボトムアップで発生するソフトウェア実装の詳細な調査があります。 これは通常、最低レベルがアクチュエーターに直接結び付けられているという事実によって決定されます。これにより、特定のフレームワークに入れられ、「操作」の可能性が制限され、同時に効率の程度が決定されます。それらは、基盤となるオートマトンの実装に準拠しています。 言及された「フレームワーク」は、開発プロセス中にすでに感じられており、最初の分析および故障中に、それらは「戦争の霧」によって隠されています。 これは、前述の「防水バルクヘッド」の役割を果たす部品間の通信の重要性を示しており、マシンのスタック全体ではなく、個々のモジュールのみを変更するように制限できます。
分割不可能なOA + UAの反復ペアの自動開発のプロセス:
図5.自動開発を使用した反復プロセス
チームが作業する大規模なプロジェクトを繰り返し開発します。この同じ形態の労働組織は、個人での使用に適しています。 この場合、私たちは手続きについて話していません。 個々の反復設計プロセスは、結果を交換して報告する必要がある参加者の会議の計画を意味するものではなく、開発者は1人だけです。 反復は単なる思考の流れです。 個々の反復設計プロセスは、OAとUAの設計プロセスであり、各反復はOAによって「完了」され、UAによって「プル」されます。 繰り返し述べたように、効果的な設計は主に効果的なOAであるため、開発はそれから始まります。
OAモデルの選択
OAの開発は最低レベルから始まります。 データは通信チャネルを介してビデオメモリのバイト単位のストリーミングをストリーミングすることによりディスプレイに出力されるため、各文字(グリフ、グリス)の「フィンガープリント」が配置され、テキストブロック全体が表示された後、ラインバッファーの内容がディスプレイにドロップされる中間ラインバッファーを使用することをお勧めしますバイトストリーム、テキストの幅全体にわたる水平線、高さ1ピクセル。
図6.ラインバッファからビデオメモリへのストリーミング出力の長いライン。
一般的な出力回路は次のようになります。
図7.一般的な出力モデル
A2の実装(一般的な出力モデルが同じであることを思い出します、図3)、ラインバッファーに出力するための操作マシンは非常に普遍的ですが、このため、任意のピクセル転送の低効率OAです。 このオプションの循環消費量はO(W * H)です。 シンボルの面積に比例します。
図8.任意のピクセル転送用の操作マシン。
しかし、高性能OAを取得する方法は? 自然な解決策は、ビットをグループで一度に転送することです。 指紋の長方形配列全体を文字ジェネレーターからラインバッファーにすぐにコピーする操作で文字を転送するのが最適です。このオプションの周期的な消費はO(1)に比例します。 ただし、そのようなチームはありません。 文字を文字列バッファーに1行ずつコピーするのが最も効率的な方法です。
図9. A1のOAの基礎となる最適な転送パターン
文字ジェネレーターからのシンボルの行ごとの出力は技術的な解決策No.1であり、将来の効率の基礎を提供し、最初の推定をすでに行うことができます:このオプションの循環消費は、 O(H)シンボルの行数に比例します。 14。
ピクセル単位の文字の幅はバイトの幅に比例せず、テキストブロック自体はバイトの境界から開始しない場合があることに注意してください。 この場合、バイトキャラクタージェネレーターの内容をバイトにコピーすることはできません。各シンボルラインの予備シフトが必要です。
図10.ラインバッファーに出力する前にグリフをシフトする必要性の説明
イラストから 図10は、ラインバッファのバイト内の各文字に複数の文字が含まれることがあることを示しています。 1バイトに含まれる複数の文字が互いに上書きされないように、シフトレジスタのデータはコピーされませんが、 またはによって重畳されます。 ただし、この操作には予備バッファクリーニングが必要であり、これはオーバーヘッドに変換されます。これは一般にバイト単位のラインバッファのサイズに比例し、そのサイズはフォントの行数に比例します。 図 11はこの関係を確認します
図11.ラインバッファーをクリーニングするオプションの場合、フォントの行数に対する総オーバーヘッドの依存性
中間結果を要約すると、作業スキームは次のとおりです。
- 文字ジェネレータからのデータはシフトレジスタにコピーされます-反復ごとに1行の文字。
- そこで、それらは
Current_shift
ピクセルだけシフトされCurrent_shift
- 既にシフトされたレジスタの内容は、
Current_byte
ポインターによってアドレス指定されたラインバッファーの特定のセクションの上または上にスーパーインポーズされます。 - ラインバッファは事前にクリアする必要があります。
- これはシンボルのすべての行に対して繰り返され、その後、
Current_shift
とCurrent_byte
両方が式によって増加します。
フォーミュラ1
Current_byte = (Current_byte + (Current_shift + Width)) >> 3; Current_shift = (Current_shift + Width) & 0x7;
図12. OAテキストブロック出力の基本モデル
特に式(1)から、 Current_shift
変数(シフト値)の7つの位置が最大値であり、大きな値によるシフトはモジュラス8によって制限されます。たとえば、12ビットは4ピクセルのシフトに変わり、1バイトでシフトレジスタをアンロードします。右へ。
図13. 7を法とするせん断制限
これは準備段階の反復であり、重要な戦略的決定の選択でした。 この実施形態では、動作している解決策自体が提案されたが、問題の状態の客観的な画像がそれらを処理するオペレーティングマシンを示唆さえしない場合がある。 この場合、問題の条件を数学的処理にかけ、元の問題を解決するのではなく、数学的に同一であるがより便利にすることができます(さらなる記事でこれを例で説明します)。 深刻なタスクの場合は、いくつかの解決策を検討し、速度やその他のリソースコストの技術的な見積もりを行う必要があります。そのため、説明されている手順に沿ってさらに1回または2回の反復を実行する必要があります。 いずれにせよ、このアプローチにより、許容できる時間に最適なソリューションを選択することができます。
選択された戦略的決定に基づいて、OAが開発されています。 OAでは、データの直接的な転送と変換に伴うすべてのことが進行中であり、OAでは、OAが機能するために必要なものが進行中です。
繰り返し1.ソースOA
オペレーティングマシンは半製品であり、有効なパラメーターを使用して必要な操作を最適に実行します。 この場合、UAはOAのパラメーター化と起動です。 この構造は高い柔軟性を提供し、特に、OA自体がCurrent_shift
およびCurrent_byte
内容を変更しないことをCurrent_byte
ます。 上記のすべての操作を実行するための既製のパラメーターセットを受け取ります。 必要な他のパラメーターを見つけるために、OAがどのように機能するかを考えてみましょう。 上記では、モデル化されている現象を視覚的に表現することの重要性についてすでに書いています。 理想的なケースだけでなく、境界条件に関連付けられた「便利ではない」オプションも描写することが重要であることを付け加えてください。 これは、おそらく以前に開発されたすべての、その後の変更を伴う、誤った決定を回避するのに役立ちます。 それは心理的に困難な瞬間であるため、私はこれに焦点を当てています-あなたの仕事を複雑にするかのように、最も難しい側面からシミュレートされた現象を描くことです。 ただし、 解決する問題の複雑さは客観的なものであり、不快な瞬間に目をつぶっているかどうかに依存せず、影響を与えることができる唯一のことはこの問題を解決する複雑さであり、最初にどれだけ難しいかを解決するソリューションを探している場合は最小限に抑えられます瞬間に直面する必要があります。 このアプローチは、プログラムの開発コストをデバッグ段階(実装された多数のモジュールを処理する場合)から設計段階(空白のキャンバスを処理する場合)にシフトします。
すべての文字の幅は異なるため、パラメータが必要です。各文字列にロードするバイト数:
図14. bytes_For_loadパラメーター
ロード後、シンボルの各行をシフトする必要があります。 シフトは、さまざまな方法でさまざまなマイクロコントローラーに対して発生することに注意してください。 ARMには、1サイクルで最大32ビット幅のビット単位でシフトするための効果的なメカニズムがあり、このようなシフトは、算術などの他のコマンドのオプションとして単純に追加できます。 msp430の場合、最適なシフトコマンドは位置ごとに16ビットです。 ただし、一般的なスキームはこれから変更されません。1桁シフトするプロセッサー(msp430)については、アセンブラーの挿入を介したより効率的なシフトスキームである「転送フラグによるシフト」コマンドを使用できます。 極端なオプションとして(これはディスプレイだけでなく、一般的に異なるOAにも当てはまります)、比較的単純なコードをアセンブラー命令の配列にデプロイするマクロアセンブラーでOAを書くことができます。 おそらくアセンブラーの実装は必要ありません。必要に応じて、追加の「切り札」、「表示」モジュールを改善する方法があることを示すためにこれを言及しました。 同時に、UAは前の記事で説明したOAおよびUAファミリの概念の一部であるため、UAを変更する必要はありません。
図15. OAおよびUAファミリー
時間が経つにつれて、オペレーティングマシンファミリにはさまざまなマシンが補充され、それらの間で効果的な半自動検索を使用できるようになり、便利な開発ツールになります。 しかし、ちなみに、この例では、「手動」自動設計の場合、 OAおよびUA ファミリは必要ないため、選択したオプションの1つに焦点を当てます。
行内のすべてのバイトをシフトする必要があります。 シフトの位置の数が最小になるようにシフトの方向をとることは論理的ですが、実際の経験では、操作の実装の均一性はかなり価値があると言われているため、右にシフトするオプションが考慮され、実際により短い時間で実行されるようにすでに実装できます側。
ある程度のシフトがあると、ロードする必要があるバイト数と比較して、シフトする必要があるバイト数がもう1バイト増える可能性があります。
図16. bytes_For_shiftパラメーター
シフトの後、シフトレジスタの内容がラインバッファにスローされます。 一見、出力のバイト数はシフトのバイト数と一致する必要がありますが、この文字の左端のピクセルが画面の端の左側にあると想像すると、出力のバイト数はシフトのバイト数と一致しません。
図17. bytes_For_outパラメーター
したがって、OAの一般的な概要は次のようになります。
class tShift_buffer { public: void Load (u1x *Source, int Bytes_amount); void Shift(int Bits_amount, int Bytes_amount); void Out (u1x *Destination, int Bytes_amount); }; //////////////////////////////////////////////////////////////////////////// // void Out_symbol() { // for(int y = 0; y < Height; y++) { u1x * Glyph_line = Current_font->Image_for(* Text) + y * bytes_Width; Shift_buffer.In (Glyph_line, bytes_For_load); Shift_buffer.Shift (Current_shift, bytes_For_shift); Shift_buffer.Out (&String_buffer [y][Current_byte], bytes_For_out); }// for(int y = y0; y < Height; y++) }// void Out_symbol()
明らかに、このOAの有効性は、シフトレジスタを使用した操作の実装方法に直接依存します。 さらにこれについては、当分の間、それらを効果的に実現するのに複雑なことは何もないようです。
これで、制御マシンのモデルのコンパイルを開始できます。 OAをさらに詳しく説明すると、行き詰まりにつながる可能性があります。 これは、非常に効果的なOAを選択すると、UAで法外なオーバーヘッドが発生し、それに応じてスキーム全体が非効率になる可能性があるためです。 さらに、既製のOAスキームを開発し、AAモデルさえ持っていない場合、このモデルを念頭に置いておく必要があります。これは、実行できない競合する要件につながる可能性があります。 最後に、最も重要なことは、前のリストからOAモデルがどの程度適切であるかを理解するには、いわば鳥の飛翔の高さからプロセス全体を見る必要があるということです。
反復1.ソースUA
そのため、AAの初期実装が必要です。これにより、OAの詳細を考慮し、UAの観点からこれが何をもたらすかを詳細に検討することができます。 UAの開発は、最初のものが2番目のパラメーターを管理するという事実により、OAの開発と切り離せません。 UAを開発するとき、OAとそのパラメーターの説明をやめませんが、逆に、これらのパラメーターとその初期値の計算を追加します。
図18. OAとAAの密接な関係
したがって、初期化されていないパラメーターやUAの制御なしにパラメーターが追跡されないようにし、パラメーターの数が測定値を超えて大きくならないようにすることをお勧めします。
表1. OAのパラメーター
可変パラメーター | 式 |
幅 | キャラクタージェネレーターからの読み込み |
current_byte、current_shift | current_byte =(current_byte +(current_shift + width))>> 3; current_shift =(current_shift + width)&0x7; current_byte 0 = 0; current_ shift 0 = x_block&0x7; |
bytes_for_load、bytes_for_shift、bytes_for_out | さらに定義 |
このようなテーブルは、機械がドラフト上で補助的なものとしてコンパイルされるときに構築されます。 ただし、前の記事の「 Looking to the Future 」の章で説明されている「一般化されたユニバーサルオートマトンテンプレート」の編集に戻ると、そのようなテーブルを使用して、UAとOAを相互エクスポート/パブリックアナウンスの形で説明し、それらを接続することができますこれは、コンピューター支援設計システムで使用されるパラメーターのセットと一致します。
UAの試用版。
位置0から始まる無限に長い行バッファーに無限のテキストを表示する場合、UAは次のようになります。
uchar * Text; uchar String_buffer[y_string][x_max /* 0.Infinity */ ]; //////////////////////////////////////////////////////////////////////////// // void Out_text_block(uchar * Text) { Current_shift = Current_byte = 0; while(1) { Witdh = Current_font->Width_for(* Text); bytes_For_load = (Width + 7) >> 3; bytes_For_shift = (Width + Current_shift + 7) >> 3; bytes_For_out = bytes_For_shift; Out_symbol(); Current_shift = (Current_shift + Width); Current_byte = (Current_byte + Current_shift) >> 3; Current_shift &= 0x7; Text++; } }// void Out_text_block(uchar * Text)
ただし、有限の長さの実際のテキストを処理しており、さらに、出力ウィンドウに対して初期シフトがあり、このテキストは、上下、左右の両方で出力ウィンドウに収まらない場合があります。
テキストが出力ウィンドウの上または下の端を超えて広がる場合。
下と上からの制限を考慮することは、右と左からよりも簡単なので、それから始めます。文字の高さが出力ストリップよりも広い場合や、テキストの最初のシフトにより、テキストの一部が上、下、またはすぐ上と下に表示される場合があります。
図19.縦長のテキストのバリエーション
OAの観点から見ると、この動作は単純に実装されています。行を列挙し、「垂直周期」のリストに変更十分0
アップHeight
それには、線を経てStart_line
までEnd_line
どこStart_line
-バッファに入る上段番号グリフ、End_line
-の範囲に該当しない最初の行番号(下)の値を検索しました。つまり、バッファに完全に収まる6x9文字の場合ですEnd_line = 9
。
最初に決定Start_line
if(y_block < y0) { Start_line = y0 - y_block; } else { Start_line = 0; } if( Start_line >= Height) // ,
End_line
値に基づいて検索されます
Start_line
。
if( (y1 – y_block) >= Height) { End_line = Height; } else { End_line = y1 – y_block; }
テキストが出力ウィンドウの端を越えて右または左に伸びる場合。
水平は、列のバイトグループ化により複雑です。ブロックの始まりの座標x_block
。値はx_shift
補正されますが、それを思い出すことはできません。
20.
x_block > x0
, , , , – . x_block < x0
-, . . 20, . , Left_shift
, .
« » . 21。
21. .
Left_shift
, ( 1 ). .
, ( 2 ). ( 3 ), 2 ( ) , 3 . , — . , , .
, 2 3 .
22.
, 2, 2', 3 3' . , , . , . , . ( ) .
1. .
|
|
left_shift | if ( x _ block >= x 0)
|
, , . 23
23.
前述したように、状態図は、オートマトンの記述に加えて、グラフ図の代替アルゴリズムであるアルゴリズムを記述するためのスキームでもあります。その上で、単にソフトウェアの実装を行うことができます。色は、状態に対応するプログラムテキストを強調表示します。
パラメーター
Line_width
は、出力ウィンドウの最後に到達したかどうかを示します
表1. OA操作のパラメーター。継続
可変パラメーター | 式 |
line_width | line _ width = line _ width - width ;
|
コミットの作成
これはまだ動作中のアプリケーションではありません。OAの代わりに、デバッグメモに表示されるスタブ(シンボル、幅、分類(2.2a、3.3a))が使用されます。タイプ2 / 2a文字の場合、オフセット値も表示されます
Left_shift
。
状況は一般的に明らかです。次のタスクは、最初の近似として、OA作業モジュールを取得することです。
繰り返し2. OA
3つのタイプ1、2、3のシンボルと2つのサブタイプ2 '、3'があります。出力のタイプごとに専用のOAを使用することは論理的です。
文字が完全に出力ウィンドウに収まらない。
左シフトのために表示領域に完全に収まらなかった文字は、図の番号1で示されます。表示領域に収まらないすべての文字を「スクロール」するだけで、処理が最も簡単です。
// , while(Text < Text_end) { Width = Current_font->Width_for(*Text); // if(Left_shift >= Width) { Left_shift -= Width; Text++; } else goto Type_2; }// while(Text < Text_end)
出力ウィンドウ全体に配置される文字。
タイプ3は、すでに説明したメインキャラクタータイプです。その処理ニーズパラメータの
Current_byte
(前のシンボルから知られている)
Current_shift
(前の文字から知られています)
bytes_For_load, bytes_For_shift, bytes_For_out
。
図24.文字パラメータータイプ3
実際の計算は代数リングで行われるため、エッジ効果は避けられません。
図25. タイプ3のパラメーター計算の説明
図の図を使用します。25パラメータの計算式は簡単に定式化できます。
bytes_For_load = (Width + 7) >> 3; bytes_For_shift = (Width + Current_shift + 7) >> 3; bytes_For_out = bytes_For_shift; Current_shift_next = (Current_shift + Width) & 0x7; Current_byte_next = Current_byte + ( (Current_shift + Width) >> 3 );
右側にのみ表示される記号。
a)
b)
図26.文字パラメータータイプ3a
価値 これは残りの行です
したがって、タイプ3aのケースはタイプ3のケースに縮小され、シンボルの幅が置き換えられます。
x1
。これは、出力ウィンドウの座標によって決まります。そして、過去の場合と同様に、代数リングを扱っています。このケースは前のケースに要約されるので、一般に、以下の図は必要ありませんが、その助けにより、予期しない矛盾を回避できます。
図27. タイプ3aのパラメーター計算の説明
Width = Line_width; bytes_For_load = (Width + 7) >> 3; bytes_For_shift = (Width + Current_shift + 7) >> 3; bytes_For_out = bytes_For_shift; Right_mask = sb_Right_mask[ (Current_shift + Width) & 0x7]; Current_shift_next = (Current_shift + Width) & 0x7; Current_byte_next = Current_byte + ( (Current_shift + Width) >> 3 );
左に突き出ている記号。
タイプ2は、部分的にディスプレイウィンドウの境界を越える場合があり、左側がディスプレイに表示されない場合があります。
図28.シンボルタイプ2
出力ウィンドウの境界を越えて左へのキャラクターの出口のシミュレーションは、新しくロードされたキャラクターをLeft_shift
ピクセル単位で左にシフトし、それをCurrent_shift
右に移動することで実現できます。
29. 2 .
, , , . ( , «» ).
Result_shift = Current_shift - Left_shift;
, Current_shift
30. 2 .
8 (5+3) 2 (5-3) . msp430. ARM7 ( ) , .
1. .
|
|
result_shift | result_shift = current_shift — left_shift; |
31. 2
Result_shift
, 3 , Current_shift
Result_shift
, , Current_shift
.
, . . 32 .
32. 2
, Left_shift
, Current_shift
7 ( Width
). , , () , LS = 10..12 , , . Left_mask
, LS = 8,9 , 0..7, , , . First_byte_gen
– , , . Left_shift
8. Left_shift
7 .
33. Left_shift.
, Result_shift
, , . ( 7 ) . . 34, , .
34. .
, Result_shift
. , 1 .
, , : -2 6. , – 5 2 . Current_shift = 0
,
2. Left_shift
left_shift & 0x7 | result_shift | |
32 | 3 3 | |
0 | 0 | 0 |
1 | -1 | 7 |
2 | -2 | 6 |
3 | -3 | 5 |
4 | -4 | 4 |
5 | -5 | 3 |
6 | -6 | 2 |
7 | -7 | 1 |
, Left_shift & 0x7
Current_shift
0..7 Result_shift
( )
3. — 2
. 33. | . 34. | ||
|RSi| | p | RSi | p |
0 | 0.125 | 0 | 0.125 |
1 | 0.21875 | 1 | 0.125 |
2 | 0.1875 | 2 | 0.125 |
3 | 0.15625 | 3 | 0.125 |
4 | 0.125 | 4 | 0.125 |
5 | 0.09375 | 5 | 0.125 |
6 | 0.0625 | 6 | 0.125 |
7 | 0.03125 | 7 | 0.125 |
∑ Pi * |RSi| 3.625 |
∑ Pi * RSi 4.5 |
, . . 34 25%, , , .
? , . 34. , , , , .
:
Current_shift = x_block & 0x7; First_byte_gen = Left_shift >> 3; int Corrected_Left_shift = Left_shift & 0x7; Left_mask = sb_Left_mask[Current_shift]; // Result_shift Current_shift if(Corrected_Left_shift <= Current_shift ) // Result_shift > 0 { Current_shift -= Corrected_Left_shift; First_byte_reg = 1; bytes_For_load = (Width + 7) >> 3 - First_byte_gen; bytes_For_shift = (Width + Current_shift + 7) >> 3 - First_byte_gen; bytes_For_out = bytes_For_shift; // , , Line_width Width -= Left_shift; } else { Current_shift = Current_shift - Corrected_Left_shift + 8; First_byte_reg = 0; bytes_For_load = (Width + 7) >> 3 - First_byte_gen; bytes_For_shift = (Width + Current_shift + 7) >> 3 - First_byte_gen; bytes_For_out = bytes_For_shift - 1; } Current_shift_next = (Current_shift + Width) & 0x7; Current_byte_next = Current_byte + ( (Current_shift + Width) >> 3 ) - First_byte_gen;
左右に突き出ているシンボル
最も複雑なケース。ケース2と3aを組み合わせているようです。
a)
b)は
、文字については、図35のパラメータタイプ2A、
シンボルタイプ2aは、タイプ2の変更されたケースで、シンボルの左右の部分が「ドロップアウト」します。
価値 x1
. , . . 36 .
36. 2
Width = Line_width; Current_shift = x_block & 0x7; First_byte_gen = Left_shift >> 3; int Corrected_Left_shift = Left_shift & 0x7; Left_mask = sb_Left_mask[Current_shift]; Right_mask = sb_Right_mask[ (Current_shift + Width) & 0x7]; if(Corrected_Left_shift <= Current_shift ) // Result_shift > 0 { Current_shift -= Corrected_Left_shift; First_byte_reg = 1; bytes_For_load = (Width + 7) >> 3 - First_byte_gen; bytes_For_shift = (Width + Current_shift + 7) >> 3 - First_byte_gen; bytes_For_out = bytes_For_shift; // , , Line_width Width -= Left_shift; } else { Current_shift = Current_shift - Corrected_Left_shift + 8; First_byte_reg = 0; bytes_For_load = (Width + 7) >> 3 - First_byte_gen; bytes_For_shift = (Width + Current_shift + 7) >> 3 - First_byte_gen; bytes_For_out = bytes_For_shift - 1; } Current_shift_next = (Current_shift + Width) & 0x7; Current_byte_next = Current_byte + ( (Current_shift + Width) >> 3 ) - First_byte_gen;
.
, , . , , . . 37。
図37.ビデオメモリとラインバッファーのバイトの座標の対応
ビデオメモリ内のウィンドウの左端の水平バイトインデックスは、式によって決定されます
Left_screen_byte = x_block >> 3;
文字列バッファーでは、このバイトは初期値のバイトに対応しますCurrent_byte
。
Current_byte = 0;
ビデオメモリの各ピクセルラインの開始バイトのアドレスは、式によって計算されます
vm_Left_screen_byte_for_line = y_vm * x_max_bytes + Left_screen_byte;
ラインバッファーの各ピクセルラインの開始バイトのアドレスは、式によって計算されます
sb_Left_screen_byte_for_line = y_sb * x_max_bytes;
x_max_bytes
ビデオメモリとラインバッファの幅は同じです。
, , Current_byte
, x1
, Currnt_shift
.
.
38.
, . :
39.
これで、最後の反復で作成されたフレームワークに基づいて作業UAを構築するのに十分な情報があります。
繰り返し2. UAはすべてをまとめて収集します
UAの要件は変更されていませんが、初期化段階で計算する必要があるパラメーターは定義されています。x_shift
この瞬間の値は補償されていることを思い出させてください
void tDisplay_A1::Out_text_block () { x_block = x0 + x_rel + x_shift; y_block = y0 + y_rel + y_shift; Text = Text_begin; if(x_block < x0) { Left_shift = x0-x_block; x_block = x0; } else Left_shift = 0; Line_width = x1 - x_block; if(Line_width <= 0) return; //////////////////////////////////////// Type_1: // while(Text < Text_end) { Width = Current_font->Width_for(*Text); // if(Left_shift >= Width) { Left_shift -= Width; Text++; } else goto Type_2; }// while(Text < Text_end) // return; //////////////////////////////////////// Type_2: // ? if(Line_width <= Width) { Width = Line_width; Current_shift = x_block & 0x7; First_byte_gen = Left_shift >> 3; int Corrected_Left_shift = Left_shift & 0x7; Left_mask = sb_Left_mask[Current_shift]; // Result_shift Current_shift if(Corrected_Left_shift <= Current_shift ) // Result_shift > 0 { Current_shift -= Corrected_Left_shift; First_byte_reg = 1; bytes_For_load = (Width + 7) >> 3 - First_byte_gen; bytes_For_shift = (Width + Current_shift + 7) >> 3 - First_byte_gen; bytes_For_out = bytes_For_shift; // , , Line_width Width -= Left_shift; } else { Current_shift = Current_shift - Corrected_Left_shift + 8; First_byte_reg = 0; bytes_For_load = (Width + 7) >> 3 - First_byte_gen; bytes_For_shift = (Width + Current_shift + 7) >> 3 - First_byte_gen; bytes_For_out = bytes_For_shift - 1; } Current_shift_next = (Current_shift + Width) & 0x7; Current_byte_next = Current_byte + ( (Current_shift + Width) >> 3 ) - First_byte_gen; Right_mask = sb_Right_mask[ Current_shift_next ]; Symbol_t2a(); goto Finalize; } Line_width -= Width; Current_shift = x_block & 0x7; First_byte_gen = Left_shift >> 3; int Corrected_Left_shift = Left_shift & 0x7; Left_mask = sb_Left_mask[Current_shift]; // Result_shift Current_shift if(Corrected_Left_shift <= Current_shift ) // Result_shift > 0 { Current_shift -= Corrected_Left_shift; First_byte_reg = 1; bytes_For_load = (Width + 7) >> 3 - First_byte_gen; bytes_For_shift = (Width + Current_shift + 7) >> 3 - First_byte_gen; bytes_For_out = bytes_For_shift; // , , Line_width Width -= Left_shift; } else { Current_shift = Current_shift - Corrected_Left_shift + 8; First_byte_reg = 0; bytes_For_load = (Width + 7) >> 3 - First_byte_gen; bytes_For_shift = (Width + Current_shift + 7) >> 3 - First_byte_gen; bytes_For_out = bytes_For_shift - 1; } Current_shift_next = (Current_shift + Width) & 0x7; Current_byte_next = Current_byte + ( (Current_shift + Width) >> 3 ) - First_byte_gen; ////////////////////////////////// // ////////////////////////////////// Symbol_t2(); // Text++; //////////////////////////////////////// Type_3: // ? while(Text < Text_end) { Width = Current_font->Width_for(*Text); // ? if(Line_width <= Width) { Width = Line_width; Line_width = 0; bytes_For_load = (Width + 7) >> 3; bytes_For_shift = (Width + Current_shift + 7) >> 3; bytes_For_out = bytes_For_shift; Current_shift_next = (Current_shift + Width) & 0x7; Current_byte_next = Current_byte + ( (Current_shift + Width) >> 3 ); Right_mask = sb_Right_mask[ Current_shift_next ]; Symbol_t3a(); goto Finalize; } Line_width -= Width; ////////////////////////////////// // ////////////////////////////////// Symbol_t3(); bytes_For_load = (Width + 7) >> 3; bytes_For_shift = (Width + Current_shift + 7) >> 3; bytes_For_out = bytes_For_shift; Current_shift_next = (Current_shift + Width) & 0x7; Current_byte_next = Current_byte + ( (Current_shift + Width) >> 3 ); Text++; }// while(Text < Text_end) Finalize: // return; }// void tDisplay_A1::Out_text_block ()
繰り返し3. OA
すべてのタイプのOAの要件は、反復2で完全に定義されています。これで、これらのOAを実装する関数を作成できます。すべてのタイプのOAの以前の説明は網羅的であるため、追加のコメントは不要です。
class tShift_buffer; // void tShift_buffer::Load (u1x * Source, u1x Destination_index, u1x bytes_Width); // void tShift_buffer::Shift (u1x First_byte_index , u1x Bytes_amount , u1x Bits); // void tShift_buffer::Out (u1x Source_index, u1x * Destination, u1x bytes_Width); // // void tShift_buffer::Out_by_or (u1x Source_index, u1x * Destination, u1x bytes_Width); // u1x & tShift_buffer::operator [](u1x Index_of_element); //////////////////////////////////////////////////////////////////////////// // void Out_symbol_t2() { // for(int y = 0; y < Height; y++) { uchar * Glyph_line = Current_font->Image_for(* Text) + y * bytes_Width; Shift_buffer.In (Glyph_line, bytes_For_load); Shift_buffer.Shift (Current_shift, bytes_For_shift); Shift_buffer. Out_by_or (&String_buffer [y][Current_byte + i], bytes_For_out); }// for(int y = y0; y < Height; y++) }// void Out_symbol_t2() //////////////////////////////////////////////////////////////////////////// // void Out_symbol_t2a() { // for(int y = 0; y < Height; y++) { uchar * Glyph_line = Current_font->Image_for(* Text) + y * bytes_Width; Shift_buffer.In (Glyph_line, bytes_For_load); Shift_buffer.Shift (Current_shift, bytes_For_shift); Shift_buffer.Out (&String_buffer [y][Current_byte + i], bytes_For_out); }// for(int y = y0; y < Height; y++) }// void Out_symbol_t2a() //////////////////////////////////////////////////////////////////////////// // void Out_symbol_t3() { // for(int y = 0; y < Height; y++) { uchar * Glyph_line = Current_font->Image_for(* Text) + y * bytes_Width; Shift_buffer.In (Glyph_line, bytes_For_load); Shift_buffer.Shift (Current_shift, bytes_For_shift); Shift_buffer.Out (&String_buffer [y][Current_byte + i], bytes_For_out); }// for(int y = y0; y < Height; y++) }// void Out_symbol_t3() //////////////////////////////////////////////////////////////////////////// // void Out_symbol_t3a() { // for(int y = 0; y < Height; y++) { uchar * Glyph_line = Current_font->Image_for(* Text) + y * bytes_Width; Shift_buffer.In (Glyph_line, bytes_For_load); Shift_buffer.Shift (Current_shift, bytes_For_shift); Shift_buffer.Out (&String_buffer [y][Current_byte + i], bytes_For_out); }// for(int y = y0; y < Height; y++) }// void Out_symbol_t3a()
繰り返し3.デバッグ
デバッグのために、Out_text関数の初期パラメーターを変更できる単純なフォームを使用しました。関心のあるパラメータはフォームの右側に表示され、バグを簡単に修正できるのを確認します。
図40.デバッグ用のフォームデバッグ
の過程については説明しませんが、バグリストに限定します。
-画面の
bytes_X_size
幅の代わりに、文字の幅が使用されました
bytes_Width
。
-新しい次の値は現在のものになりませんでした-
シフトレジスタのクリアはありませんでした-角括弧を忘れ
た形式のすべての式で
(Width + Current_shift + 7) >> 3 - First_byte_gen;
-右端のバイトインデックスのマスキングが修正されました。結果は明らかです
( (Width + Current_shift + 7) >> 3 ) - First_byte_gen;
デバッグは難しくありませんでした。表図 25、27、34、36は失望しませんでした。補助テーブルやその他の図をコンパイルすることは問題の客観的な見方の一部であるため、私はテーブルに焦点を当てています。これはプログラミングの際に非常に役立ちます。
-
. , . , 11, . , , , – tShift_register
. , , « », . – . , , - . , , , . «». , , , , .