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

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

unix.superglobalmegacorp.com

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