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

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2018 [email protected]
                      4: //
                      5: 
                      6: #include "rp5c15.h"
                      7: #include <sys/time.h>
                      8: 
                      9: // アラームは未実装
                     10: 
                     11: // XXX RTC の読み書きはロックしたほうがいいような気がする
                     12: 
                     13: RP5C15Device::RP5C15Device()
                     14: {
                     15:        logname = "rtc";
                     16:        devname = "RTC";
                     17:        devaddr = 0xe8a000;
                     18:        devlen  = 0x2000;
                     19:        monitor.Init(30, 17);
                     20: }
                     21: 
                     22: RP5C15Device::~RP5C15Device()
                     23: {
                     24: }
                     25: 
                     26: // RTC を初期化
                     27: bool
                     28: RP5C15Device::InitRTC()
                     29: {
                     30:        // ホストの時刻をローカル時刻で取得
                     31:        LoadHostRTC(true);
                     32: 
                     33:        // それをレジスタに反映。
                     34:        UpdateReg(UPDATE_ALL);
                     35: 
                     36:        return true;
                     37: }
                     38: 
1.1.1.2 ! root       39: // アドレスデコーダ
        !            40: inline uint64
        !            41: RP5C15Device::Decoder(uint32 addr) const
1.1       root       42: {
1.1.1.2 ! root       43:        // XXX 折り返しは
1.1       root       44: 
                     45:        // 偶数アドレスへのアクセスは先にエラーにする
1.1.1.2 ! root       46:        if ((addr & 1) == 0)
1.1       root       47:                return (uint64)-1;
                     48: 
                     49:        // Bank0 を 0..15、Bank1 を 16..31 に並べる
1.1.1.2 ! root       50:        return ((addr - devaddr) / 2) + bank * 0x10;
        !            51: }
        !            52: 
        !            53: uint64
        !            54: RP5C15Device::Read8(uint32 addr)
        !            55: {
        !            56:        uint8 data;
        !            57:        int n;
        !            58: 
        !            59:        n = Decoder(addr);
1.1       root       60: 
                     61:        // XXX 14, 15 は write only らしいが何が読めるか
                     62: 
                     63:        switch (n) {
                     64:         case 0x1d:     // MODE  (Bank0 と同じ)
                     65:         case 0x1e:     // TEST  (Bank0 と同じ)
                     66:         case 0x1f:     // RESET (Bank0 と同じ)
                     67:                n -= 0x10;
                     68:                FALLTHROUGH;
                     69: 
                     70:         case 0x00 ... 0x1c:
                     71:                data = reg.r[n];
                     72:                break;
                     73: 
                     74:         default:
                     75:                putlog(2, "RTC $%06x 未実装領域読み込み", addr);
                     76:                return 0xf0;
                     77:        }
                     78: 
                     79:        // 下位4ビット(RP5C15) の中の未実装ビットは %0 だが
                     80:        // 上位4ビットは %1 になる。
                     81:        data |= 0xf0;
                     82:        putlog(2, "RTC Bank%d $%x -> $%02x", bank, (n & 0x0f), data);
                     83: 
                     84:        return data;
                     85: }
                     86: 
                     87: uint64
                     88: RP5C15Device::Read16(uint32 addr)
                     89: {
                     90:        return 0xff00 | Read8(addr + 1);
                     91: }
                     92: 
                     93: uint64
                     94: RP5C15Device::Write8(uint32 addr, uint32 data)
                     95: {
                     96:        int n;
                     97: 
1.1.1.2 ! root       98:        n = Decoder(addr);
1.1       root       99: 
                    100:        putlog(2, "RTC Bank%d $%x <- $%x", bank, (n & 0x0f), (data & 0x0f));
                    101: 
                    102:        switch (n) {
                    103:         case RP5C15::SEC1:
                    104:                rtc.sec = reg.sec10 * 10 + (data & reg.mask[n]);
                    105:                UpdateReg(UPDATE_SEC);
                    106:                break;
                    107:         case RP5C15::SEC10:
                    108:                rtc.sec = (data & reg.mask[n]) * 10 + reg.sec1;
                    109:                UpdateReg(UPDATE_SEC);
                    110:                break;
                    111: 
                    112:         case RP5C15::MIN1:
                    113:                rtc.min = reg.min10 * 10 + (data & reg.mask[n]);
                    114:                UpdateReg(UPDATE_MIN);
                    115:                break;
                    116:         case RP5C15::MIN10:
                    117:                rtc.min = (data & reg.mask[n]) * 10 + reg.min1;
                    118:                UpdateReg(UPDATE_MIN);
                    119:                break;
                    120: 
                    121:         case RP5C15::HOUR1:    // hour1
                    122:                if (reg.sel24) {
                    123:                        // 24時間計
                    124:                        rtc.hour = reg.hour10 * 10 + (data & reg.mask[n]);
                    125:                } else {
                    126:                        // 12時間計
                    127:                        rtc.hour = ((reg.hour10 & 0x02) ? 12 : 0)
                    128:                                  + (reg.hour10 & 0x01) * 10 + (data & reg.mask[n]);
                    129:                }
                    130:                UpdateReg(UPDATE_HOUR);
                    131:                break;
                    132:         case RP5C15::HOUR10:   // hour10
                    133:                if (reg.sel24) {
                    134:                        // 24時間計
                    135:                        rtc.hour = (data & reg.mask[n]) * 10 + reg.hour1;
                    136:                } else {
                    137:                        // 12時間計
                    138:                        rtc.hour = ((data & 0x02) ? 12 : 0)
                    139:                                  + (data & 0x01) * 10 + reg.hour1;
                    140:                }
                    141:                UpdateReg(UPDATE_HOUR);
                    142:                break;
                    143: 
                    144:         case RP5C15::WDAY:
                    145:                // 曜日カウンタは日付などとは一切連動していない
                    146:                rtc.wday = data & reg.mask[n];
                    147:                UpdateReg(UPDATE_DAY);
                    148:                break;
                    149: 
                    150:         case RP5C15::DAY1:
                    151:                rtc.mday = reg.day10 * 10 + (data & reg.mask[n]);
                    152:                UpdateReg(UPDATE_DAY);
                    153:                break;
                    154:         case RP5C15::DAY10:
                    155:                rtc.mday = (data & reg.mask[n]) * 10 + reg.day1;
                    156:                UpdateReg(UPDATE_DAY);
                    157:                break;
                    158: 
                    159:         case RP5C15::MON1:
                    160:                rtc.mon = reg.mon10 * 10 + (data & reg.mask[n]);
                    161:                UpdateReg(UPDATE_MON);
                    162:                break;
                    163:         case RP5C15::MON10:
                    164:                rtc.mon = (data & reg.mask[n]) * 10 + reg.mon1;
                    165:                UpdateReg(UPDATE_MON);
                    166:                break;
                    167: 
                    168:         case RP5C15::YEAR1:
                    169:                rtc.year = 1980 + (reg.year10 * 10) + (data & reg.mask[n]);
                    170:                UpdateReg(UPDATE_YEAR);
                    171:                break;
                    172:         case RP5C15::YEAR10:
                    173:                rtc.year = 1980 + (data & reg.mask[n]) * 10 + reg.year1;
                    174:                UpdateReg(UPDATE_YEAR);
                    175:                break;
                    176: 
                    177:         case RP5C15::CLKSEL:
                    178:         case 0x12 ... 0x1c:
                    179:                // マスクして書き込む
                    180:                reg.r[n] = data & reg.mask[n];
                    181:                break;
                    182: 
                    183:         case RP5C15::ADJUST:
                    184:         {
                    185:                // %0 なら何もしない?
                    186:                if ((data & 1) == 0) {
                    187:                        break;
                    188:                }
                    189:                // %1 ならアジャスト。
                    190: 
                    191:                // 現在の秒が 0..29秒なら 0秒に切り下げ。
                    192:                // 30..59秒なら +1分0秒に繰り上げ。
                    193:                // いずれにしても 1秒と10秒の位は 0 にする。
                    194:                uint32 updates = UPDATE_SEC;
                    195:                if (rtc.sec < 30) {
                    196:                        // 1分切り下げ
                    197:                        rtc.sec = 0;
                    198:                } else {
                    199:                        // 1分繰り上げ
                    200:                        rtc.sec = 0;
                    201:                        updates = CarryMin(updates);
                    202:                }
                    203:                UpdateReg(updates);
                    204:                break;
                    205:         }
                    206: 
                    207:         case RP5C15::MODE:
                    208:         case RP5C15::MODE_BANK1:
                    209:                reg.mode = data & reg.mask[RP5C15::MODE];
                    210:                // bank を更新
                    211:                bank = (data & RP5C15::MODE_BANK);
                    212:                break;
                    213: 
                    214:         case RP5C15::TEST:
                    215:         case RP5C15::TEST_BANK1:
                    216:                data &= reg.mask[RP5C15::TEST];
                    217:                if (data == 0) {
                    218:                        // 通常 0 を書き込むこと、となっているので 0 は許可
                    219:                } else {
                    220:                        putlog(0, "TEST <- $%1x 未実装書き込み", data);
                    221:                }
                    222:                reg.test = data;
                    223:                break;
                    224: 
                    225:         case RP5C15::RESET:
                    226:         case RP5C15::RESET_BANK1:
                    227:                reg.reset = data & reg.mask[RP5C15::RESET];
                    228:                if ((reg.reset & RP5C15::RESET_TIMER)) {
                    229:                        // %1 を書き込むと、秒未満の内部カウンタをリセット
                    230:                        // 繰り上がり分の保持も消えるけどいいよな?
                    231:                        rtc.cnt = 0;
                    232:                }
                    233:                break;
                    234: 
                    235:         default:
                    236:                break;
                    237:        }
                    238:        return 0;
                    239: }
                    240: 
                    241: uint64
                    242: RP5C15Device::Write16(uint32 addr, uint32 data)
                    243: {
                    244:        return Write8(addr + 1, data);
                    245: }
                    246: 
                    247: uint64
                    248: RP5C15Device::Peek8(uint32 addr)
                    249: {
                    250:        int n;
                    251: 
1.1.1.2 ! root      252:        n = Decoder(addr);
1.1       root      253: 
                    254:        switch (n) {
                    255:         case RP5C15::MODE_BANK1:
                    256:         case RP5C15::TEST_BANK1:
                    257:         case RP5C15::RESET_BANK1:
                    258:                // Bank0 と同じものが見える
                    259:                n -= 0x10;
                    260:                FALLTHROUGH;
                    261: 
                    262:         case 0x00 ... 0x1c:
                    263:                return reg.r[n] | 0xf0;
                    264: 
                    265:         default:
                    266:                return 0xf0;
                    267:        }
                    268: }
                    269: 
                    270: bool
                    271: RP5C15Device::MonitorUpdate()
                    272: {
                    273:        int x;
                    274:        int y;
                    275: 
                    276:        //
                    277:        //  #0 #1
                    278:        // 1:4 2
                    279:        //
                    280:        //        0 1 2 3 4 5 6 7 8 9 A B C D E F
                    281:        // Bank0  0 1 2 3 4 5 6 7 8 9 a b c d e f
                    282:        // Bank1
                    283: 
                    284:        monitor.Clear();
                    285: 
                    286:        monitor.Print(0, 0, " #0 #1");
                    287:        y = 1;
                    288:        for (int i = 0; i < 13; i++, y++) {
                    289:                monitor.Print(0, y, "%X:%x %x", i, reg.r[i], reg.r[i + 16]);
                    290:        }
                    291:        for (int i = 13; i < 16; i++, y++) {
                    292:                monitor.Print(0, y, "%X:%x", i, reg.r[i]);
                    293:        }
                    294: 
                    295:        x = 8;
                    296:        y = 0;
                    297: 
                    298:        int year = reg.year10 * 10 + reg.year1 + 1980;
                    299:        int mon  = reg.mon10 * 10 + reg.mon1;
                    300:        int day  = reg.day10 * 10 + reg.day1;
                    301:        monitor.Print(x, y, "%04d/%02d/%02d(%s)",
                    302:                year, mon, day, wdays[reg.wday]);
                    303:        y++;
                    304: 
                    305:        int hour;
                    306:        if (reg.sel24) {
                    307:                hour = reg.hour10 * 10 + reg.hour1;
                    308:        } else {
                    309:                hour = (reg.hour10 & 1) * 10 + reg.hour1;
                    310:                monitor.Print(x, y, "%s", (reg.hour10 & 2) == 0 ? "AM" : "PM");
                    311:        }
                    312:        int min = reg.min10 * 10 + reg.min1;
                    313:        int sec = reg.sec10 * 10 + reg.sec1;
                    314:        monitor.Print(x + 3, y, "%02d:%02d:%02d", hour, min, sec);
                    315:        y++;
                    316: 
                    317:        monitor.Print(x, y++, "Leap %d", reg.leap);
                    318:        y++;
                    319: 
                    320:        monitor.Print(x, y++, "CLKOUT %c", clkout ? 'H' : 'L');
                    321:        monitor.Print(x, y++, "ALARM  %c", alarmout ? 'H' : 'L');
                    322:        y++;
                    323: 
                    324:        monitor.Print(x, y++, "cnt  %2d", rtc.cnt);
                    325: 
                    326:        return true;
                    327: }
                    328: 
                    329: // 32Hz クロック入力
                    330: //
                    331: // 32Hz ごとに呼ばれて、これが RTC の時計を進める処理をするところ。
                    332: // RTC を実時間に同期して進めるモードなら実時間を計るスケジューラから、
                    333: // RTC を仮想時間に同期して進めるモードなら VM スケジューラから呼ばれる。
                    334: //
                    335: // CLKOUT 128Hz 以上のモードには対応していない。
                    336: void
                    337: RP5C15Device::ClockIn()
                    338: {
                    339:        uint32 updates;
                    340: 
                    341:        // 32Hz カウンタを進める
                    342:        updates = CountUp();
                    343: 
                    344:        // レジスタの値を更新する
                    345:        UpdateReg(updates);
                    346: 
                    347:        // CLKOUT 端子の切り替え周期は CLKSEL による
                    348:        switch (reg.clksel) {
                    349:         case 0:        // ハイインピーダンス
                    350:         case 1:        // 16384Hz
                    351:         case 2:        // 1024Hz
                    352:         case 3:        // 128Hz
                    353:                // 128Hz 点滅とか点灯みたいなもんだろ(適当)
                    354:                clkout = true;
                    355:                break;
                    356: 
                    357:         case 4:        // 16Hz
                    358:                clkout = !clkout;
                    359:                // アラーム端子 16Hz パルス出力は %0 ならオン
                    360:                if ((reg.reset & RP5C15::RESET_16Hz) == 0) {
                    361:                        alarmout = !alarmout;
                    362:                }
                    363:                break;
                    364: 
                    365:         case 5:        // 1Hz
                    366:                // CLKOUT 端子は秒の繰り上がりに同期している。
                    367:                // ALARM 端子の 1Hz パルスもそれに同期するとは書いてないけど、
                    368:                // 面倒なのでとりあえず同じところで処理してしまう。
                    369:                // TIMER_EN (秒への繰り上がり) が無効でも反転自体は起きる気が
                    370:                // するので、ここでは UPDATE_SEC ではなく cnt で判定する。
                    371:                if ((rtc.cnt & 31) == 0) {
                    372:                        // CLKOUT は 1秒の繰り上がりが起きる時に 'H' になる
                    373:                        clkout = true;
                    374: 
                    375:                        // ALARM 反転
                    376:                        if ((reg.reset & RP5C15::RESET_1Hz) == 0) {
                    377:                                alarmout = !alarmout;
                    378:                        }
                    379:                } else if ((rtc.cnt & 31) == 16) {
                    380:                        // CLKOUT、その反対側
                    381:                        clkout = false;
                    382: 
                    383:                        // ALARM 反転
                    384:                        if ((reg.reset & RP5C15::RESET_1Hz) == 0) {
                    385:                                alarmout = !alarmout;
                    386:                        }
                    387:                }
                    388:                break;
                    389: 
                    390:         case 6:        // 1/60Hz
                    391:                if ((updates & UPDATE_MIN)) {
                    392:                        // 00秒になったので CLKOUT を 'H' に
                    393:                        clkout = true;
                    394:                } else if ((updates & UPDATE_SEC) && rtc.sec == 30) {
                    395:                        // 30秒になったので CLKOUT を 'L' に
                    396:                        clkout = false;
                    397:                }
                    398:                break;
                    399: 
                    400:         case 7:        // 'L' 固定
                    401:                clkout = false;
                    402:                break;
                    403:        }
                    404: }
                    405: 
                    406: // updates で指定された桁に該当するレジスタを更新する。
                    407: // 繰り上がりかどうかは処理せず現在の値を RP5C15 レジスタにセットするだけ。
                    408: void
                    409: RP5C15Device::UpdateReg(uint32 updates)
                    410: {
                    411:        if ((updates & UPDATE_SEC)) {
                    412:                reg.sec1  = rtc.sec % 10;
                    413:                reg.sec10 = rtc.sec / 10;
                    414:        }
                    415:        if ((updates & UPDATE_MIN)) {
                    416:                reg.min1  = rtc.min % 10;
                    417:                reg.min10 = rtc.min / 10;
                    418:        }
                    419:        if ((updates & UPDATE_HOUR)) {
                    420:                if (reg.sel24) {
                    421:                        // 24時間計モードでは普通の BCD
                    422:                        reg.hour1  = rtc.hour % 10;
                    423:                        reg.hour10 = rtc.hour / 10;
                    424:                } else {
                    425:                        // 12時間計モードなら、時のbit1 が AM/PM を表す
                    426:                        int h12 = rtc.hour % 12;
                    427:                        reg.hour1  = h12 % 10;
                    428:                        reg.hour10 = h12 / 10;
                    429:                        reg.hour10 |= (rtc.hour >= 12) ? 0x02 : 0x00;
                    430:                }
                    431:        }
                    432: 
                    433:        if ((updates & UPDATE_DAY)) {
                    434:                reg.wday  = rtc.wday;
                    435:                reg.day1  = rtc.mday % 10;
                    436:                reg.day10 = rtc.mday / 10;
                    437:        }
                    438:        if ((updates & UPDATE_MON)) {
                    439:                reg.mon1  = rtc.mon % 10;
                    440:                reg.mon10 = rtc.mon / 10;
                    441:        }
                    442:        if ((updates & UPDATE_YEAR)) {
                    443:                // X680x0 では 0 を 1980年としている。
                    444:                int y = rtc.year - 1980;
                    445:                reg.year1  = y % 10;
                    446:                reg.year10 = y / 10;
                    447:        }
                    448: }
                    449: 
                    450: /*static*/ const uint8
                    451: RP5C15::mask[] = {
                    452:        0x0f,   0x07,   0x0f,   0x07,   // 1秒 10秒   1分            10分
                    453:        0x0f,   0x03,   0x07,   0x0f,   // 1時 10時   曜日  1日
                    454:        0x01,   0x0f,   0x01,   0x0f,   // 10日        1月            10月   1年
                    455:        0x0f,   0x0d,   0x0f,   0x0f,   // 10年        MODE    TEST    RESET
                    456: 
                    457:        0x07,   0x01,   0x0f,   0x07,   // CLKO Adjust  AL1分  AL10分
                    458:        0x0f,   0x03,   0x07,   0x0f,   // AL1時 AL10時       AL曜日        AL1日
                    459:        0x03,   0x00,   0x01,   0x03,   // AL10日 ---  12/24   閏年
                    460:        0x00                                                    // ---
                    461: };

unix.superglobalmegacorp.com

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