|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.