Annotation of nono/vm/opm.cpp, revision 1.1.1.6

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
1.1.1.4   root        7: //
                      8: // OPM (YM2151)
                      9: //
                     10: 
1.1       root       11: #include "opm.h"
1.1.1.5   root       12: #include "adpcm.h"
1.1.1.4   root       13: #include "fdc.h"
1.1.1.5   root       14: #include "mpu.h"
                     15: #include "scheduler.h"
1.1       root       16: 
1.1.1.4   root       17: // コンストラクタ
1.1       root       18: OPMDevice::OPMDevice()
1.1.1.6 ! root       19:        : inherited(OBJ_OPM)
1.1       root       20: {
                     21: }
                     22: 
1.1.1.4   root       23: // デストラクタ
1.1       root       24: OPMDevice::~OPMDevice()
                     25: {
1.1.1.6 ! root       26: }
        !            27: 
        !            28: // 初期化
        !            29: bool
        !            30: OPMDevice::Init()
        !            31: {
        !            32:        if (inherited::Init() == false) {
        !            33:                return false;
        !            34:        }
        !            35: 
        !            36:        adpcm = GetADPCMDevice();
        !            37:        fdc = GetFDCDevice();
        !            38: 
        !            39:        return true;
1.1       root       40: }
                     41: 
1.1.1.5   root       42: // リセット
                     43: void
                     44: OPMDevice::ResetHard(bool poweron)
                     45: {
                     46:        busy_origin = 0;
                     47:        busy_start = 0;
                     48:        busy_end = 0;
                     49: 
1.1.1.6 ! root       50:        fdc->SetForceReady(false);
1.1.1.5   root       51: }
                     52: 
1.1       root       53: uint64
1.1.1.2   root       54: OPMDevice::Read(uint32 offset)
1.1       root       55: {
1.1.1.5   root       56:        uint8 data;
                     57: 
1.1.1.6 ! root       58:        mpu->AddCycle(19);      // InsideOut p.135
1.1.1.5   root       59: 
1.1.1.4   root       60:        switch (offset) {
                     61:         case 0:
1.1.1.6 ! root       62:                putlog(0, "Read $%06x (NOT IMPLEMENTED)", mpu->GetPaddr());
1.1.1.4   root       63:                return 0;
                     64:         case 1:
                     65:                // OPM ステータスレジスタ
1.1.1.5   root       66:                data = 0;
                     67:                if (IsBusy()) {
                     68:                        data |= 0x80;
                     69:                }
                     70:                // タイマ関係の bit1, bit0 は未実装
                     71: 
                     72:                putlog(1, "STAT -> $%02x", data);
                     73:                return data;
1.1.1.4   root       74:         default:
1.1.1.6 ! root       75:                VMPANIC("corrupted offset=%d", offset);
        !            76:                return 0xff;
1.1.1.4   root       77:        }
1.1       root       78: }
                     79: 
                     80: uint64
1.1.1.2   root       81: OPMDevice::Write(uint32 offset, uint32 data)
1.1       root       82: {
1.1.1.6 ! root       83:        mpu->AddCycle(53);      // InsideOut p.135
1.1.1.5   root       84: 
1.1.1.6 ! root       85:        uint64 now = scheduler->GetVirtTime();
1.1.1.5   root       86: 
1.1.1.4   root       87:        switch (offset) {
                     88:         case 0:
                     89:                putlog(1, "REG <- $%02x", data);
1.1.1.5   root       90:                // アドレス選択が反映されるまで 8 クロックかかるらしい
                     91:                // が、顕在化しないと思うので実装していない
1.1.1.4   root       92:                reg = data;
                     93:                break;
                     94:         case 1:
                     95:                putlog(1, "DATA <- $%02x", data);
1.1.1.5   root       96:                // CPU が命令中のどのタイミングでライトするかを用意していないので
                     97:                // 実際に OPM にライトされるタイミングは正確にはわからない。
                     98:                // なので正確な時刻の起点は不明。
                     99:                //
                    100:                // BUSY がアサートされるまで OPM クロックで 8 から 12 クロックかかる
                    101:                // らしい。
                    102:                //
                    103:                // BUSY のアサート期間は 68 クロックらしい。
                    104:                // YM2151 アプリケーションマニュアル(英語版) 2.1.1
                    105: 
                    106:                // BUSY フラグのみならず、書き込み処理期間中のときは保証されていない。
                    107:                // とりあえず無視する。
                    108:                if (busy_origin <= now && now < busy_end) {
                    109:                        putlog(0, "Write on Busy");
                    110:                        break;
                    111:                }
                    112: 
                    113:                // 時刻の起点は CPU 側の命令によって異なるはずだが
                    114:                // わからないので命令のぶんは無視しておく。
                    115:                // 53 クロックのウェイトのほうは足す。
1.1.1.6 ! root      116:                busy_origin = now + 53 * mpu->GetClock_nsec();
1.1.1.5   root      117: 
                    118:                // busy_start のほうはとりあえず 10 クロックにしておく。
                    119:                busy_start = busy_origin + 10 * clk;
                    120:                busy_end = busy_origin + 68 * clk;
                    121: 
1.1.1.4   root      122:                switch (reg) {
                    123:                 case 0x1b:
1.1.1.6 ! root      124:                        adpcm->SetClock(data & 0x80);
        !           125:                        fdc->SetForceReady(data & 0x40);
1.1.1.4   root      126:                        // 他のビットは未対応
                    127:                        break;
                    128:                 default:
1.1.1.5   root      129:                        putlog(0, "Write $%06x <- $%02x (NOT IMPLEMENTED)",
1.1.1.6 ! root      130:                                mpu->GetPaddr(), data);
1.1.1.4   root      131:                        break;
                    132:                }
                    133:                break;
                    134:         default:
1.1.1.6 ! root      135:                VMPANIC("corrupted offset=%d", offset);
        !           136:                break;
1.1.1.4   root      137:        }
                    138: 
1.1       root      139:        return 0;
                    140: }
                    141: 
                    142: uint64
1.1.1.2   root      143: OPMDevice::Peek(uint32 offset)
1.1       root      144: {
                    145:        // XXX 未実装
                    146:        return 0xff;
                    147: }
1.1.1.5   root      148: 
                    149: // OPM ステータスレジスタの B (BUSY) ビット
                    150: bool
                    151: OPMDevice::IsBusy() const
                    152: {
1.1.1.6 ! root      153:        uint64 now = scheduler->GetVirtTime();
1.1.1.5   root      154: 
                    155:        return (busy_start <= now && now < busy_end);
                    156: }

unix.superglobalmegacorp.com

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