|
|
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()
{
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.