File:  [Isaki's NoNo m68k/m88k emulator] / nono / wx / wxaccstatmonitor.cpp
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:57 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2024 nono project
// Licensed under nono-license.txt
//

//
// アクセス状況 (グラフィカル) ウィンドウ
//

// パネルには WXTextScreen 同様に四辺に DefaultPadding を手動で入れてある。

#include "wxaccstatmonitor.h"
#include "wxtextscreen.h"
#include "bankram.h"
#include "mainapp.h"
#include "mainbus.h"
#include "monitor.h"

//
// アクセス状況 (グラフィカル) パネル
//

// コンストラクタ
WXAccStatPanel::WXAccStatPanel(wxWindow *parent, Monitor *monitor_)
	: inherited(parent, monitor_)
{
	SetName("AccStatPanel");

	// デバイスを取得
	mainbus = GetMainbusDevice();

	// バンクメモリ描画のため
	is_x68030 = gMainApp.IsX68030();
	if (is_x68030) {
		for (int n = 0; n < 2; n++) {
			auto bankdev = gMainApp.FindObject<BankRAMDevice>(OBJ_BANKRAM(n));
			bankram[n] = (bankdev != NULL);
		}
	}

	FontChanged();
}

// デストラクタ
WXAccStatPanel::~WXAccStatPanel()
{
}

void
WXAccStatPanel::FontChanged()
{
	inherited::FontChanged();

	auto monsz = mainbus->accstat_monitor->GetSize();
	wxSize size(
		WXTextScreen::DefaultPadding * 2 + monsz.width * font_width,
		WXTextScreen::DefaultPadding * 2 + monsz.height * font_height);

	// バックバッファのサイズを固定。
	SetMinBitmapSize(size);

	SetSize(size);
	SetMinSize(size);

	redraw_header = true;
}

void
WXAccStatPanel::Draw()
{
	const int padding = WXTextScreen::DefaultPadding;
	const auto& accstat_rw = mainbus->accstat_rw;
	const auto& accstat_avail = mainbus->accstat_avail;
	int rows = accstat_rw.size() / 64;
	uint fw = font_width;
	uint fh = font_height;

	// 8文字分(16MB) ごとに 0.5 文字分ずつ空ける
	int width8 = fw * 8 + (fw / 2);

	if (redraw_header) {
		redraw_header = false;

		char buf[80];
		static_assert(AccStat::SHIFT >= 20, "");
		snprintf(buf, sizeof(buf),
			"Show %ubit space. %uMB/piece. ' ':Read, ' ':Write(+Read)",
			mainbus->accstat_bitlen, 1U << (AccStat::SHIFT - 20));
		DrawStringSJIS(padding, padding, buf);

		bitmap.FillRect(UD_GREEN, padding + fw * 30, padding, fw - 1, fh - 1);
		bitmap.FillRect(UD_RED, padding + fw * 40, padding, fw - 1, fh - 1);

		for (uint i = 0; i < 8; i++) {
			snprintf(buf, sizeof(buf), "+$0%x", i);
			DrawStringSJIS(padding + fw * 12 + width8 * i,
				padding + fh * 1, buf);
		}

		uint baseaddr;
		if (accstat_rw.size() == mainbus->accstat_read.size()) {
			baseaddr = 0;
		} else {
			baseaddr = 0xc0;
		}

		for (int y = 0; y < rows; y++) {
			snprintf(buf, sizeof(buf), "$%02x00'0000:",
				(uint8)(baseaddr + y * 0x08));
			DrawStringSJIS(padding, padding + fh * (y + 2), buf);
		}

		if (is_x68030) {
			for (int n = 0; n < 2; n++) {
				snprintf(buf, sizeof(buf), "BankMem #%u:", n);
				DrawStringSJIS(padding, padding + fh * (35 + n), buf);
			}
		}
	}

	// UD_{RED,GREEN} から UD_LIGHT_GREY まで HSV の S,V を線形補間。
	static const Color cols[8] = {
		UD_RED,					// HSV(18, 100, 100)
		UD_GREEN,				// HSV(162, 98,  69)
		Color(242, 115,  60),	// HSV(18,  75,  95)
		Color(47,  183, 142),	// HSV(162, 74,  72)
		Color(229, 149, 114),	// HSV(18,  50,  90)
		Color(97,  191, 163),	// HSV(162, 49,  75)
		Color(216, 178, 162),	// HSV(18,  25,  85)
		Color(149, 196, 182),	// HSV(162, 24,  77)
	};
	//	UD_LIGHT_GREY			// HSV(240,  1,  80)

	uint py = padding + fh * 2;
	for (int y = 0; y < rows; y++) {
		const uint8 *a = &mainbus->accstat_rw[y * 64];
		uint8 avail = accstat_avail[y];
		uint px = padding + fw * 12;

		for (int i = 0; i < 8; i++) {
			if ((int8)avail < 0) {
				// 何かしらデバイスがある 16MB (8文字相当) 分。
				for (int j = 0; j < 8; j++, a++, px += fw) {
					uint8 op = *a;
					Color c;
					if (__predict_true(op == 0)) {
						c = UD_LIGHT_GREY;
					} else {
						c = cols[__builtin_ctz(op)];
					}
					bitmap.DrawLineH(c, px, py, px + fw - 1);
				}
			} else {
				// この 16MB には何のデバイスもない。
				a += 8;
				// 事故がなければこれなくても動くはず
				//bitmap.DrawLineH(BGPANEL, px, py, px + fw * 8 - 1);
				px += fw * 8;
			}
			avail <<= 1;
			px += fw / 2;
		}

		// 1ラスターを縦1文字分に展開
		CopyLine(12, py, 68);
		py += fh;
	}

	// バンクメモリ
	if (is_x68030) {
		for (int n = 0; n < 2; n++) {
			if (bankram[n]) {
				py = padding + fh * (35 + n);
				const uint8 *a = &mainbus->accbank[n * AccStat::BANKLEN];
				uint px = padding + fw * 12;

				for (int j = 0; j < 8; j++, a++, px += fw) {
					uint8 op = *a;
					Color c;
					if (__predict_true(op == 0)) {
						c = UD_LIGHT_GREY;
					} else {
						c = cols[__builtin_ctz(op)];
					}
					bitmap.DrawLineH(c, px, py, px + fw - 1);
				}

				// 1ラスターを縦1文字分に展開
				CopyLine(12, py, 8);
			}
		}
	}
}

// 1ラスターを縦1文字分に展開する。
// ただの共通下請けなので引数に汎用性はない。
// cx は文字単位の X 座標 (左端の1文字目が 0、次の文字が 1)。
// py はピクセル単位の Y 座標。
// clen はコピーする文字数。
// (cxをピクセルにした座標, py) から clen 文字分の長さを次ラスターから
// (font_height - 1) ラスターまでにコピーする。
void
WXAccStatPanel::CopyLine(int cx, int py, int clen)
{
	const int padding = WXTextScreen::DefaultPadding;
	int px = padding + font_width * cx;
	Rect rect(px, py, clen * font_width, font_height - 1);

	bitmap.CopyFromTop(rect);
}


//
// アクセス状況 (グラフィカル) ウィンドウ
//

// コンストラクタ
WXAccStatWindow::WXAccStatWindow(wxWindow *parent, Monitor *monitor_)
	: inherited(parent, wxID_ANY, _("Access Status"))
{
	new WXAccStatPanel(this, monitor_);
	Fit();
}

// デストラクタ
WXAccStatWindow::~WXAccStatWindow()
{
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.