Annotation of nono/vm/upd7201.h, revision 1.1.1.10

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: #pragma once
                      8: 
                      9: #include "device.h"
1.1.1.10! root       10: #include "event.h"
1.1.1.7   root       11: #include "monitor.h"
1.1.1.10! root       12: #include <array>
1.1       root       13: 
                     14: // uPD7201/Z8530 のレジスタ
                     15: //
                     16: // uPD7201 は、書き込みが CR (Command Register) 8本、
                     17: // 読み込みが SR (Status Register) 2本。
                     18: // Z8530 は、書き込みが WR (Write Register) 16本、
                     19: // 読み込みが RR (Read Register) 8本。
                     20: //
                     21: // Z8530 の WR0..WR7、RR0..RR2 は (名前が異なるが)
                     22: // uPD7201 の CR0..CR7、SR0..SR2 とわりとよく似ている (所々違う)。
                     23: //
                     24: // そのためデバイスは uPD7201Device クラスを基底に、SIODevice
                     25: // (ほぼ uPD7201Device) と SCCDevice (Z8530) とに派生している。
                     26: // レジスタ構造体は C++ の制約的に両方のセットを持ったものを一つ
                     27: // 用意するほうが楽なので、こうなっている。
                     28: struct SIO
                     29: {
1.1.1.8   root       30:        //       b7   b6   b5   b4   b3   b2   b1   b0
                     31:        //     +---------+--------------+--------------+
1.1       root       32:        // CR0 |   CRC   |   Command    |   Pointer    |
1.1.1.8   root       33:        //     +---------+--------------+--------------+
1.1       root       34:        static const int CR0_CRC                = 0xc0;
                     35:        static const int CR0_CMD                = 0x38;
                     36:        static const int CR0_PTR                = 0x07;
                     37: 
                     38:        // Z8530 ではコマンド %000 と %001 がレジスタ切り替えなので、
                     39:        // CMD が 0x38、PTR が 0x0f とあえて被せてある。
                     40:        static const int WR0_CRC                = CR0_CRC;
                     41:        static const int WR0_CMD                = CR0_CMD;
                     42:        static const int WR0_PTR                = 0x0f;
                     43: 
1.1.1.8   root       44:        //       b7   b6   b5   b4   b3   b2   b1   b0
                     45:        //     +----+----+----+---------+----+----+----+
1.1       root       46:        // CR1 | WE | -- | WR |  RX Int | -- | TE | ES |
1.1.1.8   root       47:        //     +----+----+----+---------+----+----+----+
1.1       root       48:        //       |         |       |           |    +---- E/S Int Enable
                     49:        //       |         |       |           +--------- TX INT/DMA Enable
                     50:        //       |         |       +--------------------- RX Int Mode
                     51:        //       |         +----------------------------- Wait on RX(=%1),TX(=%0)
                     52:        //       +--------------------------------------- Wait Enable
                     53:        static const int CR1_WAIT_EN    = 0x80;
                     54:        static const int CR1_WAIT_RX    = 0x20;
                     55:        static const int CR1_RXINT              = 0x18;
                     56:        static const int CR1_TXINT_EN   = 0x02;
                     57:        static const int CR1_ESINT_EN   = 0x01;
                     58: 
                     59:        static const int WR1_WAIT_EN    = CR1_WAIT_EN;
                     60:        static const int WR1_WAIT_RX    = CR1_WAIT_RX;
                     61:        static const int WR1_RXINT              = CR1_RXINT;
                     62:        static const int WR1_TXINT_EN   = CR1_TXINT_EN;
                     63:        static const int WR1_ESINT_EN   = CR1_ESINT_EN;
                     64: 
                     65:        // CR1_RXINT
                     66:        static const int RXINT_DISABLE                  = 0x00; // disabled
                     67:        static const int RXINT_FIRSTCHAR                = 0x08; // First charactoer intr.
                     68:        static const int RXINT_ALL_INC_SPECIAL  = 0x10; // All char include special
                     69:        static const int RXINT_ALL_EXC_SPECIAL  = 0x18; // All char exclude special
                     70: 
1.1.1.8   root       71:        //       b7   b6   b5   b4   b3   b2   b1   b0
                     72:        //     +---------+----+-------------------+----+
1.1       root       73:        // CR3 | RX bits | AE | --   --   --   -- | RE |
1.1.1.8   root       74:        //     +---------+----+-------------------+----+
1.1       root       75:        //          |      |                        +---- RX Enable
                     76:        //          |      +----------------------------- Auto Enable
                     77:        //          +------------------------------------ RX bits
                     78:        static const int CR3_RXBITS             = 0xc0;
                     79:        static const int CR3_AUTO_EN    = 0x40;
                     80:        static const int CR3_RX_EN              = 0x01;
                     81: 
                     82:        static const int WR3_RXBITS             = CR3_RXBITS;
                     83:        static const int WR3_AUTO_EN    = CR3_AUTO_EN;
                     84:        static const int WR3_RX_EN              = CR3_RX_EN;
                     85: 
1.1.1.8   root       86:        //       b7   b6   b5   b4   b3   b2   b1   b0
                     87:        //     +---------+---------+---------+----+----+
1.1       root       88:        // CR4 | ClkRate | SyncMode| StopBits| PV | PE |
1.1.1.8   root       89:        //     +---------+---------+---------+----+----+
1.1       root       90:        //          |         |         |      |    +---- Parity Enable(%1)
                     91:        //          |         |         |      +--------- Parity Even(%1)
                     92:        //          |         |         +---------------- Stop Bits
                     93:        //          |         +-------------------------- Sync Mode
                     94:        //          +------------------------------------ Clock Rate
1.1.1.6   root       95:        //
1.1       root       96:        static const int CR4_CLKRATE    = 0xc0;
                     97:        static const int CR4_SYNCMODE   = 0x30;
                     98:        static const int CR4_STOPBITS   = 0x0c;
                     99:        static const int CR4_PARITY_EVEN= 0x02;
                    100:        static const int CR4_PARITY_EN  = 0x01;
                    101: 
                    102:        static const int WR4_CLKRATE    = CR4_CLKRATE;
                    103:        static const int WR4_SYNCMODE   = CR4_SYNCMODE;
                    104:        static const int WR4_STOPBITS   = CR4_STOPBITS;
                    105:        static const int WR4_PARITY_EVEN= CR4_PARITY_EVEN;
                    106:        static const int WR4_PARITY_EN  = CR4_PARITY_EN;
                    107: 
                    108:        static const int SYNC_8BIT              = 0x00;
                    109:        static const int SYNC_16BIT             = 0x10;
                    110:        static const int SYNC_HDLC              = 0x20;
                    111:        static const int SYNC_EXT               = 0x30;
                    112: 
                    113:        static const int SYNC_MODE              = 0x00;
                    114:        static const int STOP_BITS_1    = 0x04;
                    115:        static const int STOP_BITS_1_5  = 0x08;
                    116:        static const int STOP_BITS_2    = 0x0c;
                    117: 
                    118:        enum Mode {
                    119:                SYNC = 0,
                    120:                ASYNC = 1,
                    121:                HDLC = 2,
                    122:        };
                    123: 
1.1.1.8   root      124:        //       b7   b6   b5   b4   b3   b2   b1   b0
                    125:        //     +----+---------+----+----+----+----+----+
1.1       root      126:        // CR5 | DTR| TX bits | SB | TE | CRC| RTS| TC |
1.1.1.8   root      127:        //     +----+---------+----+----+----+----+----+
1.1       root      128:        //       |       |      |    |    |    |    +---- TX CRC Enable
                    129:        //       |       |      |    |    |    +--------- ~RTS
                    130:        //       |       |      |    |    +-------------- CRC-16/CCITT
                    131:        //       |       |      |    +------------------- TX Enable
                    132:        //       |       |      +------------------------ Send Break
                    133:        //       |       +------------------------------- TX Bits
                    134:        //       +--------------------------------------- ~DTR
                    135:        static const int CR5_DTR                = 0x80;
                    136:        static const int CR5_TXBITS             = 0x60;
                    137:        static const int CR5_SENDBREAK  = 0x10;
                    138:        static const int CR5_TX_EN              = 0x08;
                    139:        static const int CR5_CRC16              = 0x04;
                    140:        static const int CR5_RTS                = 0x02;
                    141:        static const int CR5_TXCRC_EN   = 0x01;
                    142: 
                    143:        static const int WR5_DTR                = CR5_DTR;
                    144:        static const int WR5_TXBITS             = CR5_TXBITS;
                    145:        static const int WR5_SENDBREAK  = CR5_SENDBREAK;
                    146:        static const int WR5_TX_EN              = CR5_TX_EN;
                    147:        static const int WR5_CRC16              = CR5_CRC16;
                    148:        static const int WR5_RTS                = CR5_RTS;
                    149:        static const int WR5_TXCRC_EN   = CR5_TXCRC_EN;
                    150: 
1.1.1.8   root      151:        //       b7   b6   b5   b4   b3   b2   b1   b0
                    152:        //     +----+----+----+----+----+----+----+----+
1.1       root      153:        // SR0 | BA | TU | CTS| SY | DCD| TE | IP | RA |
1.1.1.8   root      154:        //     +----+----+----+----+----+----+----+----+
1.1       root      155:        static const int SR0_BREAK              = 0x80; // Break/Abort
                    156:        static const int SR0_TXUNDER    = 0x40; // Tx Underrun
                    157:        static const int SR0_CTS                = 0x20; // CTS
                    158:        static const int SR0_SYNC               = 0x10; // SYNC
                    159:        static const int SR0_DCD                = 0x08; // DCD
                    160:        static const int SR0_TXEMPTY    = 0x04; // Tx Buffer Empty
                    161:        static const int SR0_INTPEND    = 0x02; // Interrupt Pending
                    162:        static const int SR0_RXAVAIL    = 0x01; // Rx Character Available
                    163: 
                    164:        static const int RR0_BREAK              = SR0_BREAK;
                    165:        static const int RR0_TXUNDER    = SR0_TXUNDER;
                    166:        static const int RR0_CTS                = SR0_CTS;
                    167:        static const int RR0_SYNC               = SR0_SYNC;
                    168:        static const int RR0_DCD                = SR0_DCD;
                    169:        static const int RR0_TXEMPTY    = SR0_TXEMPTY;
                    170:        static const int RR0_INTPEND    = SR0_INTPEND;
                    171:        static const int RR0_RXAVAIL    = SR0_RXAVAIL;
                    172: 
1.1.1.8   root      173:        //       b7   b6   b5   b4   b3   b2   b1   b0
                    174:        //     +----+----+----+----+--------------+----+
1.1       root      175:        // SR1 | EF | CRC| RO | PE | ResidueCode  | AS |
1.1.1.8   root      176:        //     +----+----+----+----+--------------+----+
1.1       root      177:        static const int SR1_ENDOFFRAME = 0x80; // End of Frame
                    178:        static const int SR1_CRCERROR   = 0x40; // CRC/Framing Error
                    179:        static const int SR1_RXOVERRUN  = 0x20; // Rx Overrun
                    180:        static const int SR1_PARITYERROR= 0x10; // Parity Error
                    181:        static const int SR1_RESIDUEMASK= 0x0e; // Residue Code 2-0
                    182:        static const int SR1_ALL_SENT   = 0x01; // All Sent
                    183: 
                    184:        static const int RR1_ENDOFFRAME = SR1_ENDOFFRAME;
                    185:        static const int RR1_CRCERROR   = SR1_CRCERROR;
                    186:        static const int RR1_RXOVERRUN  = SR1_RXOVERRUN;
                    187:        static const int RR1_PARITYERROR= SR1_PARITYERROR;
                    188:        static const int RR1_RESIDUEMASK= SR1_RESIDUEMASK;
                    189:        static const int RR1_ALL_SENT   = SR1_ALL_SENT;
                    190: 
1.1.1.5   root      191:        // 割り込みベクタ          ChB   ChA
                    192:        // Tx Buffer Empty         %000  %100
                    193:        // External/Status Change  %001  %101
                    194:        // Rx Character Available  %010  %110
                    195:        // Special Rx Condition    %011  %111
                    196:        // (この 3bit が V4-V2 か V2-V0 のところに出力される)
                    197:        static const uint INTR_TX       = (1U << 0);
                    198:        static const uint INTR_ES       = (1U << 1);
                    199:        static const uint INTR_RX       = (1U << 2);
                    200:        static const uint INTR_SP       = (1U << 3);
                    201: 
                    202:        // 割り込みあたりのロジック (uPD7201/7201A Figure 3-2 より INT 分のみ)
                    203:        //
                    204:        //   Rx Disable (CR1:b1) *1 -----------------+    *1: Rx Enable (CR3:b0)
                    205:        //                                           |        じゃなくて?
                    206:        //                        +---+              |
                    207:        // * RxCharAvailable ---->|    |             |
                    208:        //                        | AND )--+         |  +---+
                    209:        //   All/First RxChar --->|    |   |  +---+  +->|    |
                    210:        //                        +---+    +->)    |    | AND )--+
                    211:        //                                    ) OR  )-->|    |   |
                    212:        // * Special Rx Condition ----------->)    |    +---+    |  +-+
                    213:        //                                    +---+              +->)  |
                    214:        //                                                          )   |     ---
                    215:        // * External/Status -------------------------------------->) OR |o-> INT
                    216:        //                                                          )   |
                    217:        //                                    +---+              +->)  |
                    218:        // * Tx Buffer Empty ---------------->|    |    +----+   |  +-+
                    219:        //                                    |    |    |    |   |
                    220:        //   (Reset TxIntPend Cmd) --------->o| AND )-->|    |   |
                    221:        //                                    |    |    |    |   |
                    222:        //   Tx INT/DMA Enable (CR1:b1) ----->|    |    | AND )--+
                    223:        //                                    +---+     |    |
                    224:        //                                              |    |
                    225:        //   INT DMA Mode (CR2A b1-0) ----------------->|    |
                    226:        //                                              +----+
                    227: 
1.1       root      228:        int cr2a;                       // CR2A
                    229:        int vector;
                    230:        struct channel {
                    231:                // 二次変数など
                    232:                int ptr;                        // CR0 で決まるレジスタ選択ポインタ
                    233:                int id;                         // チャンネル番号。0 か 1
                    234:                const char *name;       // チャンネル名。"A" か "B"
                    235:                const char *desc;       // チャンネルの用途(モニタ表示用)
                    236:                Mode mode;                      // CR4 で決まるモード
                    237: 
                    238:                // uPD7201 レジスタ
1.1.1.5   root      239:                // CR0 の下位 3bit (PTR 部分) は読み出し時には使わないこと (代わりに
                    240:                // ptr を使用する)。書き込み時は書き込んでよい(書き捨て)。
1.1       root      241:                uint8 cr0;
                    242:                uint8 cr1;
                    243:                                                        // CR2 は特殊なのでここにはない
                    244:                uint8 cr3;
                    245:                uint8 cr4;
                    246:                uint8 cr5;
                    247:                uint8 cr6;                      // CR6 (未実装)
                    248:                uint8 cr7;                      // CR7 (未実装)
                    249: 
                    250:                uint8 sr0;
                    251:                uint8 sr1;
                    252: 
                    253:                // ここから Z8530 拡張
1.1.1.5   root      254:                uint8 wr10;                     // WR10
1.1       root      255:                uint8 wr11;                     // WR11
                    256:                uint16 tc;                      // WR12, WR13
                    257:                uint8 wr14;                     // WR14
                    258:                uint8 wr15;                     // WR15
                    259: 
                    260:                // ここからその他の内部状態
                    261:                bool es_ratched;        // E/S ビットがラッチされているか
                    262: 
                    263:                // 受信バッファは短いので先頭からの FIFO とし、
                    264:                // 取り出したら前にずらす?
                    265:                uint8 rxbuf[3];         // 受信バッファ(FIFO)
                    266:                int   rxlen;            // 受信バッファの有効バイト数
1.1.1.5   root      267: 
1.1.1.10! root      268:                uint8 txbuf;            // 送信バッファ
        !           269:                int   txlen;            // 送信バッファの有効バイト数
        !           270:                uint8 tx_shiftreg;      // 送信シフトレジスタ相当品
        !           271: 
1.1.1.5   root      272:                // First Char 用のフラグで、この受信で割り込みを起こすなら true。
                    273:                // ALL なら常に true。FIRSTCHAR の時は最初が true で1文字目の受信
                    274:                // 割り込みを出したところで false にする。
                    275:                bool all_or_first;
                    276: 
1.1.1.10! root      277:                // 送信割り込み
        !           278:                bool txint;
1.1.1.5   root      279: 
                    280:                uint int_asserted;      // 割り込み要因を保持
1.1       root      281:        } chan[2];
                    282: };
                    283: 
1.1.1.7   root      284: class uPD7201Device : public IODevice
1.1       root      285: {
1.1.1.3   root      286:        using inherited = IODevice;
1.1       root      287:  public:
1.1.1.7   root      288:        uPD7201Device(const std::string& objname_);
1.1.1.5   root      289:        virtual ~uPD7201Device() override;
1.1       root      290: 
1.1.1.6   root      291:        void ResetHard() override;
1.1       root      292: 
                    293:        // 受信
                    294:        bool Rx(int ch, uint32 data);
                    295: 
                    296:  protected:
1.1.1.10! root      297:        void ResetChannel(SIO::channel *chan);
        !           298:        virtual uint8 ReadCtrl(SIO::channel *chan);
        !           299:        uint8 ReadData(SIO::channel *chan);
        !           300:        virtual void WriteCtrl(SIO::channel *chan, uint32 data);
        !           301:        void WriteData(SIO::channel *chan, uint32 data);
        !           302:        uint8 PeekCtrl(const SIO::channel *chan) const;
        !           303:        uint8 PeekData(const SIO::channel *chan) const;
        !           304: 
        !           305:        virtual void WriteCR0(SIO::channel *chan, uint32 data);
        !           306:        void SendAbort(SIO::channel *chan);
        !           307:        void ResetESIntr(SIO::channel *chan);
        !           308:        void EnableIntrOnNextRx(SIO::channel *chan);
        !           309:        void ResetTxIntrPending(SIO::channel *chan);
        !           310:        void ErrorReset(SIO::channel *chan);
        !           311:        void ResetHighestIUS(SIO::channel *chan);
        !           312:        void WriteCR1(SIO::channel *chan, uint32 data);
        !           313:        void WriteCR2(SIO::channel *chan, uint32 data);
        !           314:        void WriteCR3(SIO::channel *chan, uint32 data);
        !           315:        void WriteCR4(SIO::channel *chan, uint32 data);
        !           316:        virtual void WriteCR5(SIO::channel *chan, uint32 data);
        !           317:        void WriteCR6(SIO::channel *chan, uint32 data);
        !           318:        void WriteCR7(SIO::channel *chan, uint32 data);
        !           319: 
        !           320:        void TrySend(SIO::channel *chan);
        !           321:        void TXCallback(Event& event);
        !           322:        virtual void Tx(int ch, uint32 data) = 0;
1.1       root      323: 
1.1.1.10! root      324:        void ChangeInterrupt();
1.1       root      325:        // 割り込みを上げる (上位デバイスで用意する)
                    326:        virtual void Interrupt() = 0;
                    327: 
1.1.1.10! root      328:        // 指定のレジスタ名を返す
        !           329:        virtual const char *CRName(const SIO::channel *chan, int n) const;
        !           330:        virtual const char *SRName(const SIO::channel *chan, int n) const;
        !           331:        // 現在のレジスタ名を返す
        !           332:        const char *CRName(const SIO::channel *chan) const {
        !           333:                return CRName(chan, chan->ptr);
        !           334:        }
        !           335:        const char *SRName(const SIO::channel *chan) const {
        !           336:                return SRName(chan, chan->ptr);
        !           337:        }
        !           338: 
1.1       root      339:        struct SIO cr {};
                    340: 
1.1.1.10! root      341:        // TxC ピンに供給されているクロックで 12ビットの通信にかかる
        !           342:        // 時間を ns 単位で設定。12 ビットは誤差を減らすために選択。
        !           343:        uint64 txc12_ns {};
        !           344: 
        !           345:        // 送信用イベント
        !           346:        std::array<Event, 2> txevent {};
        !           347: 
1.1.1.7   root      348:        Monitor monitor { this };
                    349: 
1.1       root      350:        static const int bits_per_char[4];
1.1.1.10! root      351:        static const int clkrate[4];
1.1.1.5   root      352: 
1.1.1.8   root      353:  private:
1.1.1.10! root      354:        void SetTXPeriod(SIO::channel *chan);
1.1.1.2   root      355: 
1.1.1.7   root      356:        DECLARE_MONITOR_CALLBACK(MonitorUpdate);
1.1.1.4   root      357:        void MonitorUpdateCh(TextScreen&, int ch, int xbase, int ybase);
                    358:        void MonitorReg(TextScreen&,
                    359:                int, int, uint32 reg, const char * const *names);
1.1.1.10! root      360: 
        !           361:        static const char * const crnames[16];
        !           362:        static const char * const srnames[16];
1.1       root      363: };

unix.superglobalmegacorp.com

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