MC68901.java
     1: //========================================================================================
     2: //  MC68901.java
     3: //    en:MFP -- Multi-Function Peripheral
     4: //    ja:MFP -- マルチファンクションペリフェラル
     5: //  Copyright (C) 2003-2025 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: //  https://stdkmd.net/xeij/
    11: //========================================================================================
    12: 
    13: package xeij;
    14: 
    15: import java.lang.*;  //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System
    16: 
    17: public class MC68901 {
    18: 
    19:   public static final boolean MFP_DELAYED_INTERRUPT = true;  //true=MFPの割り込み要求を1命令遅延させる
    20: 
    21:   //レジスタ
    22:   public static final int MFP_GPIP_DATA = 0x00e88001;  //GPIPデータレジスタ
    23:   public static final int MFP_AER       = 0x00e88003;  //アクティブエッジレジスタ。各ビット0=1→0,1=0→1
    24:   public static final int MFP_DDR       = 0x00e88005;  //データディレクションレジスタ。各ビット0=入力,1=出力。全ビット入力なので0x00に固定
    25:   public static final int MFP_IERA      = 0x00e88007;  //割り込みイネーブルレジスタA。各ビット0=ディセーブル,1=イネーブル
    26:   public static final int MFP_IERB      = 0x00e88009;  //割り込みイネーブルレジスタB。各ビット0=ディセーブル,1=イネーブル
    27:   public static final int MFP_IPRA      = 0x00e8800b;  //割り込みペンディングレジスタA
    28:   public static final int MFP_IPRB      = 0x00e8800d;  //割り込みペンディングレジスタB
    29:   public static final int MFP_ISRA      = 0x00e8800f;  //割り込みインサービスレジスタA
    30:   public static final int MFP_ISRB      = 0x00e88011;  //割り込みインサービスレジスタB
    31:   public static final int MFP_IMRA      = 0x00e88013;  //割り込みマスクレジスタA
    32:   public static final int MFP_IMRB      = 0x00e88015;  //割り込みマスクレジスタB
    33:   public static final int MFP_VECTOR    = 0x00e88017;  //ベクタレジスタ
    34:   public static final int MFP_TACR      = 0x00e88019;  //タイマAコントロールレジスタ
    35:   public static final int MFP_TBCR      = 0x00e8801b;  //タイマBコントロールレジスタ
    36:   public static final int MFP_TCDCR     = 0x00e8801d;  //タイマC,Dコントロールレジスタ
    37:   //  タイマのカウンタに$00を書き込んで1/200プリスケールで開始したとき、カウンタから読み出される値は最初の50μs間は$00、次の50μs間は$FF
    38:   public static final int MFP_TADR      = 0x00e8801f;  //タイマAデータレジスタ
    39:   public static final int MFP_TBDR      = 0x00e88021;  //タイマBデータレジスタ
    40:   public static final int MFP_TCDR      = 0x00e88023;  //タイマCデータレジスタ
    41:   public static final int MFP_TDDR      = 0x00e88025;  //タイマDデータレジスタ
    42:   public static final int MFP_SYNC_CHAR = 0x00e88027;  //同期キャラクタレジスタ
    43:   public static final int MFP_UCR       = 0x00e88029;  //USARTコントロールレジスタ
    44:   public static final int MFP_RSR       = 0x00e8802b;  //受信ステータスレジスタ
    45:   public static final int MFP_TSR       = 0x00e8802d;  //送信ステータスレジスタ
    46:   public static final int MFP_UDR       = 0x00e8802f;  //USARTデータレジスタ
    47: 
    48:   //GPIP
    49:   //  GPIP7 H-SYNC
    50:   //    1  水平帰線期間
    51:   //    0  水平表示期間(水平バックポーチ/水平映像期間/水平フロントポーチ)
    52:   //  GPIP6 CRTC IRQ
    53:   //    0  指定されたラスタ
    54:   //    1  その他のラスタ
    55:   //    遷移は直前の水平フロントポーチの開始位置付近、V-DISPも遷移するときはその直前
    56:   //    0番は垂直帰線期間の最初のラスタ
    57:   //      CRTC R06+1==CRTC R09のとき、指定されたラスタの開始(CRTC IRQ 1→0)と垂直映像期間の開始(V-DISP 0→1)が同じラスタになる
    58:   //  GPIP5
    59:   //    RTCのCLKOUT(1Hz)が接続されることになっていたが欠番になった
    60:   //  GPIP4 V-DISP
    61:   //    1  垂直映像期間
    62:   //    0  垂直フロントポーチ/垂直帰線期間/垂直バックポーチ
    63:   //    遷移は直前の水平フロントポーチの開始位置付近
    64:   public static final int MFP_GPIP_ALARM_LEVEL  = 0;  //0=ALARMによる電源ON
    65:   public static final int MFP_GPIP_EXPWON_LEVEL = 1;  //0=EXPWONによる電源ON
    66:   public static final int MFP_GPIP_POWER_LEVEL  = 2;  //0=POWERスイッチON
    67:   public static final int MFP_GPIP_OPMIRQ_LEVEL = 3;  //0=OPM割り込み要求あり
    68:   public static final int MFP_GPIP_VDISP_LEVEL  = 4;  //1=垂直映像期間,0=それ以外
    69:   public static final int MFP_GPIP_RINT_LEVEL   = 6;  //0=指定されたラスタ,1=それ以外
    70:   public static final int MFP_GPIP_HSYNC_LEVEL  = 7;  //0=水平表示期間,1=水平帰線期間
    71: 
    72:   //GPIPマスク
    73:   public static final int MFP_GPIP_ALARM_MASK  = 1 << MFP_GPIP_ALARM_LEVEL;
    74:   public static final int MFP_GPIP_EXPWON_MASK = 1 << MFP_GPIP_EXPWON_LEVEL;
    75:   public static final int MFP_GPIP_POWER_MASK  = 1 << MFP_GPIP_POWER_LEVEL;
    76:   public static final int MFP_GPIP_OPMIRQ_MASK = 1 << MFP_GPIP_OPMIRQ_LEVEL;
    77:   public static final int MFP_GPIP_VDISP_MASK  = 1 << MFP_GPIP_VDISP_LEVEL;
    78:   public static final int MFP_GPIP_RINT_MASK   = 1 << MFP_GPIP_RINT_LEVEL;
    79:   public static final int MFP_GPIP_HSYNC_MASK  = 1 << MFP_GPIP_HSYNC_LEVEL;
    80: 
    81:   //割り込みレベル
    82:   public static final int MFP_ALARM_LEVEL        =  0;  //40:MFP B0 GPIP0 RTC ALARM
    83:   public static final int MFP_EXPWON_LEVEL       =  1;  //41:MFP B1 GPIP1 EXPWON
    84:   public static final int MFP_POWER_LEVEL        =  2;  //42:MFP B2 GPIP2 POWER
    85:   public static final int MFP_OPMIRQ_LEVEL       =  3;  //43:MFP B3 GPIP3 FM音源
    86:   public static final int MFP_TIMER_D_LEVEL      =  4;  //44:MFP B4 Timer-D バックグラウンドスレッド
    87:   public static final int MFP_TIMER_C_LEVEL      =  5;  //45:MFP B5 Timer-C マウス処理,テキストカーソル,FDDモーターOFF,稼働時間計測
    88:   public static final int MFP_VDISP_LEVEL        =  6;  //46:MFP B6 GPIP4 V-DISP
    89:   public static final int MFP_TIMER_B_LEVEL      =  8;  //48:MFP A0 Timer-B キーボードシリアルクロック
    90:   public static final int MFP_OUTPUT_ERROR_LEVEL =  9;  //49:MFP A1 キーボードシリアル出力エラー
    91:   public static final int MFP_OUTPUT_EMPTY_LEVEL = 10;  //4A:MFP A2 キーボードシリアル出力空
    92:   public static final int MFP_INPUT_ERROR_LEVEL  = 11;  //4B:MFP A3 キーボードシリアル入力エラー
    93:   public static final int MFP_INPUT_FULL_LEVEL   = 12;  //4C:MFP A4 キーボードシリアル入力あり
    94:   public static final int MFP_TIMER_A_LEVEL      = 13;  //4D:MFP A5 Timer-A(V-DISPイベントカウント)
    95:   public static final int MFP_RINT_LEVEL         = 14;  //4E:MFP A6 GPIP6 CRTC IRQ
    96:   public static final int MFP_HSYNC_LEVEL        = 15;  //4F:MFP A7 GPIP7 H-SYNC
    97: 
    98:   //割り込みマスク
    99:   public static final int MFP_ALARM_MASK        = 1 << MFP_ALARM_LEVEL;
   100:   public static final int MFP_EXPWON_MASK       = 1 << MFP_EXPWON_LEVEL;
   101:   public static final int MFP_POWER_MASK        = 1 << MFP_POWER_LEVEL;
   102:   public static final int MFP_OPMIRQ_MASK       = 1 << MFP_OPMIRQ_LEVEL;
   103:   public static final int MFP_TIMER_D_MASK      = 1 << MFP_TIMER_D_LEVEL;
   104:   public static final int MFP_TIMER_C_MASK      = 1 << MFP_TIMER_C_LEVEL;
   105:   public static final int MFP_VDISP_MASK        = 1 << MFP_VDISP_LEVEL;
   106:   public static final int MFP_TIMER_B_MASK      = 1 << MFP_TIMER_B_LEVEL;
   107:   public static final int MFP_OUTPUT_ERROR_MASK = 1 << MFP_OUTPUT_ERROR_LEVEL;
   108:   public static final int MFP_OUTPUT_EMPTY_MASK = 1 << MFP_OUTPUT_EMPTY_LEVEL;
   109:   public static final int MFP_INPUT_ERROR_MASK  = 1 << MFP_INPUT_ERROR_LEVEL;
   110:   public static final int MFP_INPUT_FULL_MASK   = 1 << MFP_INPUT_FULL_LEVEL;
   111:   public static final int MFP_TIMER_A_MASK      = 1 << MFP_TIMER_A_LEVEL;
   112:   public static final int MFP_RINT_MASK         = 1 << MFP_RINT_LEVEL;
   113:   public static final int MFP_HSYNC_MASK        = 1 << MFP_HSYNC_LEVEL;
   114: 
   115:   public static final long MFP_OSC_FREQ = 4000000L;  //MFPのオシレータの周波数
   116: 
   117:   //タイマのプリスケール
   118:   public static final long MFP_DELTA[] = {
   119:     XEiJ.FAR_FUTURE,                     //0:カウント禁止
   120:     4 * XEiJ.TMR_FREQ / MFP_OSC_FREQ,    //1:1/4プリスケール(1μs)
   121:     10 * XEiJ.TMR_FREQ / MFP_OSC_FREQ,   //2:1/10プリスケール(2.5μs)
   122:     16 * XEiJ.TMR_FREQ / MFP_OSC_FREQ,   //3:1/16プリスケール(4μs)
   123:     50 * XEiJ.TMR_FREQ / MFP_OSC_FREQ,   //4:1/50プリスケール(12.5μs)
   124:     64 * XEiJ.TMR_FREQ / MFP_OSC_FREQ,   //5:1/64プリスケール(16μs)
   125:     100 * XEiJ.TMR_FREQ / MFP_OSC_FREQ,  //6:1/100プリスケール(25μs)
   126:     200 * XEiJ.TMR_FREQ / MFP_OSC_FREQ,  //7:1/200プリスケール(50μs)
   127:   };
   128: 
   129:   //MFP_UDRの入力データのキュー
   130:   public static final int MFP_UDR_QUEUE_BITS = 4;  //キューの長さのビット数
   131:   public static final int MFP_UDR_QUEUE_SIZE = 1 << MFP_UDR_QUEUE_BITS;  //キューの長さ
   132:   public static final int MFP_UDR_QUEUE_MASK = MFP_UDR_QUEUE_SIZE - 1;  //キューの長さのマスク
   133: 
   134:   //GPIPデータレジスタ
   135:   //  値は0または該当するビットのマスク
   136:   //  ゼロ拡張
   137:   public static int mfpGpipAlarm;  //0またはMFP_GPIP_ALARM_MASK
   138:   public static int mfpGpipExpwon;  //0またはMFP_GPIP_EXPWON_MASK
   139:   public static int mfpGpipPower;  //0またはMFP_GPIP_POWER_MASK
   140:   public static int mfpGpipOpmirq;  //0またはMFP_GPIP_OPMIRQ_MASK
   141:   public static int mfpGpipVdisp;  //0またはMFP_GPIP_VDISP_MASK
   142:   public static int mfpGpipRint;  //0またはMFP_GPIP_RINT_MASK
   143:   public static int mfpGpipHsync;  //0またはMFP_GPIP_HSYNC_MASK
   144: 
   145:   //レジスタ
   146:   //  ゼロ拡張
   147:   public static int mfpAer;  //アクティブエッジレジスタ
   148:   public static int mfpIer;  //割り込みイネーブルレジスタ(上位バイトがMFP_IERA、下位バイトがMFP_IERB)
   149:   public static int mfpImr;  //割り込みマスクレジスタ(上位バイトがMFP_IMRA、下位バイトがMFP_IMRB)
   150:   public static int mfpVectorHigh;  //ベクタレジスタのビット7~4
   151:   public static int mfpTaPrescale;  //タイマAのプリスケール(0~7、0はカウント禁止)
   152:   public static int mfpTbPrescale;  //タイマBのプリスケール(0~7、0はカウント禁止)
   153:   public static int mfpTcPrescale;  //タイマCのプリスケール(0~7、0はカウント禁止)
   154:   public static int mfpTdPrescale;  //タイマDのプリスケール(0~7、0はカウント禁止)
   155:   public static boolean mfpTaEventcount;  //タイマAイベントカウントモード
   156:   public static boolean mfpTbEventcount;  //タイマBイベントカウントモード
   157:   public static int mfpTaInitial;  //タイマAの初期値(1~256)
   158:   public static int mfpTbInitial;  //タイマBの初期値(1~256)
   159:   public static int mfpTcInitial;  //タイマCの初期値(1~256)
   160:   public static int mfpTdInitial;  //タイマDの初期値(1~256)
   161:   public static int mfpTaCurrent;  //タイマAの現在の値(1~256、イベントカウントモードのときとディレイモードでカウンタが停止しているときだけ有効)
   162:   public static int mfpTbCurrent;  //タイマBの現在の値(1~256、イベントカウントモードのときとディレイモードでカウンタが停止しているときだけ有効)
   163:   public static int mfpTcCurrent;  //タイマCの現在の値(1~256、イベントカウントモードのときとディレイモードでカウンタが停止しているときだけ有効)
   164:   public static int mfpTdCurrent;  //タイマDの現在の値(1~256、イベントカウントモードのときとディレイモードでカウンタが停止しているときだけ有効)
   165:   public static boolean mfpTbKeyboardOn;  //TBCRに$01、TBDRに$0Dが設定されている。キーボードと通信できる
   166: 
   167:   public static int mfpUCR;  //USARTコントロールレジスタ
   168:   //  |CLK|CL1|CL0|ST1|ST0|PE|E/O|-|
   169:   //   |   |       |       |  |
   170:   //   |   |       |       |  パリティの奇遇
   171:   //   |   |       |       |  1=偶数
   172:   //   |   |       |       |  0=奇数
   173:   //   |   |       |       パリティの有無
   174:   //   |   |       |       1=パリティあり
   175:   //   |   |       |       0=パリティなし
   176:   //   |   |       スタートストップ
   177:   //   |   |       00=同期
   178:   //   |   |       01=非同期 スタート1bit ストップ1bit
   179:   //   |   |       10=非同期 スタート1bit ストップ1.5bit
   180:   //   |   |       11=非同期 スタート1bit ストップ2bit
   181:   //   |   キャラクタ長
   182:   //   |   00=8bit
   183:   //   |   01=7bit
   184:   //   |   10=6bit
   185:   //   |   11=5bit
   186:   //   クロックモード
   187:   //   0  1/16
   188:   //   1  1/1
   189:   public static int mfpRSR;  //受信ステータスレジスタ
   190:   //  |BF|OE|PE|FE|F/S OR B|M/CIP|SS|RE|
   191:   //   |  |  |  |  |        |     |  |
   192:   //   |  |  |  |  |        |     |  受信イネーブル
   193:   //   |  |  |  |  |        |     |  1=受信可
   194:   //   |  |  |  |  |        |     Synchronous Strip Enable
   195:   //   |  |  |  |  |        Match/Character in Progress
   196:   //   |  |  |  |  Found/Search or Break Detect
   197:   //   |  |  |  フレームエラー
   198:   //   |  |  |  1=フレームエラーあり
   199:   //   |  |  パリティエラー
   200:   //   |  |  1=パリティエラーあり
   201:   //   |  オーバーランエラー
   202:   //   |  1=オーバーランエラーあり。UDRがリードされる前に次のデータが来た
   203:   //   バッファフル
   204:   //   1=受信バッファフル。次のデータをUDRからリードできる
   205:   //   0=受信バッファ空
   206:   public static int mfpTSR;  //送信ステータスレジスタ
   207:   //  |BE|UE|AT|END|B|H|L|TE|
   208:   //   |  |  |  |   | |   |
   209:   //   |  |  |  |   | |   送信イネーブル
   210:   //   |  |  |  |   | |   1=送信可
   211:   //   |  |  |  |   | High and Low
   212:   //   |  |  |  |   Break
   213:   //   |  |  |  End of transmission
   214:   //   |  |  Auto-Turnaround
   215:   //   |  アンダーランエラー
   216:   //   バッファエンプティ
   217:   //   1=送信バッファ空。次のデータをUDRへライトできる
   218:   //   0=送信バッファフル。次のデータをUDRへライトできない
   219:   public static long mfpTSRBufferFullTime;  //送信バッファフル時間
   220:   public static long mfpTSRBufferFullEnd;  //送信バッファフル終了時刻
   221: 
   222:   //割り込み
   223:   //  割り込み要求カウンタと割り込み受付カウンタの値が異なるときMFP_IPRA,MFP_IPRBの該当ビットがONになる
   224:   //  MFP_IERA,MFP_IERBの該当ビットに0が書き込まれたときMFP_IPRA,MFP_IPRBの該当ビットを0にするためrequestをacknowledgedにコピーする
   225:   public static final int[] mfpInnerRequest = new int[16];  //割り込み要求カウンタ
   226:   public static final int[] mfpInnerAcknowledged = new int[16];  //割り込み受付カウンタ
   227:   public static final boolean[] mfpInnerInService = new boolean[16];  //割り込み処理中のときtrue
   228:   public static int mfpInnerLevel;  //割り込み処理中のレベル
   229: 
   230:   //タイマ
   231:   public static long mfpTaStart;  //タイマAの初期値からスタートしたときのクロック
   232:   public static long mfpTbStart;  //タイマBの初期値からスタートしたときのクロック
   233:   public static long mfpTcStart;  //タイマCの初期値からスタートしたときのクロック
   234:   public static long mfpTdStart;  //タイマDの初期値からスタートしたときのクロック
   235:   public static long mfpTaDelta;  //タイマAのプリスケールに対応する1カウントあたりの時間
   236:   public static long mfpTbDelta;  //タイマBのプリスケールに対応する1カウントあたりの時間
   237:   public static long mfpTcDelta;  //タイマCのプリスケールに対応する1カウントあたりの時間
   238:   public static long mfpTdDelta;  //タイマDのプリスケールに対応する1カウントあたりの時間
   239:   public static long mfpTaClock;  //タイマAが次に割り込む時刻
   240:   public static long mfpTbClock;  //タイマBが次に割り込む時刻
   241:   public static long mfpTcClock;  //タイマCが次に割り込む時刻
   242:   public static long mfpTdClock;  //タイマDが次に割り込む時刻
   243: 
   244:   //MFP_UDRの入力データのキュー
   245:   //  入力データはゼロ拡張すること
   246:   //  キー入力を取りこぼさないためにキューを使う
   247:   //  read==writeのときキューは空
   248:   //  write+1==readのときキューは満杯
   249:   public static final int[] mfpUdrQueueArray = new int[MFP_UDR_QUEUE_SIZE];  //入力データ
   250:   public static volatile int mfpUdrQueueRead;  //最後に読み出したデータの位置
   251:   public static volatile int mfpUdrQueueWrite;  //最後に書き込んだデータの位置
   252: 
   253:   //mfpInit ()
   254:   //  MFPを初期化する
   255:   public static void mfpInit () {
   256:     //mfpInnerRequest = new int[16];
   257:     //mfpInnerAcknowledged = new int[16];
   258:     //mfpInnerInService = new boolean[16];
   259:     //mfpUdrQueueArray = new int[MFP_UDR_QUEUE_SIZE];
   260:     for (int i = 0; i < MFP_UDR_QUEUE_SIZE; i++) {
   261:       mfpUdrQueueArray[i] = 0;
   262:     }
   263:     mfpUdrQueueRead = 0;
   264:     mfpUdrQueueWrite = 0;
   265:     mfpReset ();
   266:   }  //mfpInit()
   267: 
   268:   //リセット
   269:   public static void mfpReset () {
   270:     mfpGpipAlarm = 0;
   271:     mfpGpipExpwon = MFP_GPIP_EXPWON_MASK;
   272:     mfpGpipPower = 0;
   273:     mfpGpipOpmirq = MFP_GPIP_OPMIRQ_MASK;
   274:     mfpGpipVdisp = 0;
   275:     mfpGpipRint = MFP_GPIP_RINT_MASK;
   276:     mfpGpipHsync = 0;
   277:     mfpAer = 0;
   278:     mfpIer = 0;
   279:     for (int i = 0; i < 16; i++) {
   280:       mfpInnerRequest[i] = 0;
   281:       mfpInnerAcknowledged[i] = 0;
   282:       mfpInnerInService[i] = false;
   283:     }
   284:     mfpImr = 0;
   285:     mfpVectorHigh = 0;
   286:     mfpTaPrescale = 0;
   287:     mfpTbPrescale = 0;
   288:     mfpTcPrescale = 0;
   289:     mfpTdPrescale = 0;
   290:     mfpTaEventcount = false;
   291:     mfpTbEventcount = false;
   292:     mfpTaInitial = 256;
   293:     mfpTbInitial = 256;
   294:     mfpTcInitial = 256;
   295:     mfpTdInitial = 256;
   296:     mfpTaCurrent = 0;
   297:     mfpTbCurrent = 0;
   298:     mfpTcCurrent = 0;
   299:     mfpTdCurrent = 0;
   300:     mfpTaStart = 0L;
   301:     mfpTbStart = 0L;
   302:     mfpTcStart = 0L;
   303:     mfpTdStart = 0L;
   304:     mfpTaClock = XEiJ.FAR_FUTURE;
   305:     mfpTbClock = XEiJ.FAR_FUTURE;
   306:     mfpTcClock = XEiJ.FAR_FUTURE;
   307:     mfpTdClock = XEiJ.FAR_FUTURE;
   308:     mfpUCR = 0x88;
   309:     mfpRSR = 0x01;
   310:     mfpTSR = 0x01;
   311:     mfpTSRBufferFullTime = 0L;
   312:     mfpTSRBufferFullEnd = 0L;
   313:     if (MFP_KBD_ON) {
   314:       //mfpKbdBuffer = new int[MFP_KBD_LIMIT];
   315:       mfpKbdReadPointer = 0;
   316:       mfpKbdWritePointer = 0;
   317:       mfpKbdLastData = 0;
   318:       mfpTkClock = XEiJ.FAR_FUTURE;
   319:       //mfpTkTime = 0L;
   320:     }
   321:     TickerQueue.tkqRemove (mfpTaTicker);
   322:     TickerQueue.tkqRemove (mfpTbTicker);
   323:     TickerQueue.tkqRemove (mfpTcTicker);
   324:     TickerQueue.tkqRemove (mfpTdTicker);
   325:     TickerQueue.tkqRemove (mfpTkTicker);
   326:   }  //mfpReset()
   327: 
   328:   //割り込み受付
   329:   //  コアが割り込み要求を受け付けたときに呼び出す
   330:   //  割り込みベクタ番号を返す
   331:   //  割り込み要求を取り下げる場合は0を返す
   332:   //  オートベクタを使用するデバイスはオートベクタの番号を返すこと
   333:   //
   334:   //! 未対応
   335:   //  スプリアス割り込みは発生しない
   336:   //  実機ではデバイスからMFPへの割り込み要求とMPUからMFPへの割り込み禁止指示がほぼ同時に発生するとスプリアス割り込みが通知されることがある
   337:   //    (1) デバイスがMFPに割り込みを要求する
   338:   //    (2) MPUがMFPにデバイスの割り込みの禁止を指示する
   339:   //    (3) MFPがデバイスの要求に従ってMPUに割り込みを要求する
   340:   //    (4) MFPがMPUの指示に従ってデバイスの割り込みを禁止する
   341:   //    (5) MPUがMFPの割り込み要求を受け付けてMFPに割り込みベクタの提出を指示する
   342:   //    (6) MFPがMPUの指示に従って割り込みが許可されていて割り込みを要求しているデバイスを探すが見当たらないので応答しない
   343:   //    (7) MPUがスプリアス割り込みを通知する
   344:   //  ここではデバイスが見つからないとき割り込み要求を取り下げるのでスプリアス割り込みは発生しない
   345:   public static int mfpAcknowledge () {
   346:     for (int i = 15; i >= 0; i--) {
   347:       if ((mfpImr & 1 << i) != 0) {
   348:         int request = mfpInnerRequest[i];
   349:         if (mfpInnerAcknowledged[i] != request) {
   350:           mfpInnerAcknowledged[i] = request;
   351:           mfpInnerInService[mfpInnerLevel = i] = true;
   352:           return mfpVectorHigh + i;
   353:         }
   354:       }
   355:     }
   356:     return 0;
   357:   }  //mfpAcknowledge()
   358: 
   359:   //割り込み終了
   360:   //  コアが割り込み処理を終了したときに呼び出す
   361:   //  まだ処理されていない割り込みが残っていたら再度割り込み要求を出す
   362:   public static void mfpDone () {
   363:     mfpInnerInService[mfpInnerLevel] = false;
   364:     for (int i = 15; i >= 0; i--) {
   365:       if ((mfpImr & 1 << i) != 0 && mfpInnerAcknowledged[i] != mfpInnerRequest[i]) {
   366:         if (MFP_DELAYED_INTERRUPT) {
   367:           XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   368:         } else {
   369:           XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   370:         }
   371:         return;
   372:       }
   373:     }
   374:   }  //mfpDone()
   375: 
   376:   //mfpKeyboardInput (scanCode)
   377:   //  キー入力
   378:   //  コアのスレッドで呼び出すこと
   379:   public static void mfpKeyboardInput (int scanCode) {
   380:     if (!mfpTbKeyboardOn) {
   381:       return;
   382:     }
   383:     scanCode &= 0xff;
   384:     if (mfpUdrQueueWrite + 1 != mfpUdrQueueRead) {  //キューは満杯ではない
   385:       mfpUdrQueueWrite = mfpUdrQueueWrite + 1;
   386:       mfpUdrQueueArray[mfpUdrQueueWrite & MFP_UDR_QUEUE_MASK] = scanCode;
   387:       if ((mfpIer & MFP_INPUT_FULL_MASK) != 0) {
   388:         mfpInnerRequest[MFP_INPUT_FULL_LEVEL]++;
   389:         if ((mfpImr & MFP_INPUT_FULL_MASK) != 0) {
   390:           if (MFP_DELAYED_INTERRUPT) {
   391:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   392:           } else {
   393:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   394:           }
   395:         }
   396:       }
   397:     }
   398:   }  //mfpKeyboardInput
   399: 
   400: 
   401:   //Timer-A
   402:   public static final TickerQueue.Ticker mfpTaTicker = new TickerQueue.Ticker () {
   403:     @Override protected void tick () {
   404:       if ((mfpIer & MFP_TIMER_A_MASK) != 0) {
   405:         mfpInnerRequest[MFP_TIMER_A_LEVEL]++;
   406:         if ((mfpImr & MFP_TIMER_A_MASK) != 0) {
   407:           if (MFP_DELAYED_INTERRUPT) {
   408:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   409:           } else {
   410:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   411:           }
   412:         }
   413:       }
   414:       mfpTaClock += mfpTaDelta * mfpTaInitial;
   415:       TickerQueue.tkqAdd (mfpTaTicker, mfpTaClock);
   416:     }
   417:   };
   418: 
   419:   //Timer-B
   420:   public static final TickerQueue.Ticker mfpTbTicker = new TickerQueue.Ticker () {
   421:     @Override protected void tick () {
   422:       if ((mfpIer & MFP_TIMER_B_MASK) != 0) {
   423:         mfpInnerRequest[MFP_TIMER_B_LEVEL]++;
   424:         if ((mfpImr & MFP_TIMER_B_MASK) != 0) {
   425:           if (MFP_DELAYED_INTERRUPT) {
   426:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   427:           } else {
   428:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   429:           }
   430:         }
   431:       }
   432:       mfpTbClock += mfpTbDelta * mfpTbInitial;
   433:       TickerQueue.tkqAdd (mfpTbTicker, mfpTbClock);
   434:     }
   435:   };
   436: 
   437:   //Timer-C
   438:   public static final TickerQueue.Ticker mfpTcTicker = new TickerQueue.Ticker () {
   439:     @Override protected void tick () {
   440:       if ((mfpIer & MFP_TIMER_C_MASK) != 0) {
   441:         mfpInnerRequest[MFP_TIMER_C_LEVEL]++;
   442:         if ((mfpImr & MFP_TIMER_C_MASK) != 0) {
   443:           if (MFP_DELAYED_INTERRUPT) {
   444:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   445:           } else {
   446:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   447:           }
   448:         }
   449:       }
   450:       mfpTcClock += mfpTcDelta * mfpTcInitial;
   451:       TickerQueue.tkqAdd (mfpTcTicker, mfpTcClock);
   452:     }
   453:   };
   454: 
   455:   //Timer-D
   456:   public static final TickerQueue.Ticker mfpTdTicker = new TickerQueue.Ticker () {
   457:     @Override protected void tick () {
   458:       if ((mfpIer & MFP_TIMER_D_MASK) != 0) {
   459:         mfpInnerRequest[MFP_TIMER_D_LEVEL]++;
   460:         if ((mfpImr & MFP_TIMER_D_MASK) != 0) {
   461:           if (MFP_DELAYED_INTERRUPT) {
   462:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   463:           } else {
   464:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   465:           }
   466:         }
   467:       }
   468:       mfpTdClock += mfpTdDelta * mfpTdInitial;
   469:       TickerQueue.tkqAdd (mfpTdTicker, mfpTdClock);
   470:     }
   471:   };
   472: 
   473:   //キーボード
   474:   public static final TickerQueue.Ticker mfpTkTicker = new TickerQueue.Ticker () {
   475:     @Override protected void tick () {
   476:       if (MFP_KBD_ON) {
   477:         //  XEiJ.mpuClockTimeだけで割り込みのタイミングを決めると、
   478:         //  コアのタスクが詰まっているときキー入力割り込みも詰まってリピートの開始と間隔が短くなってしまう
   479:         long time = System.currentTimeMillis () - 10L;  //10msまでは早すぎてもよいことにする
   480:         if (time < mfpTkTime) {  //早すぎる
   481:           mfpTkClock = XEiJ.mpuClockTime + XEiJ.TMR_FREQ / 1000 * (mfpTkTime - time);
   482:           TickerQueue.tkqAdd (mfpTkTicker, mfpTkClock);
   483:         } else {
   484:           if (mfpTbKeyboardOn) {
   485:             if (mfpKbdReadPointer != mfpKbdWritePointer) {  //バッファが空でないとき
   486:               if ((mfpIer & MFP_INPUT_FULL_MASK) != 0) {
   487:                 mfpInnerRequest[MFP_INPUT_FULL_LEVEL]++;
   488:                 if ((mfpImr & MFP_INPUT_FULL_MASK) != 0) {
   489:                   //MFPのキー入力割り込みを要求する
   490:                   if (MFP_DELAYED_INTERRUPT) {
   491:                     XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   492:                   } else {
   493:                     XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   494:                   }
   495:                 }
   496:               }
   497:             }
   498:           }
   499:           mfpTkClock = XEiJ.FAR_FUTURE;
   500:           TickerQueue.tkqRemove (mfpTkTicker);
   501:           //mfpTkTime = 0L;
   502:         }
   503:       }
   504:     }  //tick()
   505:   };
   506: 
   507: 
   508:   //GPIP入力
   509:   //  デバイスが呼び出す
   510:   //GPIP0
   511:   public static void mfpAlarmRise () {
   512:     if (mfpGpipAlarm == 0) {  //0→1
   513:       mfpGpipAlarm = MFP_GPIP_ALARM_MASK;
   514:       if ((mfpAer & MFP_GPIP_ALARM_MASK) != 0 && (mfpIer & MFP_ALARM_MASK) != 0) {
   515:         mfpInnerRequest[MFP_ALARM_LEVEL]++;
   516:         if ((mfpImr & MFP_ALARM_MASK) != 0) {
   517:           if (MFP_DELAYED_INTERRUPT) {
   518:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   519:           } else {
   520:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   521:           }
   522:         }
   523:       }
   524:     }
   525:   }  //mfpAlarmRise()
   526:   public static void mfpAlarmFall () {
   527:     if (mfpGpipAlarm != 0) {  //1→0
   528:       mfpGpipAlarm = 0;
   529:       if ((mfpAer & MFP_GPIP_ALARM_MASK) == 0 && (mfpIer & MFP_ALARM_MASK) != 0) {
   530:         mfpInnerRequest[MFP_ALARM_LEVEL]++;
   531:         if ((mfpImr & MFP_ALARM_MASK) != 0) {
   532:           if (MFP_DELAYED_INTERRUPT) {
   533:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   534:           } else {
   535:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   536:           }
   537:         }
   538:       }
   539:     }
   540:   }  //mfpAlarmFall()
   541: 
   542:   //GPIP1
   543:   public static void mfpExpwonRise () {
   544:     if (mfpGpipExpwon == 0) {  //0→1
   545:       mfpGpipExpwon = MFP_GPIP_EXPWON_MASK;
   546:       if ((mfpAer & MFP_GPIP_EXPWON_MASK) != 0 && (mfpIer & MFP_EXPWON_MASK) != 0) {
   547:         mfpInnerRequest[MFP_EXPWON_LEVEL]++;
   548:         if ((mfpImr & MFP_EXPWON_MASK) != 0) {
   549:           if (MFP_DELAYED_INTERRUPT) {
   550:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   551:           } else {
   552:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   553:           }
   554:         }
   555:       }
   556:     }
   557:   }  //mfpExpwonRise()
   558:   public static void mfpExpwonFall () {
   559:     if (mfpGpipExpwon != 0) {  //1→0
   560:       mfpGpipExpwon = 0;
   561:       if ((mfpAer & MFP_GPIP_EXPWON_MASK) == 0 && (mfpIer & MFP_EXPWON_MASK) != 0) {
   562:         mfpInnerRequest[MFP_EXPWON_LEVEL]++;
   563:         if ((mfpImr & MFP_EXPWON_MASK) != 0) {
   564:           if (MFP_DELAYED_INTERRUPT) {
   565:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   566:           } else {
   567:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   568:           }
   569:         }
   570:       }
   571:     }
   572:   }  //mfpExpwonFall()
   573: 
   574:   //GPIP2
   575:   public static void mfpPowerRise () {
   576:     if (mfpGpipPower == 0) {  //0→1
   577:       mfpGpipPower = MFP_GPIP_POWER_MASK;
   578:       if ((mfpAer & MFP_GPIP_POWER_MASK) != 0 && (mfpIer & MFP_POWER_MASK) != 0) {
   579:         mfpInnerRequest[MFP_POWER_LEVEL]++;
   580:         if ((mfpImr & MFP_POWER_MASK) != 0) {
   581:           if (MFP_DELAYED_INTERRUPT) {
   582:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   583:           } else {
   584:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   585:           }
   586:         }
   587:       }
   588:     }
   589:   }  //mfpPowerRise()
   590:   public static void mfpPowerFall () {
   591:     if (mfpGpipPower != 0) {  //1→0
   592:       mfpGpipPower = 0;
   593:       if ((mfpAer & MFP_GPIP_POWER_MASK) == 0 && (mfpIer & MFP_POWER_MASK) != 0) {
   594:         mfpInnerRequest[MFP_POWER_LEVEL]++;
   595:         if ((mfpImr & MFP_POWER_MASK) != 0) {
   596:           if (MFP_DELAYED_INTERRUPT) {
   597:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   598:           } else {
   599:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   600:           }
   601:         }
   602:       }
   603:     }
   604:   }  //mfpPowerFall()
   605: 
   606:   //GPIP3
   607:   public static void mfpOpmirqRise () {
   608:     if (mfpGpipOpmirq == 0) {  //0→1
   609:       mfpGpipOpmirq = MFP_GPIP_OPMIRQ_MASK;
   610:       if ((mfpAer & MFP_GPIP_OPMIRQ_MASK) != 0 && (mfpIer & MFP_OPMIRQ_MASK) != 0) {
   611:         mfpInnerRequest[MFP_OPMIRQ_LEVEL]++;
   612:         if ((mfpImr & MFP_OPMIRQ_MASK) != 0) {
   613:           if (MFP_DELAYED_INTERRUPT) {
   614:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   615:           } else {
   616:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   617:           }
   618:         }
   619:       }
   620:     }
   621:   }  //mfpOpmirqRise()
   622:   public static void mfpOpmirqFall () {
   623:     if (mfpGpipOpmirq != 0) {  //1→0
   624:       mfpGpipOpmirq = 0;
   625:       if ((mfpAer & MFP_GPIP_OPMIRQ_MASK) == 0 && (mfpIer & MFP_OPMIRQ_MASK) != 0) {
   626:         mfpInnerRequest[MFP_OPMIRQ_LEVEL]++;
   627:         if ((mfpImr & MFP_OPMIRQ_MASK) != 0) {
   628:           if (MFP_DELAYED_INTERRUPT) {
   629:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   630:           } else {
   631:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   632:           }
   633:         }
   634:       }
   635:     }
   636:   }  //mfpOpmirqFall()
   637: 
   638:   //GPIP4
   639:   public static void mfpVdispRise () {
   640:     //if (mfpGpipVdisp == 0) {  //0→1
   641:     mfpGpipVdisp = MFP_GPIP_VDISP_MASK;
   642:     if ((mfpAer & MFP_GPIP_VDISP_MASK) != 0) {
   643:       if ((mfpIer & MFP_VDISP_MASK) != 0) {
   644:         mfpInnerRequest[MFP_VDISP_LEVEL]++;
   645:         if ((mfpImr & MFP_VDISP_MASK) != 0) {
   646:           if (MFP_DELAYED_INTERRUPT) {
   647:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   648:           } else {
   649:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   650:           }
   651:         }
   652:       }
   653:       if (mfpTaEventcount && --mfpTaCurrent <= 0) {
   654:         mfpTaCurrent = mfpTaInitial;
   655:         if ((mfpIer & MFP_TIMER_A_MASK) != 0) {
   656:           mfpInnerRequest[MFP_TIMER_A_LEVEL]++;
   657:           if ((mfpImr & MFP_TIMER_A_MASK) != 0) {
   658:             if (MFP_DELAYED_INTERRUPT) {
   659:               XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   660:             } else {
   661:               XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   662:             }
   663:           }
   664:         }
   665:       }
   666:     }
   667:     //}
   668:   }  //mfpVdispRise()
   669:   public static void mfpVdispFall () {
   670:     //if (mfpGpipVdisp != 0) {  //1→0
   671:     mfpGpipVdisp = 0;
   672:     if ((mfpAer & MFP_GPIP_VDISP_MASK) == 0) {
   673:       if ((mfpIer & MFP_VDISP_MASK) != 0) {
   674:         mfpInnerRequest[MFP_VDISP_LEVEL]++;
   675:         if ((mfpImr & MFP_VDISP_MASK) != 0) {
   676:           if (MFP_DELAYED_INTERRUPT) {
   677:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   678:           } else {
   679:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   680:           }
   681:         }
   682:       }
   683:       if (mfpTaEventcount && --mfpTaCurrent <= 0) {
   684:         mfpTaCurrent = mfpTaInitial;
   685:         if ((mfpIer & MFP_TIMER_A_MASK) != 0) {
   686:           mfpInnerRequest[MFP_TIMER_A_LEVEL]++;
   687:           if ((mfpImr & MFP_TIMER_A_MASK) != 0) {
   688:             if (MFP_DELAYED_INTERRUPT) {
   689:               XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   690:             } else {
   691:               XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   692:             }
   693:           }
   694:         }
   695:       }
   696:     }
   697:     //}
   698:   }  //mfpVdispFall()
   699: 
   700:   //GPIP6
   701:   public static void mfpRintRise () {
   702:     //if (mfpGpipRint == 0) {  //0→1
   703:     mfpGpipRint = MFP_GPIP_RINT_MASK;
   704:     if ((mfpAer & MFP_GPIP_RINT_MASK) != 0 && (mfpIer & MFP_RINT_MASK) != 0) {
   705:       mfpInnerRequest[MFP_RINT_LEVEL]++;
   706:       if ((mfpImr & MFP_RINT_MASK) != 0) {
   707:         if (MFP_DELAYED_INTERRUPT) {
   708:           XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   709:         } else {
   710:           XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   711:         }
   712:       }
   713:     }
   714:     //}
   715:   }  //mfpRintRise()
   716:   public static void mfpRintFall () {
   717:     //if (mfpGpipRint != 0) {  //1→0
   718:     mfpGpipRint = 0;
   719:     if ((mfpAer & MFP_GPIP_RINT_MASK) == 0 && (mfpIer & MFP_RINT_MASK) != 0) {
   720:       mfpInnerRequest[MFP_RINT_LEVEL]++;
   721:       if ((mfpImr & MFP_RINT_MASK) != 0) {
   722:         if (MFP_DELAYED_INTERRUPT) {
   723:           XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   724:         } else {
   725:           XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   726:         }
   727:       }
   728:     }
   729:     //}
   730:   }  //mfpRintFall()
   731: 
   732:   //GPIP7
   733:   public static void mfpHsyncRise () {
   734:     //if (mfpGpipHsync == 0) {  //0→1
   735:     mfpGpipHsync = MFP_GPIP_HSYNC_MASK;
   736:     if ((mfpAer & MFP_GPIP_HSYNC_MASK) != 0 && (mfpIer & MFP_HSYNC_MASK) != 0) {
   737:       mfpInnerRequest[MFP_HSYNC_LEVEL]++;
   738:       if ((mfpImr & MFP_HSYNC_MASK) != 0) {
   739:         if (MFP_DELAYED_INTERRUPT) {
   740:           XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   741:         } else {
   742:           XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   743:         }
   744:       }
   745:     }
   746:     //}
   747:   }  //mfpHsyncRise()
   748:   public static void mfpHsyncFall () {
   749:     //if (mfpGpipHsync != 0) {  //1→0
   750:     mfpGpipHsync = 0;
   751:     if ((mfpAer & MFP_GPIP_HSYNC_MASK) == 0 && (mfpIer & MFP_HSYNC_MASK) != 0) {
   752:       mfpInnerRequest[MFP_HSYNC_LEVEL]++;
   753:       if ((mfpImr & MFP_HSYNC_MASK) != 0) {
   754:         if (MFP_DELAYED_INTERRUPT) {
   755:           XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   756:         } else {
   757:           XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   758:         }
   759:       }
   760:     }
   761:     //}
   762:   }  //mfpHsyncFall()
   763: 
   764:   //キー入力のリピートの処理をMFPで行う
   765:   //  キー入力バッファ
   766:   //    キー入力データが並んでいるリングバッファ
   767:   //    読み出しポインタ
   768:   //      次に読み出す位置
   769:   //      MFPが更新する
   770:   //    書き込みポインタ
   771:   //      次に書き込む位置
   772:   //      KBDが更新する
   773:   //    読み出しポインタと書き込みポインタが一致しているときバッファは空
   774:   //    読み出しポインタを進めると書き込みポインタと一致するとき読み出しポインタはバッファの末尾
   775:   //    書き込みポインタを進めると読み出しポインタと一致するときはバッファが一杯(なので書き込めない)
   776:   //  キー入力データ
   777:   //    0x0000xxxx  リピートしないデータ。リピートしないキーが押されたかキーが離されたときのデータ
   778:   //    0x0001xxxx  リピート開始前のデータ。リピートするキーが押されてまだ読み出されていないデータ
   779:   //    0xffffxxxx  リピート開始後のデータ。リピートするキーが押されて1回以上読み出されたデータ
   780:   //    0x00+キーコード  キーが押されたデータ
   781:   //    0x80+キーコード  キーが離されたデータ
   782:   //  最後に読み出したデータ
   783:   //    キー入力バッファから最後に読み出したデータ
   784:   //    キー入力バッファが空のときUDRから読み出される
   785:   //  キーが押されたまたは離されたとき
   786:   //    バッファが一杯でないとき
   787:   //      キーが押されたとき
   788:   //        書き込みポインタの位置にリピート開始前のデータまたはリピートしないデータを書き込む
   789:   //      キーが離されたとき
   790:   //        書き込みポインタの位置にリピートしないデータを書き込む
   791:   //      書き込みポインタを進める
   792:   //    MFPのキー入力割り込みを要求する
   793:   //  UDR読み出し
   794:   //    バッファが空でないとき
   795:   //      バッファの末尾でなくて先頭がリピート開始後のデータのとき
   796:   //        読み出しポインタを進める
   797:   //      バッファの先頭のデータを最後に読み出したデータとして保存する
   798:   //      バッファの末尾でないとき
   799:   //        読み出しポインタを進める
   800:   //        MFPのキー入力割り込みを要求する
   801:   //      バッファの末尾でリピートしないデータのとき
   802:   //        読み出しポインタを進める
   803:   //      バッファの末尾でリピート開始前のデータのとき
   804:   //        バッファの末尾のデータをリピート開始後に変更する
   805:   //        現在時刻+リピート開始時間でMFPのTimer-Kをセットする
   806:   //      バッファの末尾でリピート開始後のデータのとき
   807:   //        現在時刻+リピート間隔時間でMFPのTimer-Kをセットする
   808:   //    最後に読み出したデータを返す
   809:   //  MFPのTimer-K
   810:   //    キー入力のリピート処理のためにMFPに追加されたタイマー
   811:   //    バッファが空でないとき
   812:   //      MFPのキー入力割り込みを要求する
   813:   //  UDR読み出しとMFPのTimer-Kはどちらもコアから呼ばれるので同時に呼び出されることはない
   814:   //  キー入力割り込みがIERAで禁止されているとタイマーで割り込みがかからないのでリピートが止まってしまうが、
   815:   //  キー入力割り込みを止めたいときはIMRAでマスクするのが原則なので通常は問題ないはず
   816:   public static final boolean MFP_KBD_ON = false;  //true=キー入力のリピートの処理をMFPで行う
   817:   public static final int MFP_KBD_SIZE = 256;  //キー入力バッファのサイズ。2の累乗にすること
   818:   public static final int MFP_KBD_MASK = MFP_KBD_SIZE - 1;
   819:   public static final int[] mfpKbdBuffer = new int[MFP_KBD_SIZE];  //キー入力バッファ
   820:   public static volatile int mfpKbdReadPointer;  //読み出しポインタ。マスクしない
   821:   public static volatile int mfpKbdWritePointer;  //書き込みポインタ。マスクしない
   822:   public static int mfpKbdLastData;  //最後に読み出したデータ
   823:   public static long mfpTkClock;  //Timer-Kの次の呼び出し時刻
   824:   public static long mfpTkTime;  //次にTimer-Kが呼び出されるべき時刻(ms)。mfpTkClockがXEiJ.FAR_FUTUREでないときだけ有効
   825: 
   826:   //mfpKbdInput (data, repeat)
   827:   //  キーが押されたまたは離されたとき
   828:   //  data    0x00+キーコード  キーが押されたデータ
   829:   //          0x80+キーコード  キーが離されたデータ
   830:   //  repeat  false  リピートしない
   831:   //          true   リピートする
   832:   public static void mfpKbdInput (int data, boolean repeat) {
   833:     if (!mfpTbKeyboardOn) {
   834:       return;
   835:     }
   836:     int w = mfpKbdWritePointer;
   837:     if (w + 1 != mfpKbdReadPointer) {  //バッファが一杯でないとき
   838:       mfpKbdBuffer[w & MFP_KBD_MASK] = (repeat ? 0x00010000 : 0x00000000) | data;  //書き込みポインタの位置にデータを書き込む
   839:       mfpKbdWritePointer = w + 1;  //書き込みポインタを進める
   840:       if ((mfpIer & MFP_INPUT_FULL_MASK) != 0) {
   841:         mfpInnerRequest[MFP_INPUT_FULL_LEVEL]++;
   842:         if ((mfpImr & MFP_INPUT_FULL_MASK) != 0) {
   843:           //MFPのキー入力割り込みを要求する
   844:           if (MFP_DELAYED_INTERRUPT) {
   845:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   846:           } else {
   847:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   848:           }
   849:         }
   850:       }
   851:     }
   852:   }  //mfpKbdInput(int,boolean)
   853: 
   854:   //data = mfpKbdReadData ()
   855:   //  UDR読み出し
   856:   public static int mfpKbdReadData () {
   857:     int r = mfpKbdReadPointer;
   858:     int w = mfpKbdWritePointer;
   859:     if (r != w) {  //バッファが空でないとき
   860:       int s = mfpKbdBuffer[r & MFP_KBD_MASK];  //バッファの先頭のデータ
   861:       if (r + 1 != w && s < 0) {  //バッファの末尾でなくて先頭がリピート開始後のデータのとき
   862:         mfpKbdReadPointer = r = r + 1;  //読み出しポインタを進める
   863:         s = mfpKbdBuffer[r & MFP_KBD_MASK];  //バッファの先頭のデータ
   864:       }
   865:       mfpKbdLastData = (char) s;  //バッファの先頭のデータを最後に読み出したデータとして保存する
   866:       if (r + 1 != w) {  //バッファの末尾でないとき
   867:         mfpKbdReadPointer = r + 1;  //読み出しポインタを進める
   868:         if ((mfpIer & MFP_INPUT_FULL_MASK) != 0) {
   869:           mfpInnerRequest[MFP_INPUT_FULL_LEVEL]++;
   870:           if ((mfpImr & MFP_INPUT_FULL_MASK) != 0) {
   871:             //MFPのキー入力割り込みを要求する
   872:             if (MFP_DELAYED_INTERRUPT) {
   873:               XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   874:             } else {
   875:               XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   876:             }
   877:           }
   878:         }
   879:       } else if ((s >> 16) == 0x0000) {  //バッファの末尾でリピートしないデータのとき
   880:         mfpKbdReadPointer = r + 1;  //読み出しポインタを進める
   881:       } else if ((s >> 16) == 0x0001) {  //バッファの末尾でリピート開始前のデータのとき
   882:         mfpKbdBuffer[r & MFP_KBD_MASK] = 0xffff0000 | s;  //バッファの末尾のデータをリピート開始後に変更する
   883:         if (mfpTkTicker.time == Long.MAX_VALUE &&  //Timer-Kが予約されておらず
   884:             (mfpIer & MFP_INPUT_FULL_MASK) != 0) {  //キー入力割り込みが許可されているとき
   885:           mfpTkClock = XEiJ.mpuClockTime + XEiJ.TMR_FREQ / 1000 * Keyboard.kbdRepeatDelay;  //現在時刻+リピート開始時間でMFPのTimer-Kをセットする
   886:           TickerQueue.tkqAdd (mfpTkTicker, mfpTkClock);
   887:           mfpTkTime = System.currentTimeMillis () + Keyboard.kbdRepeatDelay;  //次にTimer-Kが呼び出されるべき時刻(ms)
   888:         }
   889:       } else {  //バッファの末尾でリピート開始後のデータのとき
   890:         if (mfpTkTicker.time == Long.MAX_VALUE &&  //Timer-Kが予約されておらず
   891:             (mfpIer & MFP_INPUT_FULL_MASK) != 0) {  //キー入力割り込みが許可されているとき
   892:           mfpTkClock = XEiJ.mpuClockTime + XEiJ.TMR_FREQ / 1000 * Keyboard.kbdRepeatInterval;  //現在時刻+リピート間隔時間でMFPのTimer-Kをセットする
   893:           TickerQueue.tkqAdd (mfpTkTicker, mfpTkClock);
   894:           mfpTkTime = System.currentTimeMillis () + Keyboard.kbdRepeatInterval;  //次にTimer-Kが呼び出されるべき時刻(ms)
   895:         }
   896:       }
   897:     }
   898:     return mfpKbdLastData;  //最後に読み出したデータを返す
   899:   }  //mfpKbdReadData()
   900: 
   901: 
   902: 
   903:   //ピーク
   904:   public static int mfpPeekByte (int a) {
   905:     try {
   906:       return (a & (XEiJ.BUS_MOTHER_MASK & 0xffff803f)) == MFP_UDR ? mfpUdrQueueArray[mfpUdrQueueRead & MFP_UDR_QUEUE_MASK] : mfpReadByte (a);
   907:     } catch (M68kException e) {
   908:     }
   909:     return 0;
   910:   }
   911: 
   912:   //リード
   913:   public static int mfpReadByte (int a) throws M68kException {
   914:     XEiJ.mpuClockTime += XEiJ.busWaitTime.mfp;
   915:     switch (a & (XEiJ.BUS_MOTHER_MASK & 0xffff803f)) {  //$00E88040~$00E89FFF→$00E88000~$00E8803F
   916:     case MFP_GPIP_DATA:
   917:       return mfpGpipHsync | mfpGpipRint | 0b00100000 | mfpGpipVdisp | mfpGpipOpmirq | mfpGpipPower | mfpGpipExpwon | mfpGpipAlarm;  //GPIP5は常に1
   918:     case MFP_AER:
   919:       return mfpAer;
   920:     case MFP_DDR:
   921:       return 0x00;
   922:     case MFP_IERA:
   923:       return mfpIer >>> 8;
   924:     case MFP_IERB:
   925:       return mfpIer & 0xff;
   926:     case MFP_IPRA:
   927:       return ((mfpInnerRequest[15] != mfpInnerAcknowledged[15] ? 0b10000000 : 0) |
   928:               (mfpInnerRequest[14] != mfpInnerAcknowledged[14] ? 0b01000000 : 0) |
   929:               (mfpInnerRequest[13] != mfpInnerAcknowledged[13] ? 0b00100000 : 0) |
   930:               (mfpInnerRequest[12] != mfpInnerAcknowledged[12] ? 0b00010000 : 0) |
   931:               (mfpInnerRequest[11] != mfpInnerAcknowledged[11] ? 0b00001000 : 0) |
   932:               (mfpInnerRequest[10] != mfpInnerAcknowledged[10] ? 0b00000100 : 0) |
   933:               (mfpInnerRequest[ 9] != mfpInnerAcknowledged[ 9] ? 0b00000010 : 0) |
   934:               (mfpInnerRequest[ 8] != mfpInnerAcknowledged[ 8] ? 0b00000001 : 0));
   935:     case MFP_IPRB:
   936:       return ((mfpInnerRequest[ 7] != mfpInnerAcknowledged[ 7] ? 0b10000000 : 0) |
   937:               (mfpInnerRequest[ 6] != mfpInnerAcknowledged[ 6] ? 0b01000000 : 0) |
   938:               (mfpInnerRequest[ 5] != mfpInnerAcknowledged[ 5] ? 0b00100000 : 0) |
   939:               (mfpInnerRequest[ 4] != mfpInnerAcknowledged[ 4] ? 0b00010000 : 0) |
   940:               (mfpInnerRequest[ 3] != mfpInnerAcknowledged[ 3] ? 0b00001000 : 0) |
   941:               (mfpInnerRequest[ 2] != mfpInnerAcknowledged[ 2] ? 0b00000100 : 0) |
   942:               (mfpInnerRequest[ 1] != mfpInnerAcknowledged[ 1] ? 0b00000010 : 0) |
   943:               (mfpInnerRequest[ 0] != mfpInnerAcknowledged[ 0] ? 0b00000001 : 0));
   944:     case MFP_ISRA:
   945:       return ((mfpInnerInService[15] ? 0b10000000 : 0) |
   946:               (mfpInnerInService[14] ? 0b01000000 : 0) |
   947:               (mfpInnerInService[13] ? 0b00100000 : 0) |
   948:               (mfpInnerInService[12] ? 0b00010000 : 0) |
   949:               (mfpInnerInService[11] ? 0b00001000 : 0) |
   950:               (mfpInnerInService[10] ? 0b00000100 : 0) |
   951:               (mfpInnerInService[ 9] ? 0b00000010 : 0) |
   952:               (mfpInnerInService[ 8] ? 0b00000001 : 0));
   953:     case MFP_ISRB:
   954:       return ((mfpInnerInService[ 7] ? 0b10000000 : 0) |
   955:               (mfpInnerInService[ 6] ? 0b01000000 : 0) |
   956:               (mfpInnerInService[ 5] ? 0b00100000 : 0) |
   957:               (mfpInnerInService[ 4] ? 0b00010000 : 0) |
   958:               (mfpInnerInService[ 3] ? 0b00001000 : 0) |
   959:               (mfpInnerInService[ 2] ? 0b00000100 : 0) |
   960:               (mfpInnerInService[ 1] ? 0b00000010 : 0) |
   961:               (mfpInnerInService[ 0] ? 0b00000001 : 0));
   962:     case MFP_IMRA:
   963:       return mfpImr >>> 8;
   964:     case MFP_IMRB:
   965:       return mfpImr & 0xff;
   966:     case MFP_VECTOR:
   967:       return mfpVectorHigh;
   968:     case MFP_TACR:
   969:       return (mfpTaEventcount ? 0x08 : 0) | mfpTaPrescale;
   970:     case MFP_TBCR:
   971:       return (mfpTbEventcount ? 0x08 : 0) | mfpTbPrescale;
   972:     case MFP_TCDCR:
   973:       return mfpTcPrescale << 4 | mfpTdPrescale;
   974:     case MFP_TADR:
   975:       if (mfpTaEventcount || mfpTaPrescale == 0) {
   976:         return mfpTaCurrent & 0xff;
   977:       }
   978:       return mfpTaInitial - (int) (Math.floor ((double) (XEiJ.mpuClockTime - mfpTaStart) / mfpTaDelta) % mfpTaInitial) & 0xff;
   979:     case MFP_TBDR:
   980:       if (mfpTbEventcount || mfpTbPrescale == 0) {
   981:         return mfpTbCurrent & 0xff;
   982:       }
   983:       return mfpTbInitial - (int) (Math.floor ((double) (XEiJ.mpuClockTime - mfpTbStart) / mfpTbDelta) % mfpTbInitial) & 0xff;
   984:     case MFP_TCDR:
   985:       if (mfpTcPrescale == 0) {
   986:         return mfpTcCurrent & 0xff;
   987:       }
   988:       return mfpTcInitial - (int) (Math.floor ((double) (XEiJ.mpuClockTime - mfpTcStart) / mfpTcDelta) % mfpTcInitial) & 0xff;
   989:     case MFP_TDDR:
   990:       if (mfpTdPrescale == 0) {
   991:         return mfpTdCurrent & 0xff;
   992:       }
   993:       return mfpTdInitial - (int) (Math.floor ((double) (XEiJ.mpuClockTime - mfpTdStart) / mfpTdDelta) % mfpTdInitial) & 0xff;
   994:     case MFP_SYNC_CHAR:
   995:       return 0;
   996:     case MFP_UCR:
   997:       return mfpUCR;
   998:     case MFP_RSR:
   999:       if (MFP_KBD_ON) {
  1000:         return (mfpRSR |
  1001:                 (mfpKbdReadPointer == mfpKbdWritePointer ? 0 : 0x80));  //BF
  1002:       } else {
  1003:         return (mfpRSR |
  1004:                 (mfpUdrQueueRead == mfpUdrQueueWrite ? 0 : 0x80));  //BF
  1005:       }
  1006:     case MFP_TSR:
  1007:       return (mfpTSR |
  1008:               (XEiJ.mpuClockTime < mfpTSRBufferFullEnd ? 0 : 0x80));  //BE
  1009:     case MFP_UDR:
  1010:       if (MFP_KBD_ON) {
  1011:         return mfpKbdReadData ();
  1012:       } else {
  1013:         if (mfpUdrQueueRead != mfpUdrQueueWrite) {  //キューは空ではない
  1014:           mfpUdrQueueRead = mfpUdrQueueRead + 1;
  1015:           if (mfpUdrQueueRead != mfpUdrQueueWrite) {  //キューが空にならなかったので再度割り込み要求を出す
  1016:             if ((mfpIer & MFP_INPUT_FULL_MASK) != 0) {
  1017:               mfpInnerRequest[MFP_INPUT_FULL_LEVEL]++;
  1018:               if ((mfpImr & MFP_INPUT_FULL_MASK) != 0) {
  1019:                 if (MFP_DELAYED_INTERRUPT) {
  1020:                   XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
  1021:                 } else {
  1022:                   XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
  1023:                 }
  1024:               }
  1025:             }
  1026:           }
  1027:         }
  1028:         return mfpUdrQueueArray[mfpUdrQueueRead & MFP_UDR_QUEUE_MASK];  //最後に押されたまたは離されたキー
  1029:       }
  1030:     default:
  1031:       if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  1032:           !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  1033:         return MemoryMappedDevice.MMD_NUL.mmdRbz (a);  //バスエラー
  1034:       }
  1035:       return 0xff;
  1036:     }
  1037:   }
  1038: 
  1039:   //ライト
  1040:   public static void mfpWriteByte (int a, int d) throws M68kException {
  1041:     XEiJ.mpuClockTime += XEiJ.busWaitTime.mfp;
  1042:     switch (a & (XEiJ.BUS_MOTHER_MASK & 0xffff803f)) {  //$00E88040~$00E89FFF→$00E88000~$00E8803F
  1043:     case MFP_GPIP_DATA:
  1044:       return;
  1045:     case MFP_AER:
  1046:       mfpAer = d & 0xff;
  1047:       return;
  1048:     case MFP_DDR:
  1049:       return;
  1050:     case MFP_IERA:
  1051:       d = (char) (d << 8);
  1052:       int oldIera = mfpIer;
  1053:       mfpIer = d | (mfpIer & 0xff);
  1054:       //MFP_IERAのビットに0を書き込むとMFP_IPRAの該当ビットも0になる
  1055:       if ((short) d >= 0) {  //(0b10000000_00000000 & d) == 0
  1056:         mfpInnerAcknowledged[15] = mfpInnerRequest[15];
  1057:       }
  1058:       if (d << 31 - 14 >= 0) {  //(0b01000000_00000000 & d) == 0
  1059:         mfpInnerAcknowledged[14] = mfpInnerRequest[14];
  1060:       }
  1061:       if (d << 31 - 13 >= 0) {  //(0b00100000_00000000 & d) == 0
  1062:         mfpInnerAcknowledged[13] = mfpInnerRequest[13];
  1063:       }
  1064:       if (d << 31 - 12 >= 0) {  //(0b00010000_00000000 & d) == 0
  1065:         mfpInnerAcknowledged[12] = mfpInnerRequest[12];
  1066:       } else if (oldIera << 31 - 12 >= 0 &&  //MFP_INPUT_FULL_MASKが0→1
  1067:                  (MFP_KBD_ON ?
  1068:                   mfpKbdReadPointer != mfpKbdWritePointer :  //バッファが空でないとき
  1069:                   mfpUdrQueueRead != mfpUdrQueueWrite)) {  //キューが空でないとき
  1070:         mfpInnerRequest[MFP_INPUT_FULL_LEVEL]++;
  1071:         if ((mfpImr & MFP_INPUT_FULL_MASK) != 0) {
  1072:           //MFPのキー入力割り込みを要求する
  1073:           if (MFP_DELAYED_INTERRUPT) {
  1074:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
  1075:           } else {
  1076:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
  1077:           }
  1078:         }
  1079:       }
  1080:       if (d << 31 - 11 >= 0) {  //(0b00001000_00000000 & d) == 0
  1081:         mfpInnerAcknowledged[11] = mfpInnerRequest[11];
  1082:       }
  1083:       if (d << 31 - 10 >= 0) {  //(0b00000100_00000000 & d) == 0
  1084:         mfpInnerAcknowledged[10] = mfpInnerRequest[10];
  1085:       }
  1086:       if (d << 31 - 9 >= 0) {  //(0b00000010_00000000 & d) == 0
  1087:         mfpInnerAcknowledged[ 9] = mfpInnerRequest[ 9];
  1088:       }
  1089:       if (d << 31 - 8 >= 0) {  //(0b00000001_00000000 & d) == 0
  1090:         mfpInnerAcknowledged[ 8] = mfpInnerRequest[ 8];
  1091:       }
  1092:       return;
  1093:     case MFP_IERB:
  1094:       mfpIer = (mfpIer & ~0xff) | (d & 0xff);
  1095:       //MFP_IERBのビットに0を書き込むとMFP_IPRBの該当ビットも0になる
  1096:       if ((byte) d >= 0) {  //(0b10000000 & d) == 0
  1097:         mfpInnerAcknowledged[ 7] = mfpInnerRequest[ 7];
  1098:       }
  1099:       if (d << 31 - 6 >= 0) {  //(0b01000000 & d) == 0
  1100:         mfpInnerAcknowledged[ 6] = mfpInnerRequest[ 6];
  1101:       }
  1102:       if (d << 31 - 5 >= 0) {  //(0b00100000 & d) == 0
  1103:         mfpInnerAcknowledged[ 5] = mfpInnerRequest[ 5];
  1104:       }
  1105:       if (d << 31 - 4 >= 0) {  //(0b00010000 & d) == 0
  1106:         mfpInnerAcknowledged[ 4] = mfpInnerRequest[ 4];
  1107:       }
  1108:       if (XEiJ.TEST_BIT_3_SHIFT ? d << 31 - 3 >= 0 : (d & 8) == 0) {
  1109:         mfpInnerAcknowledged[ 3] = mfpInnerRequest[ 3];
  1110:       }
  1111:       if (XEiJ.TEST_BIT_2_SHIFT ? d << 31 - 2 >= 0 : (d & 4) == 0) {
  1112:         mfpInnerAcknowledged[ 2] = mfpInnerRequest[ 2];
  1113:       }
  1114:       if (XEiJ.TEST_BIT_1_SHIFT ? d << 31 - 1 >= 0 : (d & 2) == 0) {
  1115:         mfpInnerAcknowledged[ 1] = mfpInnerRequest[ 1];
  1116:       }
  1117:       if (XEiJ.TEST_BIT_0_SHIFT ? d << 31 - 0 >= 0 : (d & 1) == 0) {
  1118:         mfpInnerAcknowledged[ 0] = mfpInnerRequest[ 0];
  1119:       }
  1120:       return;
  1121:     case MFP_IPRA:
  1122:       //MFP_IPRAのビットは他のすべてのビットに1を書き込むことで直接クリアできる
  1123:       switch (d & 0xff) {
  1124:       case 0b01111111:
  1125:         mfpInnerAcknowledged[15] = mfpInnerRequest[15];
  1126:         break;
  1127:       case 0b10111111:
  1128:         mfpInnerAcknowledged[14] = mfpInnerRequest[14];
  1129:         break;
  1130:       case 0b11011111:
  1131:         mfpInnerAcknowledged[13] = mfpInnerRequest[13];
  1132:         break;
  1133:       case 0b11101111:
  1134:         mfpInnerAcknowledged[12] = mfpInnerRequest[12];
  1135:         break;
  1136:       case 0b11110111:
  1137:         mfpInnerAcknowledged[11] = mfpInnerRequest[11];
  1138:         break;
  1139:       case 0b11111011:
  1140:         mfpInnerAcknowledged[10] = mfpInnerRequest[10];
  1141:         break;
  1142:       case 0b11111101:
  1143:         mfpInnerAcknowledged[ 9] = mfpInnerRequest[ 9];
  1144:         break;
  1145:       case 0b11111110:
  1146:         mfpInnerAcknowledged[ 8] = mfpInnerRequest[ 8];
  1147:         break;
  1148:       }
  1149:       return;
  1150:     case MFP_IPRB:
  1151:       //MFP_IPRBのビットは他のすべてのビットに1を書き込むことで直接クリアできる
  1152:       switch (d & 0xff) {
  1153:       case 0b01111111:
  1154:         mfpInnerAcknowledged[ 7] = mfpInnerRequest[ 7];
  1155:         break;
  1156:       case 0b10111111:
  1157:         mfpInnerAcknowledged[ 6] = mfpInnerRequest[ 6];
  1158:         break;
  1159:       case 0b11011111:
  1160:         mfpInnerAcknowledged[ 5] = mfpInnerRequest[ 5];
  1161:         break;
  1162:       case 0b11101111:
  1163:         mfpInnerAcknowledged[ 4] = mfpInnerRequest[ 4];
  1164:         break;
  1165:       case 0b11110111:
  1166:         mfpInnerAcknowledged[ 3] = mfpInnerRequest[ 3];
  1167:         break;
  1168:       case 0b11111011:
  1169:         mfpInnerAcknowledged[ 2] = mfpInnerRequest[ 2];
  1170:         break;
  1171:       case 0b11111101:
  1172:         mfpInnerAcknowledged[ 1] = mfpInnerRequest[ 1];
  1173:         break;
  1174:       case 0b11111110:
  1175:         mfpInnerAcknowledged[ 0] = mfpInnerRequest[ 0];
  1176:         break;
  1177:       }
  1178:       return;
  1179:     case MFP_ISRA:
  1180:       //MFP_ISRAのビットは他のすべてのビットに1を書き込むことで直接クリアできる
  1181:       switch (d & 0xff) {
  1182:       case 0b01111111:
  1183:         mfpInnerInService[15] = false;
  1184:         break;
  1185:       case 0b10111111:
  1186:         mfpInnerInService[14] = false;
  1187:         break;
  1188:       case 0b11011111:
  1189:         mfpInnerInService[13] = false;
  1190:         break;
  1191:       case 0b11101111:
  1192:         mfpInnerInService[12] = false;
  1193:         break;
  1194:       case 0b11110111:
  1195:         mfpInnerInService[11] = false;
  1196:         break;
  1197:       case 0b11111011:
  1198:         mfpInnerInService[10] = false;
  1199:         break;
  1200:       case 0b11111101:
  1201:         mfpInnerInService[ 9] = false;
  1202:         break;
  1203:       case 0b11111110:
  1204:         mfpInnerInService[ 8] = false;
  1205:         break;
  1206:       }
  1207:       return;
  1208:     case MFP_ISRB:
  1209:       //MFP_ISRBのビットは他のすべてのビットに1を書き込むことで直接クリアできる
  1210:       switch (d & 0xff) {
  1211:       case 0b01111111:
  1212:         mfpInnerInService[ 7] = false;
  1213:         break;
  1214:       case 0b10111111:
  1215:         mfpInnerInService[ 6] = false;
  1216:         break;
  1217:       case 0b11011111:
  1218:         mfpInnerInService[ 5] = false;
  1219:         break;
  1220:       case 0b11101111:
  1221:         mfpInnerInService[ 4] = false;
  1222:         break;
  1223:       case 0b11110111:
  1224:         mfpInnerInService[ 3] = false;
  1225:         break;
  1226:       case 0b11111011:
  1227:         mfpInnerInService[ 2] = false;
  1228:         break;
  1229:       case 0b11111101:
  1230:         mfpInnerInService[ 1] = false;
  1231:         break;
  1232:       case 0b11111110:
  1233:         mfpInnerInService[ 0] = false;
  1234:         break;
  1235:       }
  1236:       return;
  1237:     case MFP_IMRA:
  1238:       mfpImr = (d & 0xff) << 8 | (mfpImr & 0xff);
  1239:       //MFP_IMRAのビットに1を書き込んだときMFP_IPRAの該当ビットが1ならば割り込み発生
  1240:       if ((byte) d < 0 && mfpInnerRequest[15] != mfpInnerAcknowledged[15] ||  //(0b10000000 & d) != 0
  1241:           d << 31 - 6 < 0 && mfpInnerRequest[14] != mfpInnerAcknowledged[14] ||  //(0b01000000 & d) != 0
  1242:           d << 31 - 5 < 0 && mfpInnerRequest[13] != mfpInnerAcknowledged[13] ||  //(0b00100000 & d) != 0
  1243:           d << 31 - 4 < 0 && mfpInnerRequest[12] != mfpInnerAcknowledged[12] ||  //(0b00010000 & d) != 0
  1244:           (XEiJ.TEST_BIT_3_SHIFT ? d << 31 - 3 < 0 : (d & 8) != 0) && mfpInnerRequest[11] != mfpInnerAcknowledged[11] ||
  1245:           (XEiJ.TEST_BIT_2_SHIFT ? d << 31 - 2 < 0 : (d & 4) != 0) && mfpInnerRequest[10] != mfpInnerAcknowledged[10] ||
  1246:           (XEiJ.TEST_BIT_1_SHIFT ? d << 31 - 1 < 0 : (d & 2) != 0) && mfpInnerRequest[ 9] != mfpInnerAcknowledged[ 9] ||
  1247:           (XEiJ.TEST_BIT_0_SHIFT ? d << 31 - 0 < 0 : (d & 1) != 0) && mfpInnerRequest[ 8] != mfpInnerAcknowledged[ 8]) {
  1248:         if (MFP_DELAYED_INTERRUPT) {
  1249:           XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
  1250:         } else {
  1251:           XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
  1252:         }
  1253:       }
  1254:       return;
  1255:     case MFP_IMRB:
  1256:       mfpImr = (mfpImr & ~0xff) | (d & 0xff);
  1257:       //MFP_IMRBのビットに1を書き込んだときMFP_IPRBの該当ビットが1ならば割り込み発生
  1258:       if ((byte) d < 0 && mfpInnerRequest[ 7] != mfpInnerAcknowledged[ 7] ||  //(0b10000000 & d) != 0
  1259:           d << 31 - 6 < 0 && mfpInnerRequest[ 6] != mfpInnerAcknowledged[ 6] ||  //(0b01000000 & d) != 0
  1260:           d << 31 - 5 < 0 && mfpInnerRequest[ 5] != mfpInnerAcknowledged[ 5] ||  //(0b00100000 & d) != 0
  1261:           d << 31 - 4 < 0 && mfpInnerRequest[ 4] != mfpInnerAcknowledged[ 4] ||  //(0b00010000 & d) != 0
  1262:           (XEiJ.TEST_BIT_3_SHIFT ? d << 31 - 3 < 0 : (d & 8) != 0) && mfpInnerRequest[ 3] != mfpInnerAcknowledged[ 3] ||
  1263:           (XEiJ.TEST_BIT_2_SHIFT ? d << 31 - 2 < 0 : (d & 4) != 0) && mfpInnerRequest[ 2] != mfpInnerAcknowledged[ 2] ||
  1264:           (XEiJ.TEST_BIT_1_SHIFT ? d << 31 - 1 < 0 : (d & 2) != 0) && mfpInnerRequest[ 1] != mfpInnerAcknowledged[ 1] ||
  1265:           (XEiJ.TEST_BIT_0_SHIFT ? d << 31 - 0 < 0 : (d & 1) != 0) && mfpInnerRequest[ 0] != mfpInnerAcknowledged[ 0]) {
  1266:         if (MFP_DELAYED_INTERRUPT) {
  1267:           XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
  1268:         } else {
  1269:           XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
  1270:         }
  1271:       }
  1272:       return;
  1273:     case MFP_VECTOR:
  1274:       mfpVectorHigh = 0xf0 & d;  //ビット3は0(全チャンネル自動割込み終了モード)に固定
  1275:       return;
  1276:     case MFP_TACR:
  1277:       {
  1278:         int prevPrescale = mfpTaPrescale;
  1279:         mfpTaEventcount = (d & 0x08) != 0;
  1280:         mfpTaPrescale = d & 0x07;
  1281:         if (mfpTaEventcount && mfpTaPrescale != 0) {  //パルス幅計測モードはキャンセル
  1282:           mfpTaEventcount = false;
  1283:           mfpTaPrescale = 0;
  1284:         }
  1285:         if (mfpTaEventcount) {  //イベントカウントモード
  1286:           if (prevPrescale != 0) {  //ディレイモードで動作中だったとき
  1287:             mfpTaCurrent = mfpTaInitial - (int) (Math.floor ((double) (XEiJ.mpuClockTime - mfpTaStart) / mfpTaDelta) % mfpTaInitial);
  1288:           }
  1289:           mfpTaClock = XEiJ.FAR_FUTURE;
  1290:           TickerQueue.tkqRemove (mfpTaTicker);
  1291:         } else if (mfpTaPrescale != 0) {  //ディレイモード
  1292:           //! ディレイモードで動作中にプリスケールを変更されるとカウンタが即座に初期値に戻ってしまう
  1293:           mfpTaClock = (mfpTaStart = XEiJ.mpuClockTime) + (mfpTaDelta = MFP_DELTA[mfpTaPrescale]) * mfpTaInitial;
  1294:           TickerQueue.tkqAdd (mfpTaTicker, mfpTaClock);
  1295:         } else {  //カウント停止
  1296:           if (prevPrescale != 0) {  //ディレイモードで動作中だったとき
  1297:             mfpTaCurrent = mfpTaInitial - (int) (Math.floor ((double) (XEiJ.mpuClockTime - mfpTaStart) / mfpTaDelta) % mfpTaInitial);
  1298:           }
  1299:           mfpTaClock = XEiJ.FAR_FUTURE;
  1300:           TickerQueue.tkqRemove (mfpTaTicker);
  1301:         }
  1302:       }
  1303:       return;
  1304:     case MFP_TBCR:
  1305:       {
  1306:         int prevPrescale = mfpTbPrescale;
  1307:         mfpTbEventcount = (d & 0x08) != 0;
  1308:         mfpTbPrescale = d & 0x07;
  1309:         mfpTbKeyboardOn = !mfpTbEventcount && mfpTbPrescale == 0x01 && mfpTbInitial == 0x0d;
  1310:         if (mfpTbEventcount && mfpTbPrescale != 0) {  //パルス幅計測モードはキャンセル
  1311:           mfpTbEventcount = false;
  1312:           mfpTbPrescale = 0;
  1313:         }
  1314:         if (mfpTbEventcount) {  //イベントカウントモード
  1315:           if (prevPrescale != 0) {  //ディレイモードで動作中だったとき
  1316:             mfpTbCurrent = mfpTbInitial - (int) (Math.floor ((double) (XEiJ.mpuClockTime - mfpTbStart) / mfpTbDelta) % mfpTbInitial);
  1317:           }
  1318:           mfpTbClock = XEiJ.FAR_FUTURE;
  1319:           TickerQueue.tkqRemove (mfpTbTicker);
  1320:         } else if (mfpTbPrescale != 0) {  //ディレイモード
  1321:           //! ディレイモードで動作中にプリスケールを変更されるとカウンタが即座に初期値に戻ってしまう
  1322:           mfpTbClock = (mfpTbStart = XEiJ.mpuClockTime) + (mfpTbDelta = MFP_DELTA[mfpTbPrescale]) * mfpTbInitial;
  1323:           TickerQueue.tkqAdd (mfpTbTicker, mfpTbClock);
  1324:         } else {  //カウント停止
  1325:           if (prevPrescale != 0) {  //ディレイモードで動作中だったとき
  1326:             mfpTbCurrent = mfpTbInitial - (int) (Math.floor ((double) (XEiJ.mpuClockTime - mfpTbStart) / mfpTbDelta) % mfpTbInitial);
  1327:           }
  1328:           mfpTbClock = XEiJ.FAR_FUTURE;
  1329:           TickerQueue.tkqRemove (mfpTbTicker);
  1330:         }
  1331:       }
  1332:       return;
  1333:     case MFP_TCDCR:
  1334:       {
  1335:         int prevPrescale = mfpTcPrescale;
  1336:         mfpTcPrescale = d >> 4 & 0x07;
  1337:         if (mfpTcPrescale != 0) {  //ディレイモード
  1338:           //! ディレイモードで動作中にプリスケールを変更されるとカウンタが即座に初期値に戻ってしまう
  1339:           mfpTcClock = (mfpTcStart = XEiJ.mpuClockTime) + (mfpTcDelta = MFP_DELTA[mfpTcPrescale]) * mfpTcInitial;
  1340:           TickerQueue.tkqAdd (mfpTcTicker, mfpTcClock);
  1341:         } else {  //カウント停止
  1342:           if (prevPrescale != 0) {  //ディレイモードで動作中だったとき
  1343:             mfpTcCurrent = mfpTcInitial - (int) (Math.floor ((double) (XEiJ.mpuClockTime - mfpTcStart) / mfpTcDelta) % mfpTcInitial);
  1344:           }
  1345:           mfpTcClock = XEiJ.FAR_FUTURE;
  1346:           TickerQueue.tkqRemove (mfpTcTicker);
  1347:         }
  1348:       }
  1349:       {
  1350:         int prevPrescale = mfpTdPrescale;
  1351:         mfpTdPrescale = d & 0x07;
  1352:         if (mfpTdPrescale != 0) {  //ディレイモード
  1353:           //! ディレイモードで動作中にプリスケールを変更されるとカウンタが即座に初期値に戻ってしまう
  1354:           mfpTdClock = (mfpTdStart = XEiJ.mpuClockTime) + (mfpTdDelta = MFP_DELTA[mfpTdPrescale]) * mfpTdInitial;
  1355:           TickerQueue.tkqAdd (mfpTdTicker, mfpTdClock);
  1356:         } else {  //カウント停止
  1357:           if (prevPrescale != 0) {  //ディレイモードで動作中だったとき
  1358:             mfpTdCurrent = mfpTdInitial - (int) (Math.floor ((double) (XEiJ.mpuClockTime - mfpTdStart) / mfpTdDelta) % mfpTdInitial);
  1359:           }
  1360:           mfpTdClock = XEiJ.FAR_FUTURE;
  1361:           TickerQueue.tkqRemove (mfpTdTicker);
  1362:         }
  1363:       }
  1364:       return;
  1365:     case MFP_TADR:
  1366:       //! ディレイモードで動作中に初期値を変更するとオーバーフローするまでMFP_TADRの値がずれてしまう
  1367:       d &= 0xff;
  1368:       mfpTaInitial = d == 0 ? 256 : d;  //初期値
  1369:       if (!mfpTaEventcount && mfpTaPrescale == 0) {  //動作中でなければカウンタの値も変更される
  1370:         mfpTaCurrent = mfpTaInitial;
  1371:       }
  1372:       return;
  1373:     case MFP_TBDR:
  1374:       //! ディレイモードで動作中に初期値を変更するとオーバーフローするまでMFP_TADRの値がずれてしまう
  1375:       d &= 0xff;
  1376:       mfpTbInitial = d == 0 ? 256 : d;  //初期値
  1377:       mfpTbKeyboardOn = !mfpTbEventcount && mfpTbPrescale == 0x01 && mfpTbInitial == 0x0d;
  1378:       if (!mfpTbEventcount && mfpTbPrescale == 0) {  //動作中でなければカウンタの値も変更される
  1379:         mfpTbCurrent = mfpTbInitial;
  1380:       }
  1381:       return;
  1382:     case MFP_TCDR:
  1383:       //! ディレイモードで動作中に初期値を変更するとオーバーフローするまでMFP_TADRの値がずれてしまう
  1384:       d &= 0xff;
  1385:       mfpTcInitial = d == 0 ? 256 : d;  //初期値
  1386:       if (mfpTcPrescale == 0) {  //動作中でなければカウンタの値も変更される
  1387:         mfpTcCurrent = mfpTcInitial;
  1388:       }
  1389:       return;
  1390:     case MFP_TDDR:
  1391:       //! ディレイモードで動作中に初期値を変更するとオーバーフローするまでMFP_TADRの値がずれてしまう
  1392:       d &= 0xff;
  1393:       mfpTdInitial = d == 0 ? 256 : d;  //初期値
  1394:       if (mfpTdPrescale == 0) {  //動作中でなければカウンタの値も変更される
  1395:         mfpTdCurrent = mfpTdInitial;
  1396:       }
  1397:       return;
  1398:     case MFP_SYNC_CHAR:
  1399:       return;
  1400:     case MFP_UCR:
  1401:       mfpUCR = d & 0b11111110;
  1402:       mfpTSRBufferFullTime = (mfpTbDelta * mfpTbInitial *  //Timer-Bの1周期。TBOが反転する間隔
  1403:                               2 *  //TBOの1周期
  1404:                               ((mfpUCR & 0x80) != 0 ? 16 : 1) *  //クロックモード
  1405:                               ((1 * 2) +  //スタートビット
  1406:                                ((8 - ((mfpUCR >> 5) & 3)) * 2) +  //キャラクタ長
  1407:                                (((mfpUCR >> 3) & 3) + 1)) / 2);  //ストップビット
  1408:       return;
  1409:     case MFP_RSR:
  1410:       mfpRSR = d & 0b00000001;
  1411:       return;
  1412:     case MFP_TSR:
  1413:       mfpTSR = d & 0b00000001;
  1414:       return;
  1415:     case MFP_UDR:
  1416:       if (mfpTbKeyboardOn) {
  1417:         if ((byte) d < 0) {  //LEDの状態
  1418:           Keyboard.kbdSetLedStatus (d);
  1419:         } else if ((d & 0xf8) == 0x40) {  //MSCTRL
  1420:         } else if ((d & 0xf8) == 0x48) {  //ロック
  1421:         } else if ((d & 0xfc) == 0x54) {  //LEDの明るさ
  1422:           Keyboard.kbdSetLedBrightness (d);
  1423:         } else if ((d & 0xfc) == 0x58) {  //テレビコントロール
  1424:         } else if ((d & 0xfc) == 0x5c) {  //OPT.2キーによるテレビコントロール
  1425:         } else if ((d & 0xf0) == 0x60) {  //リピート開始時間
  1426:           Keyboard.kbdSetRepeatDelay (0x0f & d);
  1427:         } else if ((d & 0xf0) == 0x70) {  //リピート間隔
  1428:           Keyboard.kbdSetRepeatInterval (0x0f & d);
  1429:         }
  1430:       }
  1431:       mfpTSRBufferFullEnd = XEiJ.mpuClockTime + mfpTSRBufferFullTime;
  1432:       return;
  1433:     default:
  1434:       if ((a & 1) == 0 &&  //偶数アドレスのバイトライト
  1435:           !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  1436:         MemoryMappedDevice.MMD_NUL.mmdWb (a, d);  //バスエラー
  1437:       }
  1438:       return;
  1439:     }
  1440:   }
  1441: 
  1442: 
  1443: 
  1444: }  //class MC68901
  1445: 
  1446: 
  1447: