--- nono/vm/mk48t02.cpp 2026/04/29 17:04:28 1.1.1.1 +++ nono/vm/mk48t02.cpp 2026/04/29 17:04:39 1.1.1.5 @@ -1,12 +1,13 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // #include "mk48t02.h" -#include "configfile.h" -#include -#include +#include "config.h" +#include "mainapp.h" +#include "mystring.h" // // MK48T02 @@ -22,46 +23,27 @@ MK48T02Device::MK48T02Device() logname = "mk48t02"; devname = "MK48T02"; devaddr = 0x45000000; - monitor.Init(25, 2); - - fd = -1; + monitor_size = nnSize(25, 2); } MK48T02Device::~MK48T02Device() { - if (mem) { - munmap(mem, memlen); - mem = NULL; - } - if (fd >= 0) { - close(fd); - fd = -1; - } } bool MK48T02Device::Init() { // ファイルのロード - filename = gConfig->GetConfigDir() + "NVRAM.DAT"; - - fd = open(filename.c_str(), O_RDWR); - if (fd == -1) { - warn("%s: cannot open %s", devname, filename.c_str()); - return false; - } - - memlen = 2040; - mem = (uint8 *)mmap(NULL, memlen, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - if (mem == MAP_FAILED) { - close(fd); - warn("%s: cannot mmap %s", devname, filename.c_str()); + filename = gMainApp.GetVMDir() + "NVRAM.DAT"; + file.SetFilename(filename); + file.SetDispname(string_format("NVRAM \"%s\"", filename.c_str())); + mem = file.OpenCreate(2040); + if (mem == NULL) { return false; } // レジスタ値固定オプション (パフォーマンス測定用) - force_fixed = gConfig->ReadInt("rtc_force_fixed"); + force_fixed = gConfig->Find(".rtc-force-fixed").AsInt(); if (force_fixed) { putmsg("force_fixed"); } @@ -93,10 +75,9 @@ MK48T02Device::BCD2num(uint8 bcd) } uint64 -MK48T02Device::Read8(uint32 addr) +MK48T02Device::Read(uint32 addr) { - // アドレスは 2KB 単位でミラーになっている。 - uint32 an = addr & 0x7ff; + uint32 an = addr; uint32 data; if (an < 2040) { @@ -136,9 +117,7 @@ MK48T02Device::Read8(uint32 addr) data = reg.year; break; default: - putlog(0, "未実装バイト読み込み $%08x", addr); - data = 0xff; - break; + __unreachable(); } if (force_fixed) { @@ -153,44 +132,9 @@ MK48T02Device::Read8(uint32 addr) } uint64 -MK48T02Device::Read16(uint32 addr) +MK48T02Device::Write(uint32 addr, uint32 data) { - // アドレスは 2KB 単位でミラーになっている。 - uint32 an = addr & 0x7ff; - uint32 data; - - if (an < 2040) { - data = be16toh(*(uint16 *)&mem[an]); - putlog(3, "$%08x -> $%04x", addr, data); - } else { - putlog(0, "未実装ワード読み込み $%08x", addr); - data = 0xffff; - } - return data; -} - -uint64 -MK48T02Device::Read32(uint32 addr) -{ - // アドレスは 2KB 単位でミラーになっている。 - uint32 an = addr & 0x7ff; - uint32 data; - - if (an < 2040) { - data = be32toh(*(uint32 *)&mem[an]); - putlog(3, "$%08x -> $%08x", addr, data); - } else { - putlog(0, "未実装ロング読み込み $%08x", addr); - data = 0xffffffff; - } - return data; -} - -uint64 -MK48T02Device::Write8(uint32 addr, uint32 data) -{ - // アドレスは 2KB 単位でミラーになっている。 - uint32 an = addr & 0x7ff; + uint32 an = addr; if (an < 2040) { putlog(3, "$%08x <- $%02x", addr, data); @@ -238,48 +182,16 @@ MK48T02Device::Write8(uint32 addr, uint3 } break; default: - putlog(0, "未実装バイト書き込み $%08x <- %02x", addr, data); - break; + __unreachable(); } } return 0; } uint64 -MK48T02Device::Write16(uint32 addr, uint32 data) -{ - // アドレスは 2KB 単位でミラーになっている。 - uint32 an = addr & 0x7ff; - - if (an < 2040) { - putlog(3, "$%08x <- $%04x", addr, data); - *(uint16 *)&mem[an] = htobe16(data); - } else { - putlog(0, "未実装ワード書き込み $%08x <- %04x", addr, data); - } - return 0; -} - -uint64 -MK48T02Device::Write32(uint32 addr, uint32 data) +MK48T02Device::Peek(uint32 addr) { - // アドレスは 2KB 単位でミラーになっている。 - uint32 an = addr & 0x7ff; - - if (an < 2040) { - putlog(3, "$%08x <- $%08x", addr, data); - *(uint32 *)&mem[an] = htobe32(data); - } else { - putlog(0, "未実装ロング書き込み $%08x <- %08x", addr, data); - } - return 0; -} - -uint64 -MK48T02Device::Peek8(uint32 addr) -{ - // アドレスは 2KB 単位でミラーになっている。 - uint32 an = addr & 0x7ff; + uint32 an = addr; uint8 data; if (an < 2040) { @@ -311,13 +223,13 @@ MK48T02Device::Peek8(uint32 addr) case 7: // 年 return reg.year; default: - return 0xff; + __unreachable(); } } } -bool -MK48T02Device::MonitorUpdate() +void +MK48T02Device::MonitorUpdate(TextScreen& monitor) { monitor.Clear(); @@ -333,8 +245,6 @@ MK48T02Device::MonitorUpdate() rtc.year, rtc.mon, rtc.mday, wdays[rtc.wday]); monitor.Print(10, 1, "%02d:%02d:%02d", rtc.hour, rtc.min, rtc.sec); - - return true; } // コントロールレジスタへの書き込み @@ -382,3 +292,41 @@ MK48T02Device::ClockIn() // 内部表現とデバイスから読み出せる値が同じなので、更新処理は不要。 CountUp(); } + +// 指定したアドレスからのゼロ終端文字列を返す +// (内蔵 ROM からのアクセス用) +std::string +MK48T02Device::PeekString(uint32 addr) const +{ + std::string rv = ""; + + uint32 an = addr & 0x7ff; + for (; mem[an]; an++) { + rv += mem[an]; + } + return rv; +} + +// 指定したアドレスに文字列を書き込み、 +// 16 バイトに満たないところはゼロでパディングする。 +// 書き込めれば true を、書き込めなければ false を返す。 +// (内蔵 ROM からの書き込み用) +bool +MK48T02Device::WriteString(uint32 addr, const std::string& data) +{ + int i = 0; + + // XXX ここの文字列はゼロ終端なのかどうか + if (data.length() == 0 || data.length() > 15) { + return false; + } + + addr &= 0x7ff; + for (; i < data.length(); i++) { + Write(addr + i, data[i]); + } + for (; i < 16; i++) { + Write(addr + i, 0); + } + return true; +}