Annotation of nono/vm/ssg.cpp, revision 1.1

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2024 nono project
        !             4: // Licensed under nono-license.txt
        !             5: //
        !             6: 
        !             7: //
        !             8: // SSG (YM2149)
        !             9: //
        !            10: 
        !            11: #include "ssg.h"
        !            12: 
        !            13: // コンストラクタ
        !            14: SSGDevice::SSGDevice()
        !            15:        : inherited(OBJ_SSG)
        !            16: {
        !            17:        monitor.func = ToMonitorCallback(&SSGDevice::MonitorUpdate);
        !            18:        monitor.SetSize(45, 12);
        !            19:        monitor.Regist(ID_MONITOR_SSG);
        !            20: }
        !            21: 
        !            22: // デストラクタ
        !            23: SSGDevice::~SSGDevice()
        !            24: {
        !            25: }
        !            26: 
        !            27: // リセット
        !            28: void
        !            29: SSGDevice::ResetHard(bool poweron)
        !            30: {
        !            31: }
        !            32: 
        !            33: // A0 でアドレスポートとデータポートを分けるみたいなのではなく、
        !            34: // 謎の BDIR と BC1 を R/W と A0 につないであるっぽい感じなので、
        !            35: // トラップみたいな配置になっている。(紙資料も間違えている…)
        !            36: //
        !            37: // BDIR BC1        ->  XP I/O
        !            38: //  0    0  Inactive
        !            39: //  0    1  Read               0x83 R
        !            40: //  1    0  Write              0x82 W
        !            41: //  1    1  Address            0x83 W
        !            42: 
        !            43: busdata
        !            44: SSGDevice::Read1(uint32 addr)
        !            45: {
        !            46:        uint32 offset = addr & 1;
        !            47:        uint32 data;
        !            48: 
        !            49:        if (offset == 0) {
        !            50:                data = 0xff;    // ?
        !            51:        } else {
        !            52:                // 読み込み
        !            53:                data = reg.Get(regno);
        !            54:                putlog(3, "R%x -> $%02x", regno, data);
        !            55:        }
        !            56: 
        !            57:        return data;
        !            58: }
        !            59: 
        !            60: busdata
        !            61: SSGDevice::Write1(uint32 addr, uint32 data)
        !            62: {
        !            63:        uint32 offset = addr & 1;
        !            64: 
        !            65:        if (offset == 0) {
        !            66:                // データ書き込み
        !            67:                putlog(2, "R%x <- $%02x", regno, data);
        !            68:                switch (regno) {
        !            69:                 case 0x0:      // Frequency of channel A (Low)
        !            70:                        reg.freq[0] &= 0xf00;
        !            71:                        reg.freq[0] |= data;
        !            72:                        break;
        !            73:                 case 0x1:      // Frequency of channel A (High)
        !            74:                        reg.freq[0] &= 0x0ff;
        !            75:                        reg.freq[0] |= data << 8;
        !            76:                        break;
        !            77:                 case 0x2:      // Frequency of channel B (Low)
        !            78:                        reg.freq[1] &= 0xf00;
        !            79:                        reg.freq[1] |= data;
        !            80:                        break;
        !            81:                 case 0x3:      // Frequency of channel B (High)
        !            82:                        reg.freq[1] &= 0x0ff;
        !            83:                        reg.freq[1] |= data << 8;
        !            84:                        break;
        !            85:                 case 0x4:      // Frequency of channel C (Low)
        !            86:                        reg.freq[2] &= 0xf00;
        !            87:                        reg.freq[2] |= data;
        !            88:                        break;
        !            89:                 case 0x5:      // Frequency of channel C (High)
        !            90:                        reg.freq[2] &= 0x0ff;
        !            91:                        reg.freq[2] |= data << 8;
        !            92:                        break;
        !            93: 
        !            94:                 case 0x6:      // Frequency of noise
        !            95:                        reg.noise_freq = data & 0x1f;
        !            96:                        break;
        !            97: 
        !            98:                 case 0x7:      // I/O port and mixer settings
        !            99:                        reg.settings = data;
        !           100:                        break;
        !           101: 
        !           102:                 case 0x8:      // Level of channel A
        !           103:                        reg.ampmode[0] = (data & 0x10);
        !           104:                        reg.amplevel[0] = data & 0x0f;
        !           105:                        break;
        !           106:                 case 0x9:      // Level of channel B
        !           107:                        reg.ampmode[1] = (data & 0x10);
        !           108:                        reg.amplevel[1] = data & 0x0f;
        !           109:                        break;
        !           110:                 case 0xa:      // Level of channel C
        !           111:                        reg.ampmode[2] = (data & 0x10);
        !           112:                        reg.amplevel[2] = data & 0x0f;
        !           113:                        break;
        !           114: 
        !           115:                 case 0xb:      // Frequency of envelope (Low)
        !           116:                        reg.envelope_freq &= 0xff00;
        !           117:                        reg.envelope_freq |= data;
        !           118:                        break;
        !           119:                 case 0xc:      // Frequency of envelope (Hight)
        !           120:                        reg.envelope_freq &= 0x00ff;
        !           121:                        reg.envelope_freq |= data << 8;
        !           122:                        break;
        !           123: 
        !           124:                 case 0xd:      // Shape of envelope
        !           125:                        reg.envelope_shape = data & 0x0f;
        !           126:                        break;
        !           127: 
        !           128:                 case 0xe:      // Data of I/O port A
        !           129:                        reg.dataA = data;
        !           130:                        break;
        !           131:                 case 0xf:      // Data of I/O port B
        !           132:                        reg.dataB = data;
        !           133:                        break;
        !           134: 
        !           135:                 default:
        !           136:                        assertmsg(false, "regno=$%x", regno);
        !           137:                        break;
        !           138:                }
        !           139:        } else {
        !           140:                // アドレス書き込み
        !           141:                regno = data & 0x0f;
        !           142:                putlog(4, "reg <- $%x", regno);
        !           143:        }
        !           144: 
        !           145:        return 0;
        !           146: }
        !           147: 
        !           148: busdata
        !           149: SSGDevice::Peek1(uint32 addr)
        !           150: {
        !           151:        return reg.Get(regno);
        !           152: }
        !           153: 
        !           154: void
        !           155: SSGDevice::MonitorUpdate(Monitor *, TextScreen& screen)
        !           156: {
        !           157:        // 012345678901234567890
        !           158:        // R1/R0 Freq ChA  $xxx f=
        !           159:        // R3/R2 Freq ChB  $xxx
        !           160:        // R5/R4 Freq ChC  $xxx
        !           161:        // R6    FreqNoise  $xx
        !           162:        // R7    Settings   $xx(IB IA NC NB NA TC TB TA)
        !           163:        // R8    Level A    $xx
        !           164:        // R9    Level B    $xx
        !           165:        // Ra    Level C    $xx
        !           166:        // Rc/Rb EnvFreq  $xxxx
        !           167:        // Rd    EnvShape   $xx
        !           168:        // Re    Data A     $xx
        !           169:        // Rf    Data A     $xx
        !           170: 
        !           171:        uint f;
        !           172:        int y = 0;
        !           173: 
        !           174:        screen.Clear();
        !           175: 
        !           176:        SSG tmp = reg;
        !           177: 
        !           178:        for (int i = 0; i < 3; i++) {
        !           179:                if (__predict_false(tmp.freq[i] == 0)) {
        !           180:                        f = 0;
        !           181:                } else {
        !           182:                        f = fMaster / (16 * tmp.freq[i]);
        !           183:                }
        !           184:                screen.Print(0, y, "R%u/R%u Freq Ch%c  $%03x f=%u",
        !           185:                        i * 2 + 1, i * 2, 'A' + i, tmp.freq[i], f);
        !           186:                y++;
        !           187:        }
        !           188: 
        !           189:        if (__predict_false(tmp.noise_freq == 0)) {
        !           190:                f = 0;
        !           191:        } else {
        !           192:                f = fMaster / (16 * tmp.noise_freq);
        !           193:        }
        !           194:        screen.Print(0, y++, "R6    FreqNoise  $%02x f=%u", tmp.noise_freq, f);
        !           195: 
        !           196:        screen.Print(0, y, "R7    Settings   $%02x(", tmp.settings);
        !           197:        screen.Puts(21, y, TA::OnOff(tmp.settings & 0x80), "IB");
        !           198:        screen.Puts(24, y, TA::OnOff(tmp.settings & 0x40), "IA");
        !           199:        screen.Puts(27, y, TA::OnOff(tmp.settings & 0x20), "NC");
        !           200:        screen.Puts(30, y, TA::OnOff(tmp.settings & 0x10), "NB");
        !           201:        screen.Puts(33, y, TA::OnOff(tmp.settings & 0x08), "NA");
        !           202:        screen.Puts(36, y, TA::OnOff(tmp.settings & 0x04), "TA");
        !           203:        screen.Puts(39, y, TA::OnOff(tmp.settings & 0x02), "TA");
        !           204:        screen.Puts(42, y, TA::OnOff(tmp.settings & 0x01), "TA");
        !           205:        screen.Putc(44, y, ')');
        !           206:        y++;
        !           207: 
        !           208:        for (int i = 0; i < 3; i++) {
        !           209:                screen.Print(0, y++, "R%x    Level %c    $%02x",
        !           210:                        8 + i, 'A' + i, tmp.GetLevelReg(i));
        !           211:        }
        !           212: 
        !           213:        if (__predict_false(tmp.envelope_freq == 0)) {
        !           214:                f = 0;
        !           215:        } else {
        !           216:                f = fMaster / (256 * tmp.envelope_freq);
        !           217:        }
        !           218:        screen.Print(0, y++, "Rc/Rb EnvFreq  $%04x f=%u", tmp.envelope_freq, f);
        !           219: 
        !           220:        // モニタはソースコードのマルチバイト文字(UTF-8) を SJIS に変換する所は
        !           221:        // (まだ?)用意してないので、こっちで SJIS 文字列を用意する必要がある。
        !           222:        #define H       "\x81\x50"
        !           223:        #define L       "\x81\x51"
        !           224:        #define U       "\x81\x5e"
        !           225:        #define D       "\x81\x5f"
        !           226:        static const char *shape8[8] = {
        !           227:                D D D D D,      // "\\\\\"
        !           228:                D L L L L,      // "\____"
        !           229:                D U D U D,      // "\/\/\"
        !           230:                D H H H H,      // "\ ̄ ̄ ̄ ̄"
        !           231:                U U U U U,      // "/////"
        !           232:                U H H H H,      // "/ ̄ ̄ ̄ ̄"
        !           233:                U D U D U,      // "/\/\/"
        !           234:                U L L L L,      // "/____"
        !           235:        };
        !           236:        const char *shape;
        !           237:        uint es = tmp.envelope_shape;
        !           238:        if (es >= 8) {
        !           239:                shape = shape8[es - 8];
        !           240:        } else if (es >= 4) {
        !           241:                shape = shape8[7];
        !           242:        } else {
        !           243:                shape = shape8[1];
        !           244:        }
        !           245:        screen.Print(0, y++, "Rd    EnvShape   $%02x %s",
        !           246:                tmp.envelope_shape, shape);
        !           247:        screen.Print(0, y++, "Re    Data A     $%02x", tmp.dataA);
        !           248:        screen.Print(0, y++, "Rf    Data B     $%02x", tmp.dataB);
        !           249: }
        !           250: 
        !           251: // レジスタの内容を副作用なく返す。
        !           252: uint32
        !           253: SSG::Get(uint n) const
        !           254: {
        !           255:        switch (n) {
        !           256:         case 0x0:
        !           257:                return freq[0] & 0xff;
        !           258:         case 0x1:
        !           259:                return freq[0] >> 8;
        !           260:         case 0x2:
        !           261:                return freq[1] & 0xff;
        !           262:         case 0x3:
        !           263:                return freq[1] >> 8;
        !           264:         case 0x4:
        !           265:                return freq[2] & 0xff;
        !           266:         case 0x5:
        !           267:                return freq[2] >> 8;
        !           268:         case 0x6:
        !           269:                return noise_freq;
        !           270:         case 0x7:
        !           271:                return settings;
        !           272:         case 0x8:
        !           273:                return GetLevelReg(0);
        !           274:         case 0x9:
        !           275:                return GetLevelReg(1);
        !           276:         case 0xa:
        !           277:                return GetLevelReg(2);
        !           278:         case 0xb:
        !           279:                return envelope_freq & 0xff;
        !           280:         case 0xc:
        !           281:                return envelope_freq >> 8;
        !           282:         case 0xd:
        !           283:                return envelope_shape;
        !           284:         case 0xe:
        !           285:                return dataA;
        !           286:         case 0xf:
        !           287:                return dataB;
        !           288:         default:
        !           289:                __unreachable();
        !           290:        }
        !           291: }

unix.superglobalmegacorp.com

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