<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>VRAM &#8211; EXPERTGIG</title>
	<atom:link href="https://expertgig.jp/tag/vram/feed/" rel="self" type="application/rss+xml" />
	<link>https://expertgig.jp</link>
	<description>工場IoT に特化したシステム開発</description>
	<lastBuildDate>Sat, 07 Jun 2025 15:34:20 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>Raspi Zero 2W ベアメタル開発 04 ( MZ80KのVRAM表示編)</title>
		<link>https://expertgig.jp/2025/06/08/raspi-zero-2w-%e3%83%99%e3%82%a2%e3%83%a1%e3%82%bf%e3%83%ab%e9%96%8b%e7%99%ba-mz80k%e3%81%aevram%e8%a1%a8%e7%a4%ba%e7%b7%a8/</link>
					<comments>https://expertgig.jp/2025/06/08/raspi-zero-2w-%e3%83%99%e3%82%a2%e3%83%a1%e3%82%bf%e3%83%ab%e9%96%8b%e7%99%ba-mz80k%e3%81%aevram%e8%a1%a8%e7%a4%ba%e7%b7%a8/#respond</comments>
		
		<dc:creator><![CDATA[Ariyuki Tano]]></dc:creator>
		<pubDate>Sat, 07 Jun 2025 15:33:22 +0000</pubDate>
				<category><![CDATA[マイコン]]></category>
		<category><![CDATA[情報発信基地]]></category>
		<category><![CDATA[Lazarus]]></category>
		<category><![CDATA[MZ-80]]></category>
		<category><![CDATA[Raspi Zero 2W]]></category>
		<category><![CDATA[Ultibo]]></category>
		<category><![CDATA[VRAM]]></category>
		<category><![CDATA[Z80]]></category>
		<category><![CDATA[エミュレータ]]></category>
		<guid isPermaLink="false">https://expertgig.jp/?p=6069</guid>

					<description><![CDATA[前回、画面へのキャラクタ描画はうまく行ったので、もっとエミュレータ開発に使づくように、今日はもう一歩前進してみましょう。 MZ80Kのメモリ領域全体は、8bitマシンということで、64KBとなります。 メモリ内容を保持す [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>前回、画面へのキャラクタ描画はうまく行ったので、もっとエミュレータ開発に使づくように、今日はもう一歩前進してみましょう。</p>



<p>MZ80Kのメモリ領域全体は、8bitマシンということで、64KBとなります。</p>



<pre class="wp-block-code"><code class="">unit mem;<br>interface<br>var<br>  memory: array[0..65535] of Byte;<br>implementation<br>end. </code></pre>



<p>メモリ内容を保持する unit として、上記のように準備しました。</p>



<p>ここに、MZ-80KのモニタROM (SP-1002) を読み込んでみましょう。</p>



<pre class="wp-block-code"><code class="">//==============================================================================<br>// Load MONITOR ROM<br>//==============================================================================<br>procedure LoadMonitorRom;<br>var<br>  FS: TFileStream;<br>  MonitorPath: string;<br>  I: Integer;<br>begin<br>  ConsoleWindowWriteLn(Console1, 'Waiting for drive...');<br><br>  // C:\ または fat:\ が使えるのを待つ<br>  while not DirectoryExists('C:\') and not DirectoryExists('fat:\') do<br>    Sleep(100);<br><br>  if DirectoryExists('C:\') then<br>    MonitorPath := 'C:\mon_rom'<br>  else<br>    MonitorPath := 'fat:\mon_rom';<br><br>  ConsoleWindowWriteLn(Console1, 'Drive is ready.');<br><br>  if FileExists(MonitorPath) then<br>  begin<br>    ConsoleWindowWriteLn(Console1, 'Loading monitor ROM file...');<br>    FS := TFileStream.Create(MonitorPath, fmOpenRead);<br>    FS.Read(MonitorRom, SizeOf(MonitorRom));<br>    FS.Free;<br>    ConsoleWindowWriteLn(Console1, 'Monitor ROM loaded successfully!');<br>  end<br>  else<br>  begin<br>    ConsoleWindowWriteLn(Console1, 'Monitor ROM file not found at ' + MonitorPath);<br>  end;<br><br>  // 読み込んだ内容を memory[] にコピー<br>  for I := 0 to SizeOf(MonitorRom) - 1 do<br>    memory[I] := MonitorRom[I];<br>end;                  </code></pre>



<p>メモリの先頭 $0000番地から4KBのモニタROMを読み込んでセットします。</p>



<p>今後、Z80のエミュレータがうまく動けば、このモニタ部分を実行して、VRAMへの初期表示もされることになります。</p>



<p>まだそこまでは行けないので、今回はVRAMとして割り当てられた $D000 からの1000byte の内容を画面に表示するところまでやってみましょう。</p>



<p>つまり画面表示部分だけ先にテストしておこうというわけです。</p>



<h2 class="wp-block-heading">VRAMの内容を画面に表示する</h2>



<p>とりあえずざっとソースプログラムを見てみましょう。</p>



<pre class="wp-block-code"><code class="">//==============================================================================<br>// スクリーン描画スレッド<br>//==============================================================================<br>procedure DrawScreenThread;<br>var<br>  FTimeValue : QWord;<br>  FTimeDis   : QWord;<br>  FStartVSync: QWord;<br>  FEndVSync  : QWord;<br>  FVSyncTime : QWord;<br>  Amin       : Integer;<br>  Asec       : Integer;<br>  DrawFreq   : Integer;<br>  i, j       : Integer;<br>begin<br>  // すでにスレッドが開始されていたら停止<br>  if Assigned(ScreenThread) then<br>  begin<br>    flgStop := True;<br>    ScreenThread.Terminate;<br>    FreeAndNil(ScreenThread);<br>  end;<br><br>  // スレッド開始<br>  flgStop := False;<br>  ScreenThread := TDrawScreenThread.Create(False); // False = 自動起動<br>  ScreenThread.FreeOnTerminate := False;<br>end;<br><br>//==============================================================================<br>// Draw Screen Thread Execeute<br>//==============================================================================<br>procedure TDrawScreenThread.Execute;<br>var<br>  FStartVSync, FEndVSync, FVSyncTime: QWord;<br>begin<br>  while not Terminated do<br>  begin<br>    FStartVSync := GetTickCount64;<br><br>    //if hw80.v_gate then<br>    if true then  // z80動かすまでの仮設定<br>    begin<br>      update_scrn;<br>    end<br>    else<br>    begin<br>      ClearScreenFast(BG);  // 事前定義された背景色<br>    end;<br><br>    FEndVSync := GetTickCount64;<br>    FVSyncTime := FEndVSync - FStartVSync;<br><br>    if SYNCTIME > FVSyncTime then<br>      Sleep(SYNCTIME - FVSyncTime);<br><br>    Sleep(1);<br>  end;<br>end;<br><br>//==============================================================================<br>// 画面アップデート処理  (v-blank) [書き換えが必要部分だけ画面を書き換える]<br>//==============================================================================<br>procedure update_scrn;<br>var<br>  i: Integer;<br>  CharCode: Byte;<br>  Row, Col: Integer;<br>begin<br>  for i := 0 to 999 do<br>  begin<br>    CharCode := Memory[$D000 + i];<br>    if ScrChar[i] &lt;> CharCode then<br>    begin<br>      Row := i div 40;<br>      Col := i mod 40;<br>      DrawCharToSurface(Col * 8, Row * 8, CharCode);<br>      ScrChar[i] := CharCode;<br>    end;<br>  end;<br>end;<br><br>//==============================================================================<br>// 指定した X,Y (40x25) にキャラを表示<br>//==============================================================================<br>procedure DrawCharToSurface(X, Y: Integer; CharCode: Byte);<br>var<br>  Line, Bit: Integer;<br>  Px, Py: Integer;<br>  Data: Byte;<br>  Color: LongWord;<br>begin<br>  for Line := 0 to 7 do<br>  begin<br>    Data := FontRom[CharCode * 8 + Line];<br>    for Bit := 0 to 7 do<br>    begin<br>      Px := X + Bit;<br>      Py := Y + Line;<br><br>      if (Data and (1 shl (7 - Bit))) &lt;> 0 then<br>        Color := FG<br>      else<br>        Color := BG;<br><br>      PutPixel(Px, Py, Color);<br>    end;<br>  end;<br>end;<br><br>//==============================================================================<br>// 点を描画<br>//==============================================================================<br>procedure PutPixel(X, Y: Integer; Color: LongWord);<br>var<br>  Offset: PtrUInt;<br>begin<br>  Offset := FBInfo.PixelAddr + Y * FBInfo.Pitch + X * 4;<br>  PLongWord(Pointer(Offset))^ := Color;<br>end;<br><br>//==============================================================================<br>// 画面を高速クリア<br>//==============================================================================<br>procedure ClearScreenFast(Color: LongWord);<br>var<br>  PixelPtr: PLongWord;<br>  Count: Integer;<br>begin<br>  PixelPtr := PLongWord(Pointer(FBInfo.PixelAddr));<br>  Count := (FBInfo.Pitch div 4) * FBInfo.Height;<br><br>  while Count > 0 do<br>  begin<br>    PixelPtr^ := Color;<br>    Inc(PixelPtr);<br>    Dec(Count);<br>  end;<br>end;                 </code></pre>



<p>画面を一定周期で更新するThread を定義して実行します。</p>



<p>Thead内から、update_scrn (画面の更新処理) を呼び出します。</p>



<p>update_scrn では、高速化のためVRAM 上の値が前回と違う部分だけ更新するようにしています。</p>



<p>この中で、指定のX,Y 座標に文字を書き込む処理 DrawCharToSurface(X,Y,CharCode) を呼びだしています。</p>



<p>DrawCharToSurfaceでは、フォントデータに基づいてドットで画像を生成 ( PutPixel) しています。</p>



<p>PutPixel では、文字単位ではなくドット単位で書き込む処理が記述されています。</p>



<p>このように階層的に処理をしています。</p>



<h2 class="wp-block-heading">ランダムな情報をVRAMに書き込む</h2>



<p>まだ Z80が動いていないので、VRAMエリアに情報が書き込まれない状態ですので、とりあえずVRAMエリアにランダムに値を書き込みます。</p>



<pre class="wp-block-code"><code class="">procedure FillVRAMWithRandomChars;<br>var<br>  i: Integer;<br>begin<br>  Randomize;<br>  for i := 0 to 999 do<br>  begin<br>    Memory[$D000 + i] := Random(256);  // ランダムなキャラクターコード（0〜255）<br>  end;<br>end;   </code></pre>



<p>これで、元データはできあ゛かりますので、テストしてみましょう。</p>



<p>それと、プログラムがちゃんと動作していることを確かめるため、MZ700風に背景を青にして描画するようにしてみましょう。</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="576" src="https://expertgig.jp/wp/wp-content/uploads/2025/06/IMG_20250608_002026-1024x576.jpg" alt="" class="wp-image-6070" srcset="https://expertgig.jp/wp/wp-content/uploads/2025/06/IMG_20250608_002026-1024x576.jpg 1024w, https://expertgig.jp/wp/wp-content/uploads/2025/06/IMG_20250608_002026-300x169.jpg 300w, https://expertgig.jp/wp/wp-content/uploads/2025/06/IMG_20250608_002026-768x432.jpg 768w, https://expertgig.jp/wp/wp-content/uploads/2025/06/IMG_20250608_002026-1536x864.jpg 1536w, https://expertgig.jp/wp/wp-content/uploads/2025/06/IMG_20250608_002026-2048x1152.jpg 2048w, https://expertgig.jp/wp/wp-content/uploads/2025/06/IMG_20250608_002026-800x450.jpg 800w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>うまく行きました。</p>



<p>Z80部分もコンパイルできるところまでは修正したのですが、まだうまく動いていないので、とりあえず今日はVRAMの表示をスレッドでできたというところまで。</p>



<div class="wp-block-file"><a id="wp-block-file--media-11e68203-2e33-4c76-a816-bdaf13c6df1f" href="https://expertgig.jp/wp/wp-content/uploads/2025/06/VRAM_DRAW.zip">VRAM_DRAW</a><a href="https://expertgig.jp/wp/wp-content/uploads/2025/06/VRAM_DRAW.zip" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-11e68203-2e33-4c76-a816-bdaf13c6df1f">ダウンロード</a></div>



<p>今回は、Z80の実装とMZ80のハードウェア定義もすべてソースに含まれていますが、まだZ80の実装部分のテストができていないので、動作からは外しています。</p>



<p>しかし、Z80部分のDEBUGをどうやってやろうかな。今の開発のやり方だと、まともにデバッグできないので、Raspi の エミュレータを開発環境に絡めてやるしかないんだろうな。。また開発環境の設定を触るしかないね。</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://expertgig.jp/2025/06/08/raspi-zero-2w-%e3%83%99%e3%82%a2%e3%83%a1%e3%82%bf%e3%83%ab%e9%96%8b%e7%99%ba-mz80k%e3%81%aevram%e8%a1%a8%e7%a4%ba%e7%b7%a8/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
