|
|
nono 1.7.0
//
// nono
// Copyright (C) 2023 nono project
// Licensed under nono-license.txt
//
//
// Nereid バンクメモリ
//
// バンクメモリはロングワード単位でホストバイトオーダ配置なので、
// バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。
#include "bankram.h"
#include "config.h"
#include "mpu.h"
// コンストラクタ
BankRAMDevice::BankRAMDevice(uint objid_, int ram_size_MB)
: inherited(objid_)
{
// ram_size_MB は正数のみ。負数は親側で処理する。
assert(ram_size_MB >= 0);
ram_size = ram_size_MB * 1024 * 1024;
// 初期化は Init() で行う
}
// デストラクタ
BankRAMDevice::~BankRAMDevice()
{
}
// 初期化
bool
BankRAMDevice::Init()
{
ram.reset(new(std::nothrow) uint8[ram_size]);
if ((bool)ram == false) {
warnx("Could not allocate %u bytes at %s", ram_size, __method__);
return false;
}
wait = busdata::Wait(1 * mpu->GetClock_tsec());
return true;
}
// 電源オン/リセット
void
BankRAMDevice::ResetHard(bool poweron)
{
if (poweron) {
// ノイズで埋めたいがとりあえず。
memset(&ram[0], 0, ram_size);
}
// リセットでクリアされる。
SetPage(0);
memset(&accstat_read[0], 0, AccStat::BANKLEN);
memset(&accstat_write[0], 0, AccStat::BANKLEN);
}
inline uint32
BankRAMDevice::Decoder(uint32 addr) const
{
return pageaddr + (addr & 0xffff);
}
busdata
BankRAMDevice::Read(busaddr addr)
{
uint32 offset = Decoder(addr.Addr());
busdata data;
accstat_read[offset >> AccStat::SHIFT] = AccStat::READ;
data = *(uint32 *)&ram[offset & ~3U];
putlog(4, "$%06x ($%06x) -> $%08x", addr.Addr(), offset, data.Data());
data |= wait;
data |= BusData::Size4;
return data;
}
busdata
BankRAMDevice::Write(busaddr addr, uint32 data)
{
uint32 offset = Decoder(addr.Addr());
uint32 reqsize = addr.GetSize();
uint32 datasize = std::min(4 - (offset & 3U), reqsize);
accstat_write[offset >> AccStat::SHIFT] = AccStat::WRITE;
if (datasize == 4) {
putlog(3, "$%06x ($%06x) <- $%08x", addr.Addr(), offset, data);
*(uint32 *)&ram[offset] = data;
} else if (datasize == 1) {
data >>= (reqsize - datasize) * 8;
putlog(3, "$%06x ($%06x) <- $%02x", addr.Addr(), offset, data);
ram[HLB(offset)] = data;
} else {
data >>= (reqsize - datasize) * 8;
putlog(3, "$%06x ($%06x) <- $%0*x", addr.Addr(), offset,
datasize * 2, data);
for (int i = datasize - 1; i >= 0; i--) {
ram[HLB(offset + i)] = data;
data >>= 8;
}
}
busdata r = wait;
r |= BusData::Size4;
return r;
}
busdata
BankRAMDevice::Peek1(uint32 addr)
{
uint32 offset = Decoder(addr);
return ram[HLB(offset)];
}
bool
BankRAMDevice::Poke1(uint32 addr, uint32 data)
{
if ((int32)data >= 0) {
uint32 offset = Decoder(addr);
ram[HLB(offset)] = data;
}
return true;
}
void
BankRAMDevice::SetPage(uint32 page_)
{
page = page_;
// XXX 4MB の時の折返し確認
pageaddr = (page << 16) & (ram_size - 1);
putlog(2, "Page <- $%02x", page);
}
void
BankRAMDevice::FetchAccStat(uint8 *acc)
{
// 要素が8バイトと分かっていればこれだけで済む。
static_assert(AccStat::BANKLEN == 8, "");
// R|W をマージしながらコピー。
uint64 tmp;
tmp = *(uint64 *)&accstat_read[0];
tmp |= *(uint64 *)&accstat_write[0];
*(uint64 *)acc = tmp;
// 読んだのでリセット。
memset(&accstat_read[0], 0, AccStat::BANKLEN);
memset(&accstat_write[0], 0, AccStat::BANKLEN);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.