Annotation of nono/vm/mk48t02.cpp, revision 1.1.1.10

1.1       root        1: //
                      2: // nono
1.1.1.4   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: #include "mk48t02.h"
1.1.1.10! root        8: #include "bitops.h"
1.1.1.4   root        9: #include "mainapp.h"
1.1.1.7   root       10: #include "mpu.h"
1.1       root       11: 
                     12: //
                     13: // MK48T02
                     14: //
                     15: // SRAM 部分はビッグエンディアンのままメモリに置かれるので、
                     16: // 必要ならアクセス時に都度変換すること。
                     17: //
                     18: // 仕様は 0x45000000 から 2KB だが、
                     19: // 0x44000000 から 0x48000000 の手前まで 2KB 単位でミラーが見える。
                     20: 
1.1.1.10! root       21: // 繰り上がりについてのメモ。
        !            22: //
        !            23: // PROM で以下のようにすれば確認できる。
        !            24: //  >450007f8;l,80595923
        !            25: //  >450007fc;l,01DDMMYY
        !            26: //  >450007f8;,0
        !            27: //  >450007f8
        !            28: //
        !            29: // 2月の日数:
        !            30: //  2/30 -> 03/01
        !            31: //  2/31 -> 03/01
        !            32: //
        !            33: // 月ごとの日数:
        !            34: //  01/00/30 -> 01/01/01 (00月は小)
        !            35: //  01/0a/30 -> 01/0a/31 (0a月は大)
        !            36: //  01/0b/30 -> 01/14/01 (0b月は小)
        !            37: //  01/0c/30 -> 01/0c/31 (0c月は大)
        !            38: //  01/0d/30 -> 01/14/01 (0d月は小)
        !            39: //  01/0e/30 -> 01/0e/31 (0e月は大)
        !            40: //  01/0f/30 -> 01/18/01 (0f月は小)
        !            41: //  00/13/30 -> 01/00/01 (13月は小)
        !            42: //  01/14/30 -> 01/14/31 (14月は大)
        !            43: //  01/15/30 -> 01/16/01 (15月は小)
        !            44: //  01/16/30 -> 01/16/31 (16月は大)
        !            45: //  01/17/30 -> 02/08/01 (17月は小)
        !            46: //  01/18/30 -> 01/18/31 (18月は大)
        !            47: //  01/19/30 -> 01/10/01 (19月は小)
        !            48: //  01/1a/30 -> 01/1a/31 (1a月は大)
        !            49: //  01/1b/30 -> 01/10/01 (1b月は小)
        !            50: //  01/1c/30 -> 01/1c/31 (1c月は大)
        !            51: //  01/1d/30 -> 01/14/01 (1d月は小)
        !            52: //  01/1e/30 -> 01/1e/31 (1e月は大)
        !            53: //  01/1f/30 -> 01/18/01 (1f月は小)
        !            54: //
        !            55: // 月の繰り上がり後
        !            56: //  01/0a/31 -> 01/0b/01
        !            57: //  01/0b/31 -> 01/14/01
        !            58: //  01/0c/31 -> 01/0d/01
        !            59: //  01/0d/31 -> 01/14/01
        !            60: //  01/0e/31 -> 01/0f/01
        !            61: //  01/0f/31 -> 01/18/01
        !            62: //  00/13/30 -> 01/00/01       +Y
        !            63: //  01/14/31 -> 01/15/01
        !            64: //  01/15/31 -> 01/16/01
        !            65: //  01/16/31 -> 02/01/01       +Y
        !            66: //  01/17/31 -> 02/08/01       +Y
        !            67: //  01/18/31 -> 01/19/01
        !            68: //  01/19/31 -> 01/10/01
        !            69: //  01/1a/31 -> 02/09/01       +Y
        !            70: //  01/1b/31 -> 01/10/01
        !            71: //  01/1c/31 -> 01/1d/01
        !            72: //  01/1d/31 -> 01/14/01
        !            73: //  01/1e/31 -> 02/09/01       +Y
        !            74: //  01/1f/31 -> 01/18/01
        !            75: //
        !            76: // 日の繰り上がり(一部)
        !            77: //  01/01/0f -> 01/01/18
        !            78: //  01/01/3e -> 01/02/1f
        !            79: //  01/01/3f -> 01/01/2f
        !            80: //
        !            81: //  01/0a/28 -> 01/0b/01
        !            82: //  00/0a/28 -> 00/0a/29 (閏)
        !            83: //  00/0a/29 -> 00/0b/01
        !            84: //  00/0a/30 -> 00/0a/31
        !            85: //  00/0a/31 -> 00/0b/01
        !            86: //  00/0a/32 -> 00/0a/33
        !            87: //  00/0a/33 -> 00/0b/03
        !            88: //  00/0a/34 -> 00/0a/35
        !            89: //  00/0a/35 -> 00/0b/05
        !            90: //  00/0a/36 -> 00/0a/37
        !            91: //  00/0a/37 -> 00/0b/0f
        !            92: //  00/0a/38 -> 00/0b/19
        !            93: //  00/0a/39 -> 00/0a/21
        !            94: //  00/0b/34 -> 00/14/05
        !            95: //  00/0c/28 -> 00/0c/29
        !            96: //  00/0c/29 -> 00/0c/30
        !            97: //  00/0c/30 -> 00/0c/31
        !            98: //  00/0c/31 -> 00/0d/01
        !            99: //  00/0c/37 -> 00/0d/0f
        !           100: //  01/1a/28 -> 01/1a/29
        !           101: //
        !           102: // 0a 月は閏月として判定されるようだ。bit 0?010 でマッチかな
        !           103: 
1.1       root      104: MK48T02Device::MK48T02Device()
1.1.1.9   root      105:        : inherited("MK48T02")
1.1       root      106: {
1.1.1.9   root      107:        AddAlias("NVRAM");
                    108:        AddAlias("RTC");
                    109: 
1.1       root      110:        devaddr = 0x45000000;
1.1.1.9   root      111: 
1.1.1.10! root      112:        // 2021/07 時点の NetBSD/luna68k, OpenBSD/luna88k 合わせ。
        !           113:        // MK48T02 本来定義は 0 というか 1900 というか。
        !           114:        // see DecodeYear()
        !           115:        year_epoch = 1970;
        !           116:        use_localtime = false;
        !           117: 
1.1.1.9   root      118:        monitor.func = (MonitorCallback_t)&MK48T02Device::MonitorUpdate;
1.1.1.10! root      119:        monitor.SetSize(40, 13);
1.1.1.9   root      120:        monitor.Regist(ID_MONITOR_MK48T02);
1.1       root      121: }
                    122: 
                    123: MK48T02Device::~MK48T02Device()
                    124: {
                    125: }
                    126: 
                    127: bool
                    128: MK48T02Device::Init()
                    129: {
1.1.1.10! root      130:        if (inherited::Init() == false) {
        !           131:                return false;
        !           132:        }
        !           133: 
        !           134:        reg.ex = reg.in;
        !           135: 
        !           136:        // MK48T02 のデータシートには年には西暦年の下位2桁を設定するように
        !           137:        // 指示されている。
        !           138:        // しかし CMU Mach luna88k, NetBSD/luna68k, OpenBSD/luna88k はいずれも
        !           139:        // 西暦年から 1970 引いた値を設定するようになっている (2021/07 現在)。
        !           140:        // このため、うるう年が2年ずれた状態になる。
        !           141:        //
        !           142:        // NetBSD で MK48T02 を採用している luna68k 以外の port は
        !           143:        // ソースコード上の変数 year0 もしくは YEAR0 に
        !           144:        //  newsmips, news68k: 1900 (データシート規定通り)
        !           145:        //  sun3, sparc, mvme68k: 1968 (1968 はうるう年なので問題ない)
        !           146:        // を採用しており、バグっていない。
        !           147:        // この year0 は UNIX EPOCH とは直接関係がない RTC ハードウェアに
        !           148:        // 依存する値なのだが、LUNA では混同したのだろうか?
        !           149:        //
        !           150:        // たぶんこのバグはもう修正されることはないだろうから、こちらで補正する
        !           151:        // スイッチを用意した。
        !           152: 
        !           153:        int adjust_misused_epoch;
        !           154:        adjust_misused_epoch = gConfig->Find("luna-adjust-misused-epoch").AsInt();
        !           155:        if (adjust_misused_epoch) {
        !           156:                // エポック年のうるう年カウンタ相当を補正項として持つ
        !           157:                adjust_leap = year_epoch % 4;
        !           158:        } else {
        !           159:                adjust_leap = 0;
        !           160:        }
        !           161: 
1.1       root      162:        // ファイルのロード
1.1.1.3   root      163:        filename = gMainApp.GetVMDir() + "NVRAM.DAT";
1.1.1.4   root      164:        file.SetFilename(filename);
                    165:        file.SetDispname(string_format("NVRAM \"%s\"", filename.c_str()));
                    166:        mem = file.OpenCreate(2040);
                    167:        if (mem == NULL) {
1.1       root      168:                return false;
                    169:        }
                    170: 
                    171:        return true;
                    172: }
                    173: 
                    174: // バイナリ表現を BCD 表現に変換する
                    175: /*static*/ inline uint8
                    176: MK48T02Device::num2BCD(uint8 num)
                    177: {
                    178:        return ((num / 10) << 4) + (num % 10);
                    179: }
                    180: 
                    181: // BCD 表現をバイナリ表現に変換する
                    182: /*static*/ inline uint8
                    183: MK48T02Device::BCD2num(uint8 bcd)
                    184: {
                    185:        return (bcd >> 4) * 10 + (bcd & 0x0f);
                    186: }
                    187: 
                    188: uint64
1.1.1.7   root      189: MK48T02Device::Read(uint32 offset)
1.1       root      190: {
                    191:        uint32 data;
                    192: 
1.1.1.7   root      193:        if (offset < 2040) {
                    194:                data = mem[offset];
                    195:                putlog(3, "$%08x -> $%02x", gMPU->GetPaddr(), data);
1.1       root      196:        } else {
1.1.1.7   root      197:                switch (offset - 2040) {
1.1       root      198:                 case 0:        // コントロールレジスタ
                    199:                        data = reg.ctrl;
                    200:                        break;
                    201:                 case 1:        // 秒
1.1.1.10! root      202:                        data = reg.ex.sec | reg.stop;
1.1       root      203:                        break;
                    204:                 case 2:        // 分
1.1.1.10! root      205:                        data = reg.ex.min;
1.1       root      206:                        break;
                    207:                 case 3:        // 時
1.1.1.10! root      208:                        data = reg.ex.hour | reg.kickstart;
1.1       root      209:                        break;
                    210:                 case 4:        // 曜日
1.1.1.10! root      211:                        data = reg.ex.wday | reg.freqtest;
1.1       root      212:                        break;
                    213:                 case 5:        // 日
1.1.1.10! root      214:                        data = reg.ex.mday;
1.1       root      215:                        break;
                    216:                 case 6:        // 月
1.1.1.10! root      217:                        data = reg.ex.mon;
1.1       root      218:                        break;
                    219:                 case 7:        // 年
1.1.1.10! root      220:                        data = reg.ex.year;
1.1       root      221:                        break;
                    222:                 default:
1.1.1.3   root      223:                        __unreachable();
1.1       root      224:                }
                    225: 
1.1.1.7   root      226:                putlog(3, "$%08x -> $%02x", gMPU->GetPaddr(), data);
1.1       root      227:        }
                    228:        return data;
                    229: }
                    230: 
                    231: uint64
1.1.1.7   root      232: MK48T02Device::Write(uint32 offset, uint32 data)
1.1       root      233: {
1.1.1.7   root      234:        if (offset < 2040) {
                    235:                putlog(3, "$%08x <- $%02x", gMPU->GetPaddr(), data);
                    236:                mem[offset] = data;
1.1       root      237:        } else {
1.1.1.7   root      238:                putlog(3, "$%08x <- $%02x", gMPU->GetPaddr(), data);
1.1.1.10! root      239: 
1.1.1.7   root      240:                switch (offset - 2040) {
1.1       root      241:                 case 0:        // コントロール
                    242:                        WriteCtrl(data);
                    243:                        break;
                    244:                 case 1:        // 秒 (b7 は STOP BIT)
1.1.1.10! root      245:                        reg.stop = data & MK48T02Clock::STOP;
        !           246:                        reg.ex.sec = data & 0x7f;
1.1       root      247:                        break;
                    248:                 case 2:        // 分
1.1.1.10! root      249:                        reg.ex.min = data & 0x7f;
1.1       root      250:                        break;
                    251:                 case 3:        // 時 (b7 は KICK START)
1.1.1.10! root      252:                        reg.kickstart = data & MK48T02Clock::KICKSTART;
        !           253:                        reg.ex.hour = data & 0x3f;
1.1       root      254:                        break;
                    255:                 case 4:        // 曜日 (b6 は Frequency Test (未実装))
1.1.1.10! root      256:                        // データシートでは b7, b5, b4 は '0' とあるが実際には '1' が
        !           257:                        // 書き込める。書き込んだ '1' が内部クロックの更新でどうなるか
        !           258:                        // 未確認のため、とりあえず放置。
        !           259:                        reg.freqtest = data & MK48T02Clock::FREQTEST;
        !           260:                        reg.ex.wday = data & 0x07;
1.1       root      261:                        break;
                    262:                 case 5:        // 日
1.1.1.10! root      263:                        // データシートでは b7, b6 は '0' とあるが実際には b7 には '1' が
        !           264:                        // 書き込める (b6 には書き込めない)。b7 に書き込んだ '1' が内部
        !           265:                        // クロックの更新でどうなるか未確認のため、とりあえずは放置。
        !           266:                        reg.ex.mday = data & 0x3f;
1.1       root      267:                        break;
                    268:                 case 6:        // 月
1.1.1.10! root      269:                        reg.ex.mon = data & 0x1f;
1.1       root      270:                        break;
                    271:                 case 7:        // 年
1.1.1.10! root      272:                        reg.ex.year = data;
1.1       root      273:                        break;
                    274:                 default:
1.1.1.3   root      275:                        __unreachable();
1.1       root      276:                }
                    277:        }
                    278:        return 0;
                    279: }
                    280: 
                    281: uint64
1.1.1.7   root      282: MK48T02Device::Peek(uint32 offset)
1.1       root      283: {
1.1.1.7   root      284:        if (offset < 2040) {
                    285:                return mem[offset];
1.1       root      286:        } else {
1.1.1.7   root      287:                switch (offset - 2040) {
1.1       root      288:                 case 0:        // コントロールレジスタ
                    289:                        return reg.ctrl;
                    290:                 case 1:        // 秒 | STOP
1.1.1.10! root      291:                        return reg.ex.sec | reg.stop;
1.1       root      292:                 case 2:        // 分
1.1.1.10! root      293:                        return reg.ex.min;
1.1       root      294:                 case 3:        // 時
1.1.1.10! root      295:                        return reg.ex.hour | reg.kickstart;
1.1       root      296:                 case 4:        // 曜日
1.1.1.10! root      297:                        return reg.ex.wday | reg.freqtest;
1.1       root      298:                 case 5:        // 日
1.1.1.10! root      299:                        return reg.ex.mday;
1.1       root      300:                 case 6:        // 月
1.1.1.10! root      301:                        return reg.ex.mon;
1.1       root      302:                 case 7:        // 年
1.1.1.10! root      303:                        return reg.ex.year;
1.1       root      304:                 default:
1.1.1.3   root      305:                        __unreachable();
1.1       root      306:                }
                    307:        }
                    308: }
                    309: 
1.1.1.5   root      310: void
1.1.1.9   root      311: MK48T02Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root      312: {
1.1.1.10! root      313:        uint32 addr;
        !           314:        uint32 v;
        !           315:        int y = 0;
        !           316: 
1.1.1.9   root      317:        screen.Clear();
1.1       root      318: 
1.1.1.10! root      319:        // BCD なので %x で表示する
        !           320:        screen.Print(0, y++,
        !           321:                "Internal: %04d[%02x]/%02x/%02x(%s) %02x:%02x:%02x.%1x",
        !           322:                DecodeYear(reg.in.year), reg.in.year,
        !           323:                reg.in.mon, reg.in.mday, wdays[reg.in.wday],
        !           324:                reg.in.hour, reg.in.min, reg.in.sec, (uint32)((cnt >> 1) & 0xf));
        !           325:        screen.Print(0, y++,
        !           326:                "Register: %04d[%02x]/%02x/%02x(%s) %02x:%02x:%02x",
        !           327:                DecodeYear(reg.ex.year), reg.ex.year,
        !           328:                reg.ex.mon, reg.ex.mday, wdays[reg.ex.wday],
        !           329:                reg.ex.hour, reg.ex.min, reg.ex.sec);
        !           330:        screen.Print(0, y++, "TimeZone: %s",
        !           331:                use_localtime ? "Local" : "UTC");
        !           332:        screen.Print(0, y++, "Epoch   : %4d  (Adjust Leap: %d)",
        !           333:                year_epoch, adjust_leap);
        !           334:        y++;
        !           335: 
        !           336:        addr = 0x800;
        !           337:        v = Peek(--addr);
        !           338:        screen.Print(0, y++, "$%3x: $%02x (year=%02x)", addr, v, v);
        !           339:        v = Peek(--addr);
        !           340:        screen.Print(0, y++, "$%3x: $%02x (mon =%02x)", addr, v, v);
        !           341:        v = Peek(--addr);
        !           342:        screen.Print(0, y++, "$%3x: $%02x (date=%02x)", addr, v, v);
        !           343:        v = Peek(--addr);
        !           344:        screen.Print(0, y++, "$%3x: $%02x (wday=%02x  FT=%d)",
        !           345:                addr, v, (v & 0x07), (v & MK48T02Clock::FREQTEST) ? 1 : 0);
        !           346:        v = Peek(--addr);
        !           347:        screen.Print(0, y++, "$%3x: $%02x (hour=%02x  KS=%d)",
        !           348:                addr, v, (v & 0x3f), (v & MK48T02Clock::KICKSTART) ? 1 : 0);
        !           349:        v = Peek(--addr);
        !           350:        screen.Print(0, y++, "$%3x: $%02x (min =%02x)", addr, v, (v & 0x7f));
        !           351:        v = Peek(--addr);
        !           352:        screen.Print(0, y++, "$%3x: $%02x (sec =%02x  ST=%d)",
        !           353:                addr, v, (v & 0x7f), (v & MK48T02Clock::STOP) ? 1 : 0);
        !           354:        v = Peek(--addr);
        !           355:        screen.Print(0, y++, "$%3x: $%02x (W=%d R=%d)",
        !           356:                addr, v,
        !           357:                (v & MK48T02Clock::WRITE) ? 1 : 0,
        !           358:                (v & MK48T02Clock::READ)  ? 1 : 0);
1.1       root      359: }
                    360: 
                    361: // コントロールレジスタへの書き込み
                    362: void
                    363: MK48T02Device::WriteCtrl(uint32 data)
                    364: {
1.1.1.10! root      365:        bool write_fall = bit_falling(reg.ctrl, data, MK48T02Clock::WRITE);
        !           366: 
1.1       root      367:        reg.ctrl = data;
                    368: 
1.1.1.10! root      369:        // ホールドしているかどうかは状態なのでエッジではない
        !           370:        hold = (reg.ctrl & (MK48T02Clock::READ | MK48T02Clock::WRITE));
        !           371: 
        !           372:        if (write_fall) {
        !           373:                // WRITE ビットの立ち下がりエッジで
        !           374:                // 外部レジスタから内部カウンタへセット
        !           375:                reg.in = reg.ex;
        !           376:                // 分周段は規定されていないが意味的にクリアするほうが良いだろう
        !           377:                cnt = 0;
1.1       root      378:        }
                    379: }
                    380: 
1.1.1.10! root      381: uint
        !           382: MK48T02Device::GetSec() const
        !           383: {
        !           384:        return BCD2num(reg.in.sec);
        !           385: }
        !           386: 
        !           387: void
        !           388: MK48T02Device::SetSec(uint v)
        !           389: {
        !           390:        reg.in.sec = num2BCD(v);
        !           391: }
        !           392: 
        !           393: uint
        !           394: MK48T02Device::GetMin() const
        !           395: {
        !           396:        return BCD2num(reg.in.min);
        !           397: }
        !           398: 
        !           399: void
        !           400: MK48T02Device::SetMin(uint v)
        !           401: {
        !           402:        reg.in.min = num2BCD(v);
        !           403: }
        !           404: 
        !           405: uint
        !           406: MK48T02Device::GetHour() const
        !           407: {
        !           408:        return BCD2num(reg.in.hour);
        !           409: }
        !           410: 
        !           411: void
        !           412: MK48T02Device::SetHour(uint v)
        !           413: {
        !           414:        reg.in.hour = num2BCD(v);
        !           415: }
        !           416: 
        !           417: uint
        !           418: MK48T02Device::GetWday() const
        !           419: {
        !           420:        // データシートの正規の値範囲は 1..7 だが 0 も問題なく保持できて、
        !           421:        // NetBSD/luna68k, OpenBSD/luna88k は日付を日曜に変更する際には 0 を
        !           422:        // レジスタに書き込んでいる。そのためレジスタ値は 0 と 7 を日曜、
        !           423:        // 1を月曜…という運用ということにする。
        !           424:        // 戻り値は 0..6 (0が日曜)。
        !           425: 
        !           426:        int v = reg.in.wday;
        !           427:        if (v == 7) {
        !           428:                v = 0;
        !           429:        }
        !           430:        return v;
        !           431: }
        !           432: 
        !           433: void
        !           434: MK48T02Device::SetWday(uint v)
        !           435: {
        !           436:        // 引数は 0..6 (0が日曜)、MK48T02 の正規の範囲は 1..7 で曜日との対応は
        !           437:        // 運用依存のようだ。NetBSD/luna68k, OpenBSD/luna88k は 0 を日曜、1 を
        !           438:        // 月曜…と扱っているが、MK48T02 の曜日レジスタは 7 の翌日 1 に繰り上がる
        !           439:        // 動作なので、ここでもレジスタには 1..7 (1が月曜、7が日曜) をセットする。
        !           440:        if (v == 0)
        !           441:                v = 7;
        !           442:        reg.in.wday = v;
        !           443: }
        !           444: 
        !           445: uint
        !           446: MK48T02Device::GetMday() const
        !           447: {
        !           448:        return BCD2num(reg.in.mday);
        !           449: }
        !           450: 
        !           451: void
        !           452: MK48T02Device::SetMday(uint v)
        !           453: {
        !           454:        reg.in.mday = num2BCD(v);
        !           455: }
        !           456: 
        !           457: uint
        !           458: MK48T02Device::GetMon() const
        !           459: {
        !           460:        return BCD2num(reg.in.mon);
        !           461: }
        !           462: 
        !           463: void
        !           464: MK48T02Device::SetMon(uint v)
        !           465: {
        !           466:        reg.in.mon = num2BCD(v);
        !           467: }
        !           468: 
        !           469: uint
        !           470: MK48T02Device::DecodeYear(uint bcd_year) const
        !           471: {
        !           472:        uint y = BCD2num(bcd_year);
        !           473:        y += year_epoch;
        !           474: 
        !           475:        // 1970年より前を 2000 年代とみなすのはシステム依存だが
        !           476:        // UNIX 系はみんなこう(?)
        !           477:        // XXX ここの 1970 と RTC エポックを一致させれば端折れるじゃん!と
        !           478:        //     思いついたのかしら?
        !           479:        if (y < 1970) {
        !           480:                y += 100;
        !           481:        }
        !           482:        return y;
        !           483: }
        !           484: 
        !           485: uint
        !           486: MK48T02Device::GetYear() const
        !           487: {
        !           488:        // see DecodeYear()
        !           489:        return DecodeYear(reg.in.year);
        !           490: }
        !           491: 
        !           492: void
        !           493: MK48T02Device::SetYear(uint v)
        !           494: {
        !           495:        // see DecodeYear()
        !           496:        v -= year_epoch;
        !           497:        reg.in.year = num2BCD(v % 100);
        !           498: }
        !           499: 
        !           500: uint
        !           501: MK48T02Device::GetLeap() const
        !           502: {
        !           503:        // 補正項込みで計算
        !           504:        return (BCD2num(reg.in.year) + adjust_leap) & 3;
        !           505: }
        !           506: 
        !           507: void
        !           508: MK48T02Device::SetLeap(uint v)
        !           509: {
        !           510:        // nop
        !           511:        // MK48T02 ではうるう年カウンタはなく、西暦年でうるう年を判断している。
        !           512: }
        !           513: 
        !           514: // 1Hz 仮想 RTC からのコール
        !           515: // 分周段 0/32 秒でコールされる。
        !           516: void
        !           517: MK48T02Device::Tick1Hz()
        !           518: {
        !           519:        if (reg.stop) {
        !           520:                // 実機は電力消費を抑えるため発振器ごと止めるが、
        !           521:                // 分周段が規定されていないので秒カウントを止めれば十分なはず
        !           522:                //nop
        !           523:        } else {
        !           524:                CountUpSec();
        !           525:        }
        !           526: 
        !           527:        if (hold == false) {
        !           528:                // 毎秒コピーする (Datasheet p2)
        !           529:                reg.ex = reg.in;
        !           530:        }
1.1       root      531: }
1.1.1.3   root      532: 
                    533: // 指定したアドレスからのゼロ終端文字列を返す
                    534: // (内蔵 ROM からのアクセス用)
                    535: std::string
                    536: MK48T02Device::PeekString(uint32 addr) const
                    537: {
                    538:        std::string rv = "";
                    539: 
1.1.1.7   root      540:        addr &= 0x7ff;
                    541:        for (; mem[addr]; addr++) {
                    542:                rv += mem[addr];
1.1.1.3   root      543:        }
                    544:        return rv;
                    545: }
                    546: 
                    547: // 指定したアドレスに文字列を書き込み、
                    548: // 16 バイトに満たないところはゼロでパディングする。
                    549: // 書き込めれば true を、書き込めなければ false を返す。
                    550: // (内蔵 ROM からの書き込み用)
                    551: bool
                    552: MK48T02Device::WriteString(uint32 addr, const std::string& data)
                    553: {
                    554:        int i = 0;
                    555: 
1.1.1.9   root      556:        // ここの文字列は16バイト未満なら一見ゼロ終端のようだが、
                    557:        // 16バイトならゼロ終端せず16文字とするフォーマット。
                    558: 
                    559:        if (data.length() > 16) {
1.1.1.3   root      560:                return false;
                    561:        }
                    562: 
                    563:        addr &= 0x7ff;
                    564:        for (; i < data.length(); i++) {
1.1.1.9   root      565:                mem[addr + i] = data[i];
1.1.1.3   root      566:        }
                    567:        for (; i < 16; i++) {
1.1.1.9   root      568:                mem[addr + i] = 0;
1.1.1.3   root      569:        }
                    570:        return true;
                    571: }
1.1.1.9   root      572: 
                    573: // 全域をゼロクリアする。
                    574: // クリアするだけなので、その後何か書いたりチェックサムを計算したりする
                    575: // 必要はある。
                    576: // (内蔵 ROM からの書き込み用)
                    577: void
                    578: MK48T02Device::ClearAll()
                    579: {
                    580:        for (int i = 0, sz = file.GetMemSize(); i < sz; i++) {
                    581:                mem[i] = 0;
                    582:        }
                    583: }

unix.superglobalmegacorp.com

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