Annotation of nono/vm/rp5c15.cpp, revision 1.1.1.11

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.10  root        7: //
                      8: // RTC (RP5C15)
                      9: //
1.1       root       10: 
                     11: // アラームは未実装
                     12: 
1.1.1.10  root       13: #include "rp5c15.h"
1.1.1.11! root       14: #include "mfp.h"
1.1.1.10  root       15: #include "mpu.h"
1.1.1.11! root       16: #include "power.h"
1.1       root       17: 
1.1.1.10  root       18: // コンストラクタ
1.1       root       19: RP5C15Device::RP5C15Device()
1.1.1.8   root       20:        : inherited("RTC")
1.1       root       21: {
                     22:        devaddr = 0xe8a000;
                     23:        devlen  = 0x2000;
1.1.1.8   root       24: 
1.1.1.10  root       25:        // X68k の RTC epoch は 1980年固定で変更の必要はないので、設定も見ない。
1.1.1.9   root       26:        year_epoch = 1980;
1.1.1.10  root       27:        // X68k は通常ローカルタイム (というか JST) で使用する前提
1.1.1.9   root       28:        use_localtime = true;
                     29: 
1.1.1.10  root       30:        monitor.func = ToMonitorCallback(&RP5C15Device::MonitorUpdate);
1.1.1.9   root       31:        monitor.SetSize(41, 22);
1.1.1.8   root       32:        monitor.Regist(ID_MONITOR_RTC);
1.1       root       33: }
                     34: 
1.1.1.10  root       35: // デストラクタ
1.1       root       36: RP5C15Device::~RP5C15Device()
                     37: {
                     38: }
                     39: 
1.1.1.7   root       40: // 初期化
1.1       root       41: bool
1.1.1.7   root       42: RP5C15Device::Init()
1.1       root       43: {
1.1.1.9   root       44:        // デフォルトで 24 時間計にしておく
                     45:        reg.sel24 = 0x01;
                     46:        // デフォルトで 1HZ_ON, 16HZ_ON をネゲート(1)しておく
                     47:        reg.reset = RP5C15::RESET_1Hz | RP5C15::RESET_16Hz;
1.1       root       48: 
1.1.1.9   root       49:        return inherited::Init();
1.1       root       50: }
                     51: 
1.1.1.2   root       52: uint64
1.1.1.6   root       53: RP5C15Device::Read(uint32 offset)
1.1.1.2   root       54: {
                     55:        uint8 data;
                     56:        int n;
                     57: 
1.1.1.5   root       58:        gMPU->AddCycle(29);     // InsideOut p.135
                     59: 
1.1.1.3   root       60:        // バンクを展開する
1.1.1.9   root       61:        int bank = (reg.mode & RP5C15::MODE_BANK);
1.1.1.6   root       62:        n = bank * 0x10 + offset;
1.1       root       63: 
                     64:        // XXX 14, 15 は write only らしいが何が読めるか
                     65: 
                     66:        switch (n) {
                     67:         case 0x1d:     // MODE  (Bank0 と同じ)
                     68:         case 0x1e:     // TEST  (Bank0 と同じ)
                     69:         case 0x1f:     // RESET (Bank0 と同じ)
                     70:                n -= 0x10;
                     71:                FALLTHROUGH;
                     72: 
                     73:         case 0x00 ... 0x1c:
                     74:                data = reg.r[n];
                     75:                break;
                     76:         default:
1.1.1.3   root       77:                __unreachable();
1.1       root       78:        }
                     79: 
                     80:        // 下位4ビット(RP5C15) の中の未実装ビットは %0 だが
                     81:        // 上位4ビットは %1 になる。
                     82:        data |= 0xf0;
1.1.1.6   root       83:        putlog(2, "RTC Bank%d $%x -> $%02x", bank, offset, data);
1.1       root       84: 
                     85:        return data;
                     86: }
                     87: 
                     88: uint64
1.1.1.6   root       89: RP5C15Device::Write(uint32 offset, uint32 data)
1.1       root       90: {
                     91:        int n;
                     92: 
1.1.1.5   root       93:        gMPU->AddCycle(38);     // InsideOut p.135
                     94: 
1.1.1.3   root       95:        // バンクを展開する
1.1.1.9   root       96:        int bank = (reg.mode & RP5C15::MODE_BANK);
1.1.1.6   root       97:        n = bank * 0x10 + offset;
1.1       root       98: 
1.1.1.6   root       99:        putlog(2, "RTC Bank%d $%x <- $%x", bank, offset, (data & 0x0f));
1.1       root      100: 
                    101:        switch (n) {
                    102:         case RP5C15::SEC1:
                    103:         case RP5C15::SEC10:
                    104:         case RP5C15::MIN1:
                    105:         case RP5C15::MIN10:
1.1.1.9   root      106:         case RP5C15::HOUR1:
                    107:         case RP5C15::HOUR10:
                    108:         case RP5C15::WDAY:             // 曜日カウンタは日付などとは一切連動していない
1.1       root      109:         case RP5C15::DAY1:
                    110:         case RP5C15::DAY10:
                    111:         case RP5C15::MON1:
                    112:         case RP5C15::MON10:
                    113:         case RP5C15::YEAR1:
                    114:         case RP5C15::YEAR10:
1.1.1.9   root      115:         case RP5C15::SEL24:
                    116:         case RP5C15::LEAP:
                    117:                reg.r[n] = data & reg.mask[n];
1.1       root      118:                break;
                    119: 
                    120:         case RP5C15::CLKSEL:
1.1.1.9   root      121:                reg.clksel = data & reg.mask[n];
                    122:                switch (reg.clksel) {
                    123:                 case 0:        // ハイインピーダンス
                    124:                 case 1:        // 16384Hz
                    125:                 case 2:        // 1024Hz
                    126:                 case 3:        // 128Hz
                    127:                        // 128Hz 点滅とか点灯みたいなもんだろ(適当)
                    128:                        clkout = true;
                    129:                        break;
                    130: 
                    131:                        // (?) たぶん内部ではずっとカウンタ部分は動いていて
                    132:                        // 出力位置を切り替えているだけのはずなので、
                    133:                        // CLKSEL を変えた時の初期状態は内部カウンタの状態に依存するはず。
                    134:                 case 4:        // 16Hz
                    135:                        clkout = ((cnt & 1) == 0);
                    136:                        break;
                    137:                 case 5:        // 1Hz
                    138:                        clkout = ((cnt & 16) == 0);
                    139:                        break;
                    140:                 case 6:        // 1/60Hz
                    141:                        clkout = (cnt_60sec < 30);
                    142:                        break;
                    143:                 case 7:
                    144:                        clkout = false;
                    145:                        break;
                    146:                }
                    147:                break;
                    148: 
                    149:                // アラーム関係は未実装
                    150:         case RP5C15::ALARM_MIN1 ... RP5C15::ALARM_DAY10:
                    151:         case RP5C15::notused1:
                    152:         case RP5C15::notused2:
1.1       root      153:                // マスクして書き込む
                    154:                reg.r[n] = data & reg.mask[n];
                    155:                break;
                    156: 
                    157:         case RP5C15::ADJUST:
                    158:         {
                    159:                // %0 なら何もしない?
                    160:                if ((data & 1) == 0) {
                    161:                        break;
                    162:                }
                    163:                // %1 ならアジャスト。
                    164: 
                    165:                // 現在の秒が 0..29秒なら 0秒に切り下げ。
                    166:                // 30..59秒なら +1分0秒に繰り上げ。
                    167:                // いずれにしても 1秒と10秒の位は 0 にする。
1.1.1.9   root      168:                // XXX 秒以下のカウンタもクリアするのでは?
                    169:                if (GetSec() >= 30) {
1.1       root      170:                        // 1分繰り上げ
1.1.1.9   root      171:                        CountUpMin();
1.1       root      172:                }
1.1.1.9   root      173:                // マニュアルを読む限り秒以下をクリア(?)
                    174:                reg.sec1 = 0;
                    175:                reg.sec10 = 0;
                    176:                cnt = 0;
                    177:                clock_hold = false;
1.1       root      178:                break;
                    179:         }
                    180: 
                    181:         case RP5C15::MODE:
                    182:         case RP5C15::MODE_BANK1:
                    183:                reg.mode = data & reg.mask[RP5C15::MODE];
1.1.1.9   root      184: 
                    185:                if ((reg.mode & RP5C15::MODE_TIMER_EN)) {
                    186:                        if (clock_hold) {
                    187:                                // ホールドされていた秒カウントアップを実行
                    188:                                CountUpSec();
                    189:                                clock_hold = false;
                    190:                        }
                    191:                }
1.1       root      192:                break;
                    193: 
                    194:         case RP5C15::TEST:
                    195:         case RP5C15::TEST_BANK1:
                    196:                data &= reg.mask[RP5C15::TEST];
                    197:                if (data == 0) {
                    198:                        // 通常 0 を書き込むこと、となっているので 0 は許可
                    199:                } else {
1.1.1.11! root      200:                        putlog(0, "TEST <- $%1x (NOT IMPLEMENTED)", data);
1.1       root      201:                }
                    202:                reg.test = data;
                    203:                break;
                    204: 
                    205:         case RP5C15::RESET:
                    206:         case RP5C15::RESET_BANK1:
                    207:                reg.reset = data & reg.mask[RP5C15::RESET];
                    208:                if ((reg.reset & RP5C15::RESET_TIMER)) {
                    209:                        // %1 を書き込むと、秒未満の内部カウンタをリセット
1.1.1.9   root      210:                        // 繰り上がり分の保持も消す。
                    211:                        cnt = 0;
                    212:                        clock_hold = false;
                    213:                }
                    214:                if ((reg.reset & RP5C15::RESET_16Hz)) {
                    215:                        alarm_16Hz = false;
                    216:                }
                    217:                if ((reg.reset & RP5C15::RESET_1Hz)) {
                    218:                        alarm_1Hz = false;
1.1       root      219:                }
1.1.1.11! root      220:                ChangeAlarmOut();
1.1       root      221:                break;
                    222: 
                    223:         default:
                    224:                break;
                    225:        }
                    226:        return 0;
                    227: }
                    228: 
                    229: uint64
1.1.1.6   root      230: RP5C15Device::Peek(uint32 offset)
1.1       root      231: {
                    232:        int n;
                    233: 
1.1.1.3   root      234:        // バンクを展開する
1.1.1.9   root      235:        int bank = (reg.mode & RP5C15::MODE_BANK);
1.1.1.6   root      236:        n = bank * 0x10 + offset;
1.1       root      237: 
                    238:        switch (n) {
                    239:         case RP5C15::MODE_BANK1:
                    240:         case RP5C15::TEST_BANK1:
                    241:         case RP5C15::RESET_BANK1:
                    242:                // Bank0 と同じものが見える
                    243:                n -= 0x10;
                    244:                FALLTHROUGH;
                    245: 
                    246:         case 0x00 ... 0x1c:
                    247:                return reg.r[n] | 0xf0;
                    248: 
                    249:         default:
1.1.1.3   root      250:                __unreachable();
1.1       root      251:        }
                    252: }
                    253: 
1.1.1.4   root      254: void
1.1.1.8   root      255: RP5C15Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root      256: {
1.1.1.9   root      257:        int x = 18;
                    258:        int y = 0;
1.1       root      259: 
1.1.1.8   root      260:        screen.Clear();
1.1       root      261: 
1.1.1.9   root      262:        int year = reg.year10 * 10 + reg.year1 + year_epoch;
                    263:        int hour10;
                    264:        const char *ampm;
1.1       root      265:        if (reg.sel24) {
1.1.1.9   root      266:                ampm = "";
                    267:                hour10 = reg.hour10;
1.1       root      268:        } else {
1.1.1.9   root      269:                ampm = (reg.hour10 & 2) == 0 ? " AM": " PM";
                    270:                hour10 = reg.hour10 & 1;
1.1       root      271:        }
1.1.1.9   root      272:        screen.Print(0, y++, "%04d[%x%x]/%x%x/%x%x(%s) %x%x:%x%x:%x%x.%02x%s",
                    273:                year, reg.year10, reg.year1,
                    274:                reg.mon10, reg.mon1, reg.day10, reg.day1, wdays[reg.wday],
                    275:                hour10, reg.hour1, reg.min10, reg.min1, reg.sec10, reg.sec1,
                    276:                ((uint32)cnt & 0x1f), ampm);
                    277: 
                    278:        screen.Print(0, y, "TimeZone: %s", (use_localtime) ? "Local" : "UTC");
                    279:        screen.Print(x, y, "Epoch: %4d",  year_epoch);
                    280: 
                    281:        // バンク0
                    282:        y = 3;
                    283:        screen.Print(0, y++, "Bank0");
                    284:        static const char * const b0names[] = {
                    285:                " 1sec",
                    286:                "10sec",
                    287:                " 1min",
                    288:                "10min",
                    289:                " 1hour",
                    290:                "10hour",
                    291:                "wday",
                    292:                " 1day",
                    293:                "10day",
                    294:                " 1mon",
                    295:                "10mon",
                    296:                " 1year",
                    297:                "10year",
                    298:        };
                    299:        for (int i = 0; i < countof(b0names); i++) {
                    300:                screen.Print(0, y, "$%x(%s)", i, b0names[i]);
                    301:                screen.Print(10, y, ": %x", reg.r[i]);
                    302:                y++;
                    303:        }
                    304: 
                    305:        // バンク1
                    306:        y = 3;
                    307:        screen.Print(x, y++, "Bank1");
                    308:        static const char * const b1names[] = {
                    309:                "CLKSEL",
                    310:                "ADJ",
                    311:                "AL 1m",
                    312:                "AL10m",
                    313:                "AL 1h",
                    314:                "AL10h",
                    315:                "ALwday",
                    316:                "AL 1d",
                    317:                "AL10d",
                    318:                "",
                    319:                "12/24H",
                    320:                "LEAP",
                    321:                "",
                    322:        };
                    323:        for (int i = 0; i < countof(b1names); i++) {
                    324:                if (b1names[i][0] != '\0') {
                    325:                        screen.Print(x, y, "$%x(%s)", i, b1names[i]);
                    326:                        screen.Print(x + 10, y, ": %x", reg.r[16 + i]);
                    327:                } else {
                    328:                        // $9 と $c は欠番
                    329:                        screen.Print(x, y, "$%x - ", i);
                    330:                }
                    331:                y++;
                    332:        }
                    333: 
                    334:        // CLKSEL
                    335:        static const char * const clksel_s[] = {
                    336:                "HiZ",
                    337:                "16384Hz",
                    338:                "1024Hz",
                    339:                "128Hz",
                    340:                "16Hz",
                    341:                "1Hz",
                    342:                "1/60Hz",
                    343:                "L",
                    344:        };
                    345:        screen.Print(x + 14, 4, "(%s)", clksel_s[reg.clksel]);
                    346: 
                    347:        // 12/24H
                    348:        screen.Print(x + 14, 14, "(%dH)", reg.sel24 ? 24 : 12);
                    349: 
                    350:        // MODE
                    351:        y = 17;
                    352:        screen.Print(0, y, "$d(MODE):  %x", reg.mode);
                    353:        screen.Puts(13, y, TA::OnOff(reg.mode & RP5C15::MODE_TIMER_EN), "TIMER_EN");
                    354:        screen.Puts(22, y, TA::OnOff(reg.mode & RP5C15::MODE_ALARM_EN), "ALARM_EN");
                    355:        screen.Print(31, y, "BANK=%d", reg.mode & RP5C15::MODE_BANK);
                    356: 
                    357:        // TEST
1.1       root      358:        y++;
1.1.1.9   root      359:        screen.Print(0, y, "$e(TEST):  %x", reg.test);
1.1       root      360: 
1.1.1.9   root      361:        // RESET
1.1       root      362:        y++;
1.1.1.9   root      363:        screen.Print(0, y, "$f(RESET): %x", reg.reset);
                    364:        screen.Print(13, y, "1Hz=%s",
                    365:                (reg.reset & RP5C15::RESET_1Hz) ? "OFF" : "ON");
                    366:        screen.Print(21, y, "16Hz=%s",
                    367:                (reg.reset & RP5C15::RESET_16Hz) ? "OFF" : "ON");
                    368:        screen.Puts(30, y, TA::OnOff(reg.reset & RP5C15::RESET_TIMER), "TIMER");
                    369:        screen.Puts(36, y, TA::OnOff(reg.reset & RP5C15::RESET_ALARM), "ALARM");
1.1       root      370: 
1.1.1.9   root      371:        // PIN
1.1       root      372:        y++;
1.1.1.9   root      373:        y++;
                    374:        // ハードウェアの ~ALARM ピンは負論理なのでアクティブ L だが、
                    375:        // ここでは分かりやすさ優先で正論理としている。
                    376:        screen.Print(0, y, "Pin: CLKOUT=%c  ALARM=%c",
                    377:                clkout ? 'H' : 'L',
1.1.1.11! root      378:                alarm_out ? 'H' : 'L');
1.1.1.9   root      379: }
1.1       root      380: 
1.1.1.9   root      381: // 秒を取得
                    382: uint
                    383: RP5C15Device::GetSec() const
                    384: {
                    385:        return reg.sec10 * 10 + reg.sec1;
1.1       root      386: }
                    387: 
1.1.1.9   root      388: // 秒を設定
                    389: void
                    390: RP5C15Device::SetSec(uint v)
                    391: {
                    392:        reg.sec1  = v % 10;
                    393:        reg.sec10 = v / 10;
                    394: }
1.1       root      395: 
1.1.1.9   root      396: // 分を取得
                    397: uint
                    398: RP5C15Device::GetMin() const
                    399: {
                    400:        return reg.min10 * 10 + reg.min1;
                    401: }
                    402: 
                    403: // 分を設定
                    404: void
                    405: RP5C15Device::SetMin(uint v)
                    406: {
                    407:        reg.min1  = v % 10;
                    408:        reg.min10 = v / 10;
                    409: }
                    410: 
                    411: // 時を取得
                    412: uint
                    413: RP5C15Device::GetHour() const
                    414: {
                    415:        if (reg.sel24) {
                    416:                return reg.hour10 * 10 + reg.hour1;
                    417:        } else {
                    418:                int h10;
                    419:                h10 = (reg.hour10 & 0x1) * 10 + ((reg.hour10 & 0x2) >> 1) * 12;
                    420:                return h10 + reg.hour1;
                    421:        }
                    422: }
1.1       root      423: 
1.1.1.9   root      424: // 時を設定
                    425: void
                    426: RP5C15Device::SetHour(uint v)
                    427: {
                    428:        if (reg.sel24) {
                    429:                reg.hour1  = v % 10;
                    430:                reg.hour10 = v / 10;
                    431:        } else {
                    432:                int pm = (v < 12) ? 0x0 : 0x2;
                    433:                v %= 12;
                    434:                reg.hour1  = v % 10;
                    435:                reg.hour10 = v / 10 + pm;
                    436:        }
                    437: }
                    438: 
                    439: // 曜日を取得
                    440: uint
                    441: RP5C15Device::GetWday() const
                    442: {
                    443:        return reg.wday;
                    444: }
                    445: 
                    446: // 曜日を設定
                    447: void
                    448: RP5C15Device::SetWday(uint v)
                    449: {
                    450:        reg.wday = v;
                    451: }
                    452: 
                    453: // 日を取得
                    454: uint
                    455: RP5C15Device::GetMday() const
                    456: {
                    457:        return reg.day10 * 10 + reg.day1;
                    458: }
                    459: 
                    460: // 日を設定
                    461: void
                    462: RP5C15Device::SetMday(uint v)
                    463: {
                    464:        reg.day1  = v % 10;
                    465:        reg.day10 = v / 10;
                    466: }
                    467: 
                    468: // 月を取得
                    469: uint
                    470: RP5C15Device::GetMon() const
                    471: {
                    472:        return reg.mon10 * 10 + reg.mon1;
                    473: }
                    474: 
                    475: // 月を設定
                    476: void
                    477: RP5C15Device::SetMon(uint v)
                    478: {
                    479:        reg.mon1  = v % 10;
                    480:        reg.mon10 = v / 10;
                    481: }
                    482: 
                    483: // 年を取得
                    484: uint
                    485: RP5C15Device::GetYear() const
                    486: {
                    487:        return reg.year10 * 10 + reg.year1 + year_epoch;
                    488: }
                    489: 
                    490: // 年を設定
                    491: void
                    492: RP5C15Device::SetYear(uint v)
                    493: {
                    494:        v -= year_epoch;
                    495:        reg.year1  = v % 10;
                    496:        reg.year10 = v / 10;
                    497: }
                    498: 
                    499: uint
                    500: RP5C15Device::GetLeap() const
                    501: {
                    502:        return reg.leap;
                    503: }
                    504: 
                    505: void
                    506: RP5C15Device::SetLeap(uint v)
                    507: {
                    508:        reg.leap = v & 3;
                    509: }
                    510: 
1.1.1.11! root      511: // ALARM OUT 信号
        !           512: void
        !           513: RP5C15Device::ChangeAlarmOut()
        !           514: {
        !           515:        bool old = alarm_out;
        !           516: 
        !           517:        // アラーム出力は内部のアラーム用 16Hz, 1Hz と
        !           518:        // アラーム時刻一致の alarm_on との OR 論理となっている。
        !           519:        alarm_out = alarm_16Hz | alarm_1Hz | alarm_on;
        !           520: 
        !           521:        if (old != alarm_out) {
        !           522:                gPower->SetAlarmOut(alarm_out);
        !           523:                gMFP->SetAlarmOut(alarm_out);
        !           524:        }
        !           525: }
        !           526: 
1.1.1.9   root      527: // 32Hz 仮想 RTC からのコール
                    528: void
                    529: RP5C15Device::Tick32Hz()
                    530: {
                    531:        if (reg.clksel == 4) {
1.1.1.10  root      532:                // CLKOUT 16Hz は duty50% なのでオン/オフ駆動は 32Hz になる
1.1.1.9   root      533:                clkout = ((cnt & 1) == 0);
                    534:        }
                    535: 
                    536:        // ALARM 端子の 16Hz パルスも CLKOUT に同期するとは書いてないけど、
                    537:        // 面倒なのでとりあえず同じところで処理してしまう。
                    538:        // データシートの書き方的には同じ波形になると思われる。
                    539: 
                    540:        // アラーム端子 16Hz パルス出力は %0 ならオン
                    541:        if ((reg.reset & RP5C15::RESET_16Hz) == 0) {
                    542:                alarm_16Hz = !alarm_16Hz;
1.1.1.11! root      543:                ChangeAlarmOut();
1.1.1.9   root      544:        }
                    545: }
                    546: 
                    547: // 2Hz 仮想 RTC からのコール
                    548: // 分周段 0/32, 16/32 秒でコールされる。
                    549: void
                    550: RP5C15Device::Tick2Hz()
                    551: {
                    552:        if (reg.clksel == 5) {
1.1.1.10  root      553:                // CLKOUT 1Hz は duty50% なのでオン/オフ駆動は 2Hz になる。
1.1       root      554:                // CLKOUT 端子は秒の繰り上がりに同期している。
                    555:                // TIMER_EN (秒への繰り上がり) が無効でも反転自体は起きる気が
                    556:                // するので、ここでは UPDATE_SEC ではなく cnt で判定する。
1.1.1.10  root      557:                // CLKOUT は 1秒の繰り上がりが起きる時に 'H' になる。
1.1       root      558: 
1.1.1.9   root      559:                clkout = ((cnt & 15) == 0);
                    560:        }
1.1       root      561: 
1.1.1.9   root      562:        // ALARM 端子の 1Hz パルスも CLKOUT に同期するとは書いてないけど、
                    563:        // 面倒なのでとりあえず同じところで処理してしまう。
                    564:        // データシートの書き方的には同じ波形になると思われる。
1.1       root      565: 
1.1.1.9   root      566:        // アラーム端子 16Hz パルス出力は %0 ならオン
                    567:        if ((reg.reset & RP5C15::RESET_1Hz) == 0) {
                    568:                alarm_1Hz = !alarm_1Hz;
1.1.1.11! root      569:                ChangeAlarmOut();
1.1       root      570:        }
                    571: }
                    572: 
1.1.1.9   root      573: // 1Hz 仮想 RTC からのコール
                    574: // 分周段 0/32 秒でコールされる。
1.1       root      575: void
1.1.1.9   root      576: RP5C15Device::Tick1Hz()
1.1       root      577: {
1.1.1.9   root      578:        if ((reg.mode & RP5C15::MODE_TIMER_EN)) {
                    579:                // 秒カウンタ更新
                    580:                CountUpSec();
                    581:        } else {
                    582:                // 秒カウンタは更新させない。内部のクロックホールドをアサート。
                    583:                clock_hold = true;
                    584:        }
                    585: 
                    586:        // CLKOUT 1/60 Hz については
                    587:        // 「秒のカウントアップのタイミングでアップエッジ」
                    588:        // としか書かれておらず、00 or 30 秒で動作するとは書かれていない。
                    589:        // データシートの図からはカレンダとは独立しているように読める。
                    590: 
1.1.1.10  root      591:        // 1/60Hz CLKOUT のための 60sec カウンタ。
1.1.1.9   root      592:        // このカウンタは clksel によらず常にカウントする。
                    593:        cnt_60sec++;
                    594:        if (cnt_60sec == 60) {
                    595:                cnt_60sec = 0;
1.1       root      596:        }
                    597: 
1.1.1.9   root      598:        if (reg.clksel == 6) {
1.1.1.10  root      599:                // CLKOUT 1/60Hz は duty50% なのでオン/オフ駆動は 30sec になる
1.1.1.9   root      600:                clkout = (cnt_60sec < 30);
1.1       root      601:        }
                    602: }
                    603: 
                    604: /*static*/ const uint8
                    605: RP5C15::mask[] = {
                    606:        0x0f,   0x07,   0x0f,   0x07,   // 1秒 10秒   1分            10分
                    607:        0x0f,   0x03,   0x07,   0x0f,   // 1時 10時   曜日  1日
                    608:        0x01,   0x0f,   0x01,   0x0f,   // 10日        1月            10月   1年
                    609:        0x0f,   0x0d,   0x0f,   0x0f,   // 10年        MODE    TEST    RESET
                    610: 
                    611:        0x07,   0x01,   0x0f,   0x07,   // CLKO Adjust  AL1分  AL10分
                    612:        0x0f,   0x03,   0x07,   0x0f,   // AL1時 AL10時       AL曜日        AL1日
                    613:        0x03,   0x00,   0x01,   0x03,   // AL10日 ---  12/24   閏年
                    614:        0x00                                                    // ---
                    615: };

unix.superglobalmegacorp.com

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