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

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

unix.superglobalmegacorp.com

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