Z8530.java
     1: //========================================================================================
     2: //  Z8530.java
     3: //    en:SCC -- Serial Communication Controller
     4: //    ja:SCC -- シリアルコミュニケーションコントローラ
     5: //  Copyright (C) 2003-2017 Makoto Kamada
     6: //
     7: //  This file is part of the XEiJ (X68000 Emulator in Java).
     8: //  You can use, modify and redistribute the XEiJ if the conditions are met.
     9: //  Read the XEiJ License for more details.
    10: //  http://stdkmd.com/xeij/
    11: //========================================================================================
    12: 
    13: //----------------------------------------------------------------------------------------
    14: //  マウス
    15: //    マウスイベントとマウスモーションイベントで取得したデータを返す
    16: //  RS-232C
    17: //    ターミナルに接続
    18: //----------------------------------------------------------------------------------------
    19: 
    20: package xeij;
    21: 
    22: import java.awt.event.*;  //ActionEvent,ActionListener,ComponentAdapter,ComponentEvent,ComponentListener,FocusAdapter,FocusEvent,FocusListener,InputEvent,KeyAdapter,KeyEvent,KeyListener,MouseAdapter,MouseEvent,MouseListener,MouseMotionAdapter,MouseWheelEvent,WindowAdapter,WindowEvent,WindowListener,WindowStateListener
    23: import java.lang.*;  //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System
    24: import java.util.*;  //ArrayList,Arrays,Calendar,GregorianCalendar,HashMap,Map,Map.Entry,Timer,TimerTask,TreeMap
    25: import javax.swing.*;  //AbstractButton,AbstractSpinnerModel,Box,ButtonGroup,DefaultListModel,ImageIcon,JApplet,JButton,JCheckBox,JCheckBoxMenuItem,JComponent,JDialog,JFileChooser,JFrame,JLabel,JList,JMenu,JMenuBar,JMenuItem,JPanel,JRadioButton,JScrollPane,JSpinner,JTextArea,JTextField,JTextPane,JViewport,ScrollPaneConstants,SpinnerListModel,SpinnerNumberModel,SwingConstants,SwingUtilities,UIManager,UIDefaults,UnsupportedLookAndFeelException
    26: import javax.swing.event.*;  //CaretEvent,CaretListener,ChangeEvent,ChangeListener,DocumentEvent,DocumentListener,ListSelectionListener
    27: 
    28: public class Z8530 {
    29: 
    30:   public static final boolean SCC_DEBUG_TRACE = false;
    31:   public static boolean sccTraceOn;
    32:   public static JMenuItem sccTraceMenuItem;
    33: 
    34:   public static final int SCC_FREQ = 5000000;  //SCCの動作周波数。5MHz
    35: 
    36:   //ポート
    37:   public static final int SCC_0_COMMAND = 0x00e98001;
    38:   public static final int SCC_0_DATA    = 0x00e98003;
    39:   public static final int SCC_1_COMMAND = 0x00e98005;
    40:   public static final int SCC_1_DATA    = 0x00e98007;
    41: 
    42:   //割り込み
    43:   //  ベクタ
    44:   //    0  ポート0B送信バッファ空(マウス送信)
    45:   //    1  ポート0B外部/ステータス変化
    46:   //    2  ポート0B受信バッファフル(マウス受信)
    47:   //    3  ポート0B特別受信条件
    48:   //    4  ポート1A送信バッファ空(RS-232C送信)
    49:   //    5  ポート1A外部/ステータス変化
    50:   //    6  ポート1A受信バッファフル(RS-232C受信)
    51:   //    7  ポート1A特別受信条件
    52:   //  マスク
    53:   //    0x80  常に0
    54:   //    0x40  常に0
    55:   //    0x20  ポート1A受信バッファフル(RS-232C受信)
    56:   //    0x10  ポート1A送信バッファ空(RS-232C送信)
    57:   //    0x08  ポート1A外部/ステータス変化
    58:   //    0x04  ポート0B受信バッファフル(マウス受信)
    59:   //    0x02  ポート0B送信バッファ空(マウス送信)
    60:   //    0x01  ポート0B外部/ステータス変化
    61:   //  優先順位
    62:   //    高い  1A受信バッファフル(RS-232C受信)
    63:   //          1A送信バッファ空(RS-232C送信)
    64:   //          1A外部/ステータス変化
    65:   //          0B受信バッファフル(マウス受信)
    66:   //          0B送信バッファ空(マウス送信)
    67:   //    低い  0B外部/ステータス変化
    68:   //!!! マウス送信、外部/ステータス変化、特別受信条件の割り込みは未実装
    69:   public static int sccInterruptVector;  //非修飾ベクタ。WR2
    70:   public static int sccVectorInclude;  //WR9&0x11
    71:   //  マウス受信割り込み
    72:   public static final int SCC_0B_RECEIVE_VECTOR = 2;
    73:   public static final int SCC_0B_RECEIVE_MASK = 0x04;
    74:   public static int scc0bReceiveMask;  //マスク
    75:   public static int scc0bReceiveRR3;  //RR3のペンディングビット。割り込み発生でセット
    76:   public static int scc0bReceiveRequest;  //リクエスト。割り込み発生でセット、受け付けでクリア
    77:   public static int scc0bReceiveVector;  //修飾ベクタ
    78:   //  RS-232C受信割り込み
    79:   public static final int SCC_1A_RECEIVE_VECTOR = 6;
    80:   public static final int SCC_1A_RECEIVE_MASK = 0x20;
    81:   public static int scc1aReceiveMask;  //マスク
    82:   public static int scc1aReceiveRR3;  //RR3のペンディングビット。割り込み発生でセット
    83:   public static int scc1aReceiveRequest;  //リクエスト。割り込み発生でセット、受け付けでクリア
    84:   public static int scc1aReceiveVector;  //修飾ベクタ
    85:   //  RS-232C送信割り込み
    86:   public static final int SCC_1A_SEND_VECTOR = 4;
    87:   public static final int SCC_1A_SEND_MASK = 0x10;
    88:   public static int scc1aSendMask;  //マスク
    89:   public static int scc1aSendRR3;  //RR3のペンディングビット。割り込み発生でセット
    90:   public static int scc1aSendRequest;  //リクエスト。割り込み発生でセット、受け付けでクリア
    91:   public static int scc1aSendVector;  //修飾ベクタ
    92: 
    93:   //ポートB マウス
    94:   public static int scc0RegisterNumber;
    95:   public static int scc0Rts;  //RTS(0または1)
    96:   public static int scc0BaudRateGen;  //WR13<<8|WR12
    97:   public static int scc0InputCounter;  //マウスデータのカウンタ。0~2
    98:   public static int scc0Data1;
    99:   public static int scc0Data2;
   100:   public static final int SCC0_SCALE_MIN = 0;
   101:   public static final int SCC0_SCALE_MAX = 40;
   102:   public static final int SCC0_SCALE_MID = (SCC0_SCALE_MAX - SCC0_SCALE_MIN) >> 1;
   103:   public static int scc0ScaleIndex;  //マウスの移動速度のスケール。SCC0_SCALE_MIN~SCC0_SCALE_MAX
   104:   public static int scc0RatioX;  //マウスの移動速度の係数*65536
   105:   public static int scc0RatioY;
   106:   public static final String[] scc0Texts = new String[SCC0_SCALE_MAX - SCC0_SCALE_MIN + 1];  //スケールのテキストの配列
   107:   public static JLabel scc0Label;  //スケールのラベル
   108:   public static JSlider scc0Slider;  //スケールを指定するスライダー
   109: 
   110:   public static final boolean SCC_FSX_MOUSE = true;  //true=SX-Windowをシームレスにする
   111:   public static int sccFSXMouseHook;  //FSX.Xのマウス受信データ処理ルーチンのアドレス
   112:   public static int sccFSXMouseWork;  //FSX.Xのマウスワークのアドレス
   113: 
   114:   //ポートA RS-232C
   115:   public static final int SCC_1_INPUT_BITS = 12;
   116:   public static final int SCC_1_INPUT_SIZE = 1 << SCC_1_INPUT_BITS;
   117:   public static final int SCC_1_INPUT_MASK = SCC_1_INPUT_SIZE - 1;
   118:   public static int scc1RegisterNumber;
   119:   public static final int[] scc1InputBuffer = new int[SCC_1_INPUT_SIZE];  //RS-232C受信バッファ。データはゼロ拡張済み
   120:   public static int scc1InputRead;  //RS-232C受信バッファから次に読み出すデータの位置。read==writeのときバッファエンプティ
   121:   public static int scc1InputWrite;  //RS-232C受信バッファに次に書き込むデータの位置。(write+1&SCC_1_INPUT_MASK)==readのときバッファフル
   122:   //  ボーレート
   123:   public static int scc1ClockModeShift;  //WR4のbit6-7。0=2^0,1=2^4,2=2^5,3=2^6
   124:   public static int scc1BaudRateGen;  //WR13<<8|WR12
   125:   public static long scc1Interval;  //転送間隔(XEiJ.TMR_FREQ単位)
   126:   public static long scc1InputClock;  //受信バッファの先頭のデータの受信予定時刻
   127: 
   128:   public static final TickerQueue.Ticker sccTicker = new TickerQueue.Ticker () {
   129:     @Override protected void tick () {
   130:       if (SCC_DEBUG_TRACE && sccTraceOn) {
   131:         System.out.printf ("%08x sccTicker.tick()\n", XEiJ.regPC0);
   132:       }
   133:       if (scc1aReceiveMask != 0) {
   134:         scc1aReceiveRR3 = SCC_1A_RECEIVE_MASK;
   135:         scc1aReceiveRequest = SCC_1A_RECEIVE_MASK;
   136:         XEiJ.mpuIRR |= XEiJ.MPU_SCC_INTERRUPT_MASK;
   137:       }
   138:     }
   139:   };
   140: 
   141:   //sccInit ()
   142:   //  SCCを初期化する
   143:   public static void sccInit () {
   144: 
   145:     if (SCC_DEBUG_TRACE) {
   146:       sccTraceOn = true;
   147:       sccTraceMenuItem = Multilingual.mlnText (
   148:         ComponentFactory.createCheckBoxMenuItem (sccTraceOn, "SCC Trace", new ActionListener () {
   149:           @Override public void actionPerformed (ActionEvent ae) {
   150:             sccTraceOn = ((JCheckBoxMenuItem) ae.getSource ()).isSelected ();
   151:           }
   152:         }),
   153:         "ja", "SCC トレース");
   154:     }
   155: 
   156:     //scc0ScaleIndex = SCC0_SCALE_MID;
   157: 
   158:     //ラベル
   159:     //scc0Texts = new String[SCC0_SCALE_MAX - SCC0_SCALE_MIN + 1];
   160:     for (int i = SCC0_SCALE_MIN; i <= SCC0_SCALE_MAX; i++) {
   161:       scc0Texts[i - SCC0_SCALE_MIN] = String.format ("%4.2f", Math.pow (4.0, (double) (i - SCC0_SCALE_MID) / (double) SCC0_SCALE_MID));
   162:     }
   163:     scc0Label = ComponentFactory.createLabel (scc0Texts[SCC0_SCALE_MID]);
   164:     //スライダー
   165:     scc0Slider = ComponentFactory.setEnabled (
   166:       ComponentFactory.setPreferredSize (
   167:         ComponentFactory.createHorizontalSlider (
   168:           SCC0_SCALE_MIN,
   169:           SCC0_SCALE_MAX,
   170:           scc0ScaleIndex,
   171:           (SCC0_SCALE_MAX - SCC0_SCALE_MIN) / 4,
   172:           1,
   173:           scc0Texts,
   174:           new ChangeListener () {
   175:             @Override public void stateChanged (ChangeEvent ce) {
   176:               scc0SetScaleIndex (((JSlider) ce.getSource ()).getValue ());
   177:             }
   178:           }),
   179:         224, 43),
   180:       XEiJ.rbtRobot != null);
   181: 
   182:     //scc1InputBuffer = new int[SCC_1_INPUT_SIZE];
   183: 
   184:     sccReset ();
   185: 
   186:   }  //sccInit()
   187: 
   188:   //リセット
   189:   public static void sccReset () {
   190:     //割り込み
   191:     sccInterruptVector = 0x00;
   192:     sccVectorInclude = 0x00;
   193:     scc0bReceiveMask = 0;
   194:     scc0bReceiveRR3 = 0;
   195:     scc0bReceiveRequest = 0;
   196:     scc0bReceiveVector = 0;
   197:     scc1aReceiveMask = 0;
   198:     scc1aReceiveRR3 = 0;
   199:     scc1aReceiveRequest = 0;
   200:     scc1aReceiveVector = 0;
   201:     scc1aSendMask = 0;
   202:     scc1aSendRR3 = 0;
   203:     scc1aSendRequest = 0;
   204:     scc1aSendVector = 0;
   205:     //マウス
   206:     scc0RegisterNumber = 0;
   207:     scc0Rts = 0;
   208:     scc0BaudRateGen = 31;  //4800bps。(5000000/2/16)/4800-2=30.552。(5000000/2/16)/(31+2)=4734.848=4800*0.986
   209:     scc0InputCounter = 0;
   210:     scc0Data1 = 0;
   211:     scc0Data2 = 0;
   212:     //scc0ScaleIndex = SCC0_SCALE_MID;
   213:     scc0SetScaleIndex (scc0ScaleIndex);
   214:     if (SCC_FSX_MOUSE) {
   215:       sccFSXMouseHook = 0;
   216:       sccFSXMouseWork = 0;
   217:     }
   218:     //RS-232C
   219:     scc1RegisterNumber = 0;
   220:     Arrays.fill (scc1InputBuffer, 0);
   221:     scc1InputRead = 0;
   222:     scc1InputWrite = 0;
   223:     //  ボーレート
   224:     scc1BaudRateGen = 14;  //9600bps。(5000000/2/16)/9600-2=14.276。(5000000/2/16)/(14+2)=9765.625=9600*1.017
   225:     scc1ClockModeShift = 1;  //1/16
   226:     scc1Interval = XEiJ.TMR_FREQ / ((SCC_FREQ / 2 >> scc1ClockModeShift) / (scc1BaudRateGen + 2));
   227:     scc1InputClock = XEiJ.FAR_FUTURE;
   228:     TickerQueue.tkqRemove (sccTicker);
   229:   }  //sccReset()
   230: 
   231:   public static void scc0SetScaleIndex (int i) {
   232:     scc0ScaleIndex = i;
   233:     scc0Label.setText (scc0Texts[i]);
   234:     scc0UpdateRatio ();
   235:   }  //scc0SetScaleIndex(int)
   236: 
   237:   public static void scc0UpdateRatio () {
   238:     double scale = Math.pow (4.0, (double) (scc0ScaleIndex - SCC0_SCALE_MID) / (double) SCC0_SCALE_MID);
   239:     if (XEiJ.musHostsPixelUnitsOn) {
   240:       //scc0RatioX = (int) Math.round (65536.0 * scale * (double) XEiJ.pnlScreenWidth / (double) XEiJ.pnlZoomWidth);
   241:       //scc0RatioY = (int) Math.round (65536.0 * scale * (double) XEiJ.pnlScreenHeight / (double) XEiJ.pnlZoomHeight);
   242:       scc0RatioX = (int) (65536.0 * scale * (double) XEiJ.pnlScreenWidth / (double) XEiJ.pnlZoomWidth);
   243:       scc0RatioY = (int) (65536.0 * scale * (double) XEiJ.pnlScreenHeight / (double) XEiJ.pnlZoomHeight);
   244:     } else {
   245:       //scc0RatioX = (int) Math.round (65536.0 * scale);
   246:       //scc0RatioY = (int) Math.round (65536.0 * scale);
   247:       scc0RatioX = (int) (65536.0 * scale);
   248:       scc0RatioY = (int) (65536.0 * scale);
   249:     }
   250:   }  //scc0UpdateRatio()
   251: 
   252:   //割り込み受付
   253:   //  コアが割り込み要求を受け付けたときに呼び出す
   254:   //  割り込みベクタ番号を返す
   255:   //  割り込み要求を取り下げる場合は0を返す
   256:   //  オートベクタを使用するデバイスはオートベクタの番号を返すこと
   257:   public static int sccAcknowledge () {
   258:     int d = 0;
   259:     //優先順位は固定
   260:     if (scc1aReceiveRequest != 0) {  //1A受信バッファフル(RS-232C受信)
   261:       scc1aReceiveRequest = 0;
   262:       d = scc1aReceiveVector;
   263:     } else if (scc1aSendRequest != 0) {  //1A送信バッファ空(RS-232C送信)
   264:       scc1aSendRequest = 0;
   265:       d = scc1aSendVector;
   266:     } else if (scc0bReceiveRequest != 0) {  //0B受信バッファフル(マウス受信)
   267:       scc0bReceiveRequest = 0;
   268:       d = scc0bReceiveVector;
   269:     }
   270:     if (SCC_DEBUG_TRACE && sccTraceOn) {
   271:       System.out.printf ("%08x sccAcknowledge()=0x%02x\n", XEiJ.regPC0, d);
   272:     }
   273:     return d;
   274:   }  //sccAcknowledge()
   275: 
   276:   //割り込み終了
   277:   //  コアが割り込み処理を終了したときに呼び出す
   278:   //  まだ処理されていない割り込みが残っていたら再度割り込み要求を出す
   279:   public static void sccDone () {
   280:     if (SCC_DEBUG_TRACE && sccTraceOn) {
   281:       System.out.printf ("%08x sccDone()\n", XEiJ.regPC0);
   282:     }
   283:     if ((scc1aReceiveRequest | scc1aSendRequest | scc0bReceiveRequest) != 0) {
   284:       XEiJ.mpuIRR |= XEiJ.MPU_SCC_INTERRUPT_MASK;
   285:     }
   286:   }  //sccDone()
   287: 
   288:   //scc1Receive (d)
   289:   //  RS-232C受信
   290:   //  コアのスレッドで呼び出すこと
   291:   public static void scc1Receive (int d) {
   292:     int next = scc1InputWrite + 1 & SCC_1_INPUT_MASK;
   293:     if (next != scc1InputRead) {  //バッファフルではない
   294:       scc1InputBuffer[scc1InputWrite] = 0xff & d;  //ゼロ拡張してから書き込む
   295:       if (scc1InputRead == scc1InputWrite) {  //バッファが空だったとき
   296:         scc1InputClock = XEiJ.mpuClockTime;  //受信バッファの先頭のデータの受信予定時刻
   297:         TickerQueue.tkqAdd (sccTicker, scc1InputClock);  //割り込みを発生させる
   298:       }
   299:       scc1InputWrite = next;
   300:     }
   301:   }  //scc1Receive(int)
   302: 
   303:   //sccUpdateVector ()
   304:   //  scc0bReceiveVector,scc1aReceiveVector,scc1aSendVectorを更新する
   305:   //  sccInterruptVector,sccVectorIncludeを更新したら呼び出す
   306:   public static void sccUpdateVector () {
   307:     if (sccVectorInclude == 0x00) {  //(WR9&0x01)==0x00
   308:       scc0bReceiveVector = sccInterruptVector;
   309:       scc1aReceiveVector = sccInterruptVector;
   310:       scc1aSendVector    = sccInterruptVector;
   311:     } else if (sccVectorInclude == 0x01) {  //(WR9&0x11)==0x01
   312:       int t = sccInterruptVector & 0b11110001;
   313:       scc0bReceiveVector = t | SCC_0B_RECEIVE_VECTOR << 1;
   314:       scc1aReceiveVector = t | SCC_1A_RECEIVE_VECTOR << 1;
   315:       scc1aSendVector    = t | SCC_1A_SEND_VECTOR << 1;
   316:     } else {  //(WR9&0x11)==0x11
   317:       int t = sccInterruptVector & 0b10001111;
   318:       scc0bReceiveVector = t | SCC_0B_RECEIVE_VECTOR << 4;
   319:       scc1aReceiveVector = t | SCC_1A_RECEIVE_VECTOR << 4;
   320:       scc1aSendVector    = t | SCC_1A_SEND_VECTOR << 4;
   321:     }
   322:     if (SCC_DEBUG_TRACE) {
   323:       System.out.printf ("scc0bReceiveVector=0x%02x\n", scc0bReceiveVector);
   324:       System.out.printf ("scc1aReceiveVector=0x%02x\n", scc1aReceiveVector);
   325:       System.out.printf ("scc1aSendVector=0x%02x\n", scc1aSendVector);
   326:     }
   327:   }  //sccUpdateVector()
   328: 
   329: }  //class Z8530
   330: 
   331: 
   332: