Annotation of nono/vm/goldfish_tty.cpp, revision 1.1.1.4

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2024 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // Goldfish TTY
                      9: //
                     10: 
                     11: // レジスタ仕様は次の通り。
                     12: //  +$00.L PUT_CHAR            -W: 1バイト出力
                     13: //  +$04.L BYTES_READY R-: 受信キューにあるバイト数を取得
                     14: //  +$08.L COMMAND             -W: コマンド
                     15: //  +$0c.L -
                     16: //  +$10.L DATA_PTR            -W: DMA 開始アドレス
                     17: //  +$14.L DATA_LEN            -W: DMA データ長
                     18: //  +$18.L DATA_PTR_HIGH W: DMA 開始アドレスの上位 32 ビット
                     19: //  +$1c.L -
                     20: //  +$20.L VERSION             R-: このデバイスのバージョン ($1)
                     21: //
                     22: // コマンドは
                     23: //  $00 INT_DISABLE
                     24: //  $01 INT_ENABLE
                     25: //  $02 WRITE_BUFFER
                     26: //  $03 READ_BUFFER
                     27: //
                     28: // 受信キューにデータがあれば割り込みを上げる。
                     29: // 受信キューが空になると割り込みを下げる。
                     30: //
                     31: // WRITE_BUFFER, READ_BUFFER はたぶんバスマスタ的転送。
                     32: // 読み出し時 (READ_BUFFER) は、DATA_PTR で指定したアドレスにたぶん最大
                     33: // DATA_LEN バイトを GFTTY デバイスが書き込む。
                     34: // 書き込み時 (WRITE_BUFFER) は、DATA_PTR で指定したアドレスから DATA_LEN
                     35: // バイトを GFTTY デバイスが読み込む。
                     36: //
                     37: // nono では DATA_PTR_HIGH は実装しない。
                     38: 
                     39: #include "goldfish_tty.h"
                     40: #include "goldfish_pic.h"
                     41: #include "hostcom.h"
                     42: #include "mainbus.h"
1.1.1.2   root       43: #include "mpu.h"
1.1       root       44: #include "scheduler.h"
1.1.1.4 ! root       45: #include "syncer.h"
1.1       root       46: 
                     47: // コンストラクタ
                     48: GFTTYDevice::GFTTYDevice()
                     49:        : inherited(OBJ_GFTTY)
                     50: {
                     51: }
                     52: 
                     53: // デストラクタ
                     54: GFTTYDevice::~GFTTYDevice()
                     55: {
                     56:        if ((bool)hostcom) {
                     57:                hostcom->SetRxCallback(NULL);
                     58:        }
                     59: }
                     60: 
                     61: bool
                     62: GFTTYDevice::Create()
                     63: {
                     64:        // 対応するホストドライバを作成
1.1.1.4 ! root       65:        try {
        !            66:                hostcom.reset(new HostCOMDevice(this, "HostCOM"));
        !            67:        } catch (...) { }
1.1       root       68:        if ((bool)hostcom == false) {
1.1.1.4 ! root       69:                warnx("Failed to initialize HostCOMDevice at %s", __method__);
1.1       root       70:                return false;
                     71:        }
                     72:        hostcom->SetRxCallback(ToDeviceCallback(&GFTTYDevice::HostRxCallback));
                     73: 
                     74:        return true;
                     75: }
                     76: 
                     77: void
                     78: GFTTYDevice::SetLogLevel(int loglevel_)
                     79: {
                     80:        inherited::SetLogLevel(loglevel_);
                     81: 
1.1.1.4 ! root       82:        if ((bool)hostcom) {
        !            83:                hostcom->SetLogLevel(loglevel_);
        !            84:        }
1.1       root       85: }
                     86: 
                     87: // 初期化
                     88: bool
                     89: GFTTYDevice::Init()
                     90: {
                     91:        mainbus = GetMainbusDevice();
                     92: 
                     93:        gfpic = GetGFPICDevice(1);
                     94:        gfpic->RegistIRQ(32, "GFTTY", this);
                     95: 
                     96:        scheduler->ConnectMessage(MessageID::HOSTCOM_RX, this,
                     97:                ToMessageCallback(&GFTTYDevice::RxMessage));
                     98:        return true;
                     99: }
                    100: 
                    101: // 電源オン/リセット
                    102: void
                    103: GFTTYDevice::ResetHard(bool poweron)
                    104: {
1.1.1.4 ! root      105:        sesame_idx = 0;
1.1       root      106:        rxq.clear();
                    107:        intr_enable = false;
                    108:        ChangeInterrupt();
                    109: }
                    110: 
                    111: busdata
1.1.1.2   root      112: GFTTYDevice::ReadPort(uint32 offset)
1.1       root      113: {
                    114:        busdata data;
                    115: 
                    116:        switch (offset) {
                    117:         case BYTES_READY:
1.1.1.2   root      118:                data = GetREADY();
                    119:                putlog(2, "BYTES_READY -> $%08x", data.Data());
1.1       root      120:                break;
                    121: 
                    122:         case VERSION:
1.1.1.2   root      123:                data = GFTTYVersion;
1.1       root      124:                putlog(2, "VERSION -> $%08x", data.Data());
                    125:                break;
                    126: 
                    127:         default:
1.1.1.2   root      128:                putlog(1, "Read $%08x.L", mpu->GetPaddr());
1.1       root      129:                data.SetBusErr();
                    130:                break;
                    131:        }
                    132: 
1.1.1.2   root      133:        data |= BusData::Size4;
1.1       root      134:        return data;
                    135: }
                    136: 
                    137: busdata
1.1.1.2   root      138: GFTTYDevice::WritePort(uint32 offset, uint32 data)
1.1       root      139: {
                    140:        busdata r;
                    141: 
                    142:        switch (offset) {
                    143:         case PUT_CHAR:
                    144:                putlog(2, "PUT_CHAR <- $%02x", data);
1.1.1.4 ! root      145:                Tx(data);
1.1       root      146:                break;
                    147: 
                    148:         case COMMAND:
                    149:                Command(data);
                    150:                break;
                    151: 
                    152:         case DATA_PTR:
                    153:                putlog(2, "DATA_PTR <- $%08x", data);
                    154:                dma_ptr = data;
                    155:                break;
                    156: 
                    157:         case DATA_LEN:
                    158:                putlog(2, "DATA_LEN <- $%08x", data);
                    159:                dma_len = data;
                    160:                break;
                    161: 
                    162:         default:
1.1.1.2   root      163:                putlog(1, "Write $%08x.L", mpu->GetPaddr());
1.1       root      164:                r.SetBusErr();
                    165:                break;
                    166:        }
1.1.1.2   root      167: 
                    168:        r |= BusData::Size4;
1.1       root      169:        return r;
                    170: }
                    171: 
                    172: busdata
1.1.1.2   root      173: GFTTYDevice::PeekPort(uint32 offset)
                    174: {
                    175:        switch (offset) {
                    176:         case BYTES_READY:
                    177:                return GetREADY();
                    178:         case VERSION:
                    179:                return GFTTYVersion;
                    180:         default:
                    181:                return BusData::BusErr;
                    182:        }
                    183: }
                    184: 
                    185: // 着信しているバイト数を返す。
                    186: uint32
                    187: GFTTYDevice::GetREADY() const
1.1       root      188: {
1.1.1.2   root      189:        return rxq.size();
1.1       root      190: }
                    191: 
                    192: void
                    193: GFTTYDevice::Command(uint32 cmd)
                    194: {
                    195:        switch (cmd) {
                    196:         case CMD_INT_DISABLE:
                    197:                putlog(1, "CMD_INT_DISABLE");
                    198:                intr_enable = false;
                    199:                ChangeInterrupt();
                    200:                break;
                    201: 
                    202:         case CMD_INT_ENABLE:
                    203:                putlog(1, "CMD_INT_ENABLE");
                    204:                intr_enable = true;
                    205:                ChangeInterrupt();
                    206:                break;
                    207: 
                    208:         case CMD_WRITE_BUFFER:
                    209:         {
                    210:                // ゲストからの書き込み
                    211:                putlog(1, "CMD_WRITE_BUFFER($%08x, $%08x)", dma_ptr, dma_len);
                    212:                uint32 addr = dma_ptr;
                    213:                uint32 end = addr + dma_len;
                    214:                for (; addr < end; addr++) {
1.1.1.2   root      215:                        busdata data = mainbus->HVRead1(addr);
1.1       root      216:                        if (data.IsBusErr()) {
                    217:                                putlog(1, "WRITE_BUFFER: BusError at $%08x", addr);
                    218:                                break;
                    219:                        }
1.1.1.4 ! root      220:                        Tx(data);
1.1       root      221:                }
                    222:                break;
                    223:         }
                    224: 
                    225:         case CMD_READ_BUFFER:
                    226:         {
                    227:                // ゲストからの読み込み (ゲスト空間へ書き出し)
                    228:                putlog(1, "CMD_READ_BUFFER($%08x, $%08x)", dma_ptr, dma_len);
                    229:                uint32 addr = dma_ptr;
                    230:                uint32 len = std::min(dma_len, (uint32)rxq.size());
                    231:                for (uint32 end = addr + len; addr < end; addr++) {
                    232:                        uint32 data = rxq.front();
                    233:                        rxq.pop_front();
1.1.1.2   root      234:                        busdata bd = mainbus->HVWrite1(addr, data);
1.1       root      235:                        if (bd.IsBusErr()) {
                    236:                                putlog(1, "READ_BUFFER: BusError at $%08x", addr);
                    237:                                break;
                    238:                        }
                    239:                }
                    240:                ChangeInterrupt();
                    241:                break;
                    242:         }
                    243: 
                    244:         default:
                    245:                putlog(1, "Unknown command $%08x", cmd);
                    246:                break;
                    247:        }
                    248: }
                    249: 
1.1.1.4 ! root      250: // 1バイト送信。
        !           251: void
        !           252: GFTTYDevice::Tx(uint32 data)
        !           253: {
        !           254:        // パフォーマンス測定用のギミック。
        !           255:        // GFTTY に特定の文字列を書き込むと、
        !           256:        // VM 電源オン時から現在までの実時間をログに出力する。NetBSD の
        !           257:        // マルチユーザブートがあらかた終わってログインプロンプトが出る手前の
        !           258:        // /etc/rc.local に
        !           259:        //
        !           260:        // printf '\e[?68008h\e[?68008l'
        !           261:        //
        !           262:        // と書いておくことで、ここまでにかかる時間を表示できる。
        !           263:        // この値はホスト性能に依存するため、同一環境下での相対比較のみ可能。
        !           264:        //
        !           265:        // このエスケープシーケンスは DEC/xterm 拡張の設定と解除を続けて行う
        !           266:        // もので、68008 は空いてそうな適当な値。知らない番号の拡張機能については
        !           267:        // おそらく黙って何もしないだけだと思うので、どの端末エミュレータを通過
        !           268:        // しても副作用は少ないと思われる。
        !           269:        static const char sesame[] = "\x1b[?68008h\x1b[?68008l";
        !           270:        if (__predict_false(data == sesame[sesame_idx])) {
        !           271:                sesame_idx++;
        !           272:                if (__predict_false(sesame_idx >= strlen(sesame))) {
        !           273:                        GetSyncer()->PutlogRealtime();
        !           274:                        sesame_idx = 0;
        !           275:                }
        !           276:        } else {
        !           277:                sesame_idx = 0;
        !           278:        }
        !           279: 
        !           280:        // 1バイト送信。
        !           281:        hostcom->Tx(data);
        !           282: }
        !           283: 
1.1       root      284: void
                    285: GFTTYDevice::ChangeInterrupt()
                    286: {
                    287:        bool irq = (intr_enable && rxq.empty() == false);
                    288:        gfpic->ChangeINT(this, irq);
                    289: }
                    290: 
                    291: // ホストスレッドからの受信通知
                    292: // (HostCOM スレッドで呼ばれる)
                    293: void
                    294: GFTTYDevice::HostRxCallback()
                    295: {
                    296:        scheduler->SendMessage(MessageID::HOSTCOM_RX);
                    297: }
                    298: 
                    299: // ホストシリアルからの1バイト(以上)受信メッセージ
                    300: // (VM スレッドで呼ばれる)
                    301: void
                    302: GFTTYDevice::RxMessage(MessageID msgid, uint32 arg)
                    303: {
                    304:        bool recv = false;
                    305: 
                    306:        for (;;) {
                    307:                uint32 data = hostcom->Rx();
                    308:                if ((int32)data < 0) {
                    309:                        break;
                    310:                }
                    311:                rxq.push_back(data);
                    312:                recv = true;
                    313:        }
                    314: 
                    315:        if (recv) {
                    316:                ChangeInterrupt();
                    317:        }
                    318: }

unix.superglobalmegacorp.com

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