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