MC68901.java
     1: //========================================================================================
     2: //  MC68901.java
     3: //    en:MFP -- Multi-Function Peripheral
     4: //    ja:MFP -- マルチファンクションペリフェラル
     5: //  Copyright (C) 2003-2017 Makoto Kamada
     6: //
     7: //  This file is part of the XEiJ (X68000 Emulator in Java).
     8: //  You can use, modify and redistribute the XEiJ if the conditions are met.
     9: //  Read the XEiJ License for more details.
    10: //  http://stdkmd.com/xeij/
    11: //========================================================================================
    12: 
    13: 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 mfpTcPrescale;  //タイマCのプリスケール(0~7、0はカウント禁止)
   153:   public static int mfpTdPrescale;  //タイマDのプリスケール(0~7、0はカウント禁止)
   154:   public static boolean mfpTaEventcount;  //イベントカウントモード
   155:   public static int mfpTaInitial;  //タイマAの初期値(1~256)
   156:   public static int mfpTcInitial;  //タイマCの初期値(1~256)
   157:   public static int mfpTdInitial;  //タイマDの初期値(1~256)
   158:   public static int mfpTaCurrent;  //タイマAの現在の値(1~256、イベントカウントモードのときとディレイモードでカウンタが停止しているときだけ有効)
   159:   public static int mfpTcCurrent;  //タイマCの現在の値(1~256、イベントカウントモードのときとディレイモードでカウンタが停止しているときだけ有効)
   160:   public static int mfpTdCurrent;  //タイマDの現在の値(1~256、イベントカウントモードのときとディレイモードでカウンタが停止しているときだけ有効)
   161: 
   162:   //割り込み
   163:   //  割り込み要求カウンタと割り込み受付カウンタの値が異なるときMFP_IPRA,MFP_IPRBの該当ビットがONになる
   164:   //  MFP_IERA,MFP_IERBの該当ビットに0が書き込まれたときMFP_IPRA,MFP_IPRBの該当ビットを0にするためrequestをacknowledgedにコピーする
   165:   public static final int[] mfpInnerRequest = new int[16];  //割り込み要求カウンタ
   166:   public static final int[] mfpInnerAcknowledged = new int[16];  //割り込み受付カウンタ
   167:   public static final boolean[] mfpInnerInService = new boolean[16];  //割り込み処理中のときtrue
   168:   public static int mfpInnerLevel;  //割り込み処理中のレベル
   169: 
   170:   //タイマ
   171:   public static long mfpTaStart;  //タイマAの初期値からスタートしたときのクロック
   172:   public static long mfpTcStart;  //タイマCの初期値からスタートしたときのクロック
   173:   public static long mfpTdStart;  //タイマDの初期値からスタートしたときのクロック
   174:   public static long mfpTaDelta;  //タイマAのプリスケールに対応する1カウントあたりの時間
   175:   public static long mfpTcDelta;  //タイマCのプリスケールに対応する1カウントあたりの時間
   176:   public static long mfpTdDelta;  //タイマDのプリスケールに対応する1カウントあたりの時間
   177:   public static long mfpTaClock;  //タイマAが次に割り込む時刻
   178:   public static long mfpTcClock;  //タイマCが次に割り込む時刻
   179:   public static long mfpTdClock;  //タイマDが次に割り込む時刻
   180:   public static long mfpTcTdClock;  //Math.min(mfpTcClock,mfpTdClock)
   181: 
   182:   //MFP_UDRの入力データのキュー
   183:   //  入力データはゼロ拡張すること
   184:   //  キー入力を取りこぼさないためにキューを使う
   185:   //  read==writeのときキューは空
   186:   //  書き込むとread==writeになってしまうときは一杯なので書き込まない
   187:   public static final int[] mfpUdrQueueArray = new int[MFP_UDR_QUEUE_SIZE];  //入力データ
   188:   public static int mfpUdrQueueRead;  //最後に読み出したデータの位置
   189:   public static int mfpUdrQueueWrite;  //最後に書き込んだデータの位置
   190: 
   191:   //mfpInit ()
   192:   //  MFPを初期化する
   193:   public static void mfpInit () {
   194:     //mfpInnerRequest = new int[16];
   195:     //mfpInnerAcknowledged = new int[16];
   196:     //mfpInnerInService = new boolean[16];
   197:     //mfpUdrQueueArray = new int[MFP_UDR_QUEUE_SIZE];
   198:     for (int i = 0; i < MFP_UDR_QUEUE_SIZE; i++) {
   199:       mfpUdrQueueArray[i] = 0;
   200:     }
   201:     mfpUdrQueueRead = 0;
   202:     mfpUdrQueueWrite = 0;
   203:     mfpReset ();
   204:   }  //mfpInit()
   205: 
   206:   //リセット
   207:   public static void mfpReset () {
   208:     mfpGpipAlarm = 0;
   209:     mfpGpipExpwon = MFP_GPIP_EXPWON_MASK;
   210:     mfpGpipPower = 0;
   211:     mfpGpipOpmirq = MFP_GPIP_OPMIRQ_MASK;
   212:     mfpGpipVdisp = 0;
   213:     mfpGpipRint = MFP_GPIP_RINT_MASK;
   214:     mfpGpipHsync = 0;
   215:     mfpAer = 0;
   216:     mfpIer = 0;
   217:     for (int i = 0; i < 16; i++) {
   218:       mfpInnerRequest[i] = 0;
   219:       mfpInnerAcknowledged[i] = 0;
   220:       mfpInnerInService[i] = false;
   221:     }
   222:     mfpImr = 0;
   223:     mfpVectorHigh = 0;
   224:     mfpTaPrescale = 0;
   225:     mfpTcPrescale = 0;
   226:     mfpTdPrescale = 0;
   227:     mfpTaEventcount = false;
   228:     mfpTaInitial = 256;
   229:     mfpTcInitial = 256;
   230:     mfpTdInitial = 256;
   231:     mfpTaCurrent = 0;
   232:     mfpTcCurrent = 0;
   233:     mfpTdCurrent = 0;
   234:     mfpTaStart = 0L;
   235:     mfpTcStart = 0L;
   236:     mfpTdStart = 0L;
   237:     mfpTaClock = XEiJ.FAR_FUTURE;
   238:     mfpTcClock = XEiJ.FAR_FUTURE;
   239:     mfpTdClock = XEiJ.FAR_FUTURE;
   240:     mfpTcTdClock = XEiJ.FAR_FUTURE;
   241:     if (MFP_KBD_ON) {
   242:       //mfpKbdBuffer = new int[MFP_KBD_LIMIT];
   243:       mfpKbdReadPointer = 0;
   244:       mfpKbdWritePointer = 0;
   245:       mfpKbdLastData = 0;
   246:       mfpTkClock = XEiJ.FAR_FUTURE;
   247:       mfpTaTkClock = XEiJ.FAR_FUTURE;
   248:       //mfpTkTime = 0L;
   249:     }
   250:     TickerQueue.tkqRemove (mfpTaTicker);
   251:     TickerQueue.tkqRemove (mfpTcTicker);
   252:     TickerQueue.tkqRemove (mfpTdTicker);
   253:     TickerQueue.tkqRemove (mfpTkTicker);
   254:   }  //mfpReset()
   255: 
   256:   //割り込み受付
   257:   //  コアが割り込み要求を受け付けたときに呼び出す
   258:   //  割り込みベクタ番号を返す
   259:   //  割り込み要求を取り下げる場合は0を返す
   260:   //  オートベクタを使用するデバイスはオートベクタの番号を返すこと
   261:   //
   262:   //! 未対応
   263:   //  スプリアス割り込みは発生しない
   264:   //  実機ではデバイスからMFPへの割り込み要求とMPUからMFPへの割り込み禁止指示がほぼ同時に発生するとスプリアス割り込みが通知されることがある
   265:   //    (1) デバイスがMFPに割り込みを要求する
   266:   //    (2) MPUがMFPにデバイスの割り込みの禁止を指示する
   267:   //    (3) MFPがデバイスの要求に従ってMPUに割り込みを要求する
   268:   //    (4) MFPがMPUの指示に従ってデバイスの割り込みを禁止する
   269:   //    (5) MPUがMFPの割り込み要求を受け付けてMFPに割り込みベクタの提出を指示する
   270:   //    (6) MFPがMPUの指示に従って割り込みが許可されていて割り込みを要求しているデバイスを探すが見当たらないので応答しない
   271:   //    (7) MPUがスプリアス割り込みを通知する
   272:   //  ここではデバイスが見つからないとき割り込み要求を取り下げるのでスプリアス割り込みは発生しない
   273:   public static int mfpAcknowledge () {
   274:     for (int i = 15; i >= 0; i--) {
   275:       if ((mfpImr & 1 << i) != 0) {
   276:         int request = mfpInnerRequest[i];
   277:         if (mfpInnerAcknowledged[i] != request) {
   278:           mfpInnerAcknowledged[i] = request;
   279:           mfpInnerInService[mfpInnerLevel = i] = true;
   280:           return mfpVectorHigh + i;
   281:         }
   282:       }
   283:     }
   284:     return 0;
   285:   }  //mfpAcknowledge()
   286: 
   287:   //割り込み終了
   288:   //  コアが割り込み処理を終了したときに呼び出す
   289:   //  まだ処理されていない割り込みが残っていたら再度割り込み要求を出す
   290:   public static void mfpDone () {
   291:     mfpInnerInService[mfpInnerLevel] = false;
   292:     for (int i = 15; i >= 0; i--) {
   293:       if ((mfpImr & 1 << i) != 0 && mfpInnerAcknowledged[i] != mfpInnerRequest[i]) {
   294:         if (MFP_DELAYED_INTERRUPT) {
   295:           XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   296:         } else {
   297:           XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   298:         }
   299:         return;
   300:       }
   301:     }
   302:   }  //mfpDone()
   303: 
   304:   //mfpKeyboardInput (scanCode)
   305:   //  キー入力
   306:   //  コアのスレッドで呼び出すこと
   307:   public static void mfpKeyboardInput (int scanCode) {
   308:     scanCode &= 0xff;
   309:     int write = mfpUdrQueueWrite + 1 & MFP_UDR_QUEUE_MASK;
   310:     if (mfpUdrQueueRead != write) {  //キューに書き込めるとき
   311:       mfpUdrQueueWrite = write;
   312:       mfpUdrQueueArray[mfpUdrQueueWrite] = scanCode;
   313:       if ((mfpIer & MFP_INPUT_FULL_MASK) != 0) {
   314:         mfpInnerRequest[MFP_INPUT_FULL_LEVEL]++;
   315:         if ((mfpImr & MFP_INPUT_FULL_MASK) != 0) {
   316:           if (MFP_DELAYED_INTERRUPT) {
   317:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   318:           } else {
   319:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   320:           }
   321:         }
   322:       }
   323:     }
   324:   }  //mfpKeyboardInput
   325: 
   326: 
   327:   //Timer-A
   328:   public static final TickerQueue.Ticker mfpTaTicker = new TickerQueue.Ticker () {
   329:     @Override protected void tick () {
   330:       if ((mfpIer & MFP_TIMER_A_MASK) != 0) {
   331:         mfpInnerRequest[MFP_TIMER_A_LEVEL]++;
   332:         if ((mfpImr & MFP_TIMER_A_MASK) != 0) {
   333:           if (MFP_DELAYED_INTERRUPT) {
   334:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   335:           } else {
   336:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   337:           }
   338:         }
   339:       }
   340:       mfpTaClock += mfpTaDelta * mfpTaInitial;
   341:       TickerQueue.tkqAdd (mfpTaTicker, mfpTaClock);
   342:     }
   343:   };
   344: 
   345:   //Timer-C
   346:   public static final TickerQueue.Ticker mfpTcTicker = new TickerQueue.Ticker () {
   347:     @Override protected void tick () {
   348:       if ((mfpIer & MFP_TIMER_C_MASK) != 0) {
   349:         mfpInnerRequest[MFP_TIMER_C_LEVEL]++;
   350:         if ((mfpImr & MFP_TIMER_C_MASK) != 0) {
   351:           if (MFP_DELAYED_INTERRUPT) {
   352:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   353:           } else {
   354:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   355:           }
   356:         }
   357:       }
   358:       mfpTcClock += mfpTcDelta * mfpTcInitial;
   359:       TickerQueue.tkqAdd (mfpTcTicker, mfpTcClock);
   360:     }
   361:   };
   362: 
   363:   //Timer-D
   364:   public static final TickerQueue.Ticker mfpTdTicker = new TickerQueue.Ticker () {
   365:     @Override protected void tick () {
   366:       if ((mfpIer & MFP_TIMER_D_MASK) != 0) {
   367:         mfpInnerRequest[MFP_TIMER_D_LEVEL]++;
   368:         if ((mfpImr & MFP_TIMER_D_MASK) != 0) {
   369:           if (MFP_DELAYED_INTERRUPT) {
   370:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   371:           } else {
   372:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   373:           }
   374:         }
   375:       }
   376:       mfpTdClock += mfpTdDelta * mfpTdInitial;
   377:       TickerQueue.tkqAdd (mfpTdTicker, mfpTdClock);
   378:     }
   379:   };
   380: 
   381:   //キーボード
   382:   public static final TickerQueue.Ticker mfpTkTicker = new TickerQueue.Ticker () {
   383:     @Override protected void tick () {
   384:       if (MFP_KBD_ON) {
   385:         //  XEiJ.mpuClockTimeだけで割り込みのタイミングを決めると、
   386:         //  コアのタスクが詰まっているときキー入力割り込みも詰まってリピートの開始と間隔が短くなってしまう
   387:         long time = System.currentTimeMillis () - 10L;  //10msまでは早すぎてもよいことにする
   388:         if (time < mfpTkTime) {  //早すぎる
   389:           mfpTkClock = XEiJ.mpuClockTime + XEiJ.TMR_FREQ / 1000 * (mfpTkTime - time);
   390:           TickerQueue.tkqAdd (mfpTkTicker, mfpTkClock);
   391:         } else {
   392:           if (mfpKbdReadPointer != mfpKbdWritePointer) {  //バッファが空でないとき
   393:             if ((mfpIer & MFP_INPUT_FULL_MASK) != 0) {
   394:               mfpInnerRequest[MFP_INPUT_FULL_LEVEL]++;
   395:               if ((mfpImr & MFP_INPUT_FULL_MASK) != 0) {
   396:                 //MFPのキー入力割り込みを要求する
   397:                 if (MFP_DELAYED_INTERRUPT) {
   398:                   XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   399:                 } else {
   400:                   XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   401:                 }
   402:               }
   403:             }
   404:           }
   405:           mfpTkClock = XEiJ.FAR_FUTURE;
   406:           TickerQueue.tkqRemove (mfpTkTicker);
   407:           //mfpTkTime = 0L;
   408:         }
   409:       }
   410:     }  //tick()
   411:   };
   412: 
   413: 
   414:   //GPIP入力
   415:   //  デバイスが呼び出す
   416:   //GPIP0
   417:   public static void mfpAlarmRise () {
   418:     if (mfpGpipAlarm == 0) {  //0→1
   419:       mfpGpipAlarm = MFP_GPIP_ALARM_MASK;
   420:       if ((mfpAer & MFP_GPIP_ALARM_MASK) != 0 && (mfpIer & MFP_ALARM_MASK) != 0) {
   421:         mfpInnerRequest[MFP_ALARM_LEVEL]++;
   422:         if ((mfpImr & MFP_ALARM_MASK) != 0) {
   423:           if (MFP_DELAYED_INTERRUPT) {
   424:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   425:           } else {
   426:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   427:           }
   428:         }
   429:       }
   430:     }
   431:   }  //mfpAlarmRise()
   432:   public static void mfpAlarmFall () {
   433:     if (mfpGpipAlarm != 0) {  //1→0
   434:       mfpGpipAlarm = 0;
   435:       if ((mfpAer & MFP_GPIP_ALARM_MASK) == 0 && (mfpIer & MFP_ALARM_MASK) != 0) {
   436:         mfpInnerRequest[MFP_ALARM_LEVEL]++;
   437:         if ((mfpImr & MFP_ALARM_MASK) != 0) {
   438:           if (MFP_DELAYED_INTERRUPT) {
   439:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   440:           } else {
   441:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   442:           }
   443:         }
   444:       }
   445:     }
   446:   }  //mfpAlarmFall()
   447: 
   448:   //GPIP1
   449:   public static void mfpExpwonRise () {
   450:     if (mfpGpipExpwon == 0) {  //0→1
   451:       mfpGpipExpwon = MFP_GPIP_EXPWON_MASK;
   452:       if ((mfpAer & MFP_GPIP_EXPWON_MASK) != 0 && (mfpIer & MFP_EXPWON_MASK) != 0) {
   453:         mfpInnerRequest[MFP_EXPWON_LEVEL]++;
   454:         if ((mfpImr & MFP_EXPWON_MASK) != 0) {
   455:           if (MFP_DELAYED_INTERRUPT) {
   456:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   457:           } else {
   458:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   459:           }
   460:         }
   461:       }
   462:     }
   463:   }  //mfpExpwonRise()
   464:   public static void mfpExpwonFall () {
   465:     if (mfpGpipExpwon != 0) {  //1→0
   466:       mfpGpipExpwon = 0;
   467:       if ((mfpAer & MFP_GPIP_EXPWON_MASK) == 0 && (mfpIer & MFP_EXPWON_MASK) != 0) {
   468:         mfpInnerRequest[MFP_EXPWON_LEVEL]++;
   469:         if ((mfpImr & MFP_EXPWON_MASK) != 0) {
   470:           if (MFP_DELAYED_INTERRUPT) {
   471:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   472:           } else {
   473:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   474:           }
   475:         }
   476:       }
   477:     }
   478:   }  //mfpExpwonFall()
   479: 
   480:   //GPIP2
   481:   public static void mfpPowerRise () {
   482:     if (mfpGpipPower == 0) {  //0→1
   483:       mfpGpipPower = MFP_GPIP_POWER_MASK;
   484:       if ((mfpAer & MFP_GPIP_POWER_MASK) != 0 && (mfpIer & MFP_POWER_MASK) != 0) {
   485:         mfpInnerRequest[MFP_POWER_LEVEL]++;
   486:         if ((mfpImr & MFP_POWER_MASK) != 0) {
   487:           if (MFP_DELAYED_INTERRUPT) {
   488:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   489:           } else {
   490:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   491:           }
   492:         }
   493:       }
   494:     }
   495:   }  //mfpPowerRise()
   496:   public static void mfpPowerFall () {
   497:     if (mfpGpipPower != 0) {  //1→0
   498:       mfpGpipPower = 0;
   499:       if ((mfpAer & MFP_GPIP_POWER_MASK) == 0 && (mfpIer & MFP_POWER_MASK) != 0) {
   500:         mfpInnerRequest[MFP_POWER_LEVEL]++;
   501:         if ((mfpImr & MFP_POWER_MASK) != 0) {
   502:           if (MFP_DELAYED_INTERRUPT) {
   503:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   504:           } else {
   505:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   506:           }
   507:         }
   508:       }
   509:     }
   510:   }  //mfpPowerFall()
   511: 
   512:   //GPIP3
   513:   public static void mfpOpmirqRise () {
   514:     if (mfpGpipOpmirq == 0) {  //0→1
   515:       mfpGpipOpmirq = MFP_GPIP_OPMIRQ_MASK;
   516:       if ((mfpAer & MFP_GPIP_OPMIRQ_MASK) != 0 && (mfpIer & MFP_OPMIRQ_MASK) != 0) {
   517:         mfpInnerRequest[MFP_OPMIRQ_LEVEL]++;
   518:         if ((mfpImr & MFP_OPMIRQ_MASK) != 0) {
   519:           if (MFP_DELAYED_INTERRUPT) {
   520:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   521:           } else {
   522:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   523:           }
   524:         }
   525:       }
   526:     }
   527:   }  //mfpOpmirqRise()
   528:   public static void mfpOpmirqFall () {
   529:     if (mfpGpipOpmirq != 0) {  //1→0
   530:       mfpGpipOpmirq = 0;
   531:       if ((mfpAer & MFP_GPIP_OPMIRQ_MASK) == 0 && (mfpIer & MFP_OPMIRQ_MASK) != 0) {
   532:         mfpInnerRequest[MFP_OPMIRQ_LEVEL]++;
   533:         if ((mfpImr & MFP_OPMIRQ_MASK) != 0) {
   534:           if (MFP_DELAYED_INTERRUPT) {
   535:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   536:           } else {
   537:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   538:           }
   539:         }
   540:       }
   541:     }
   542:   }  //mfpOpmirqFall()
   543: 
   544:   //GPIP4
   545:   public static void mfpVdispRise () {
   546:     //if (mfpGpipVdisp == 0) {  //0→1
   547:     mfpGpipVdisp = MFP_GPIP_VDISP_MASK;
   548:     if ((mfpAer & MFP_GPIP_VDISP_MASK) != 0) {
   549:       if ((mfpIer & MFP_VDISP_MASK) != 0) {
   550:         mfpInnerRequest[MFP_VDISP_LEVEL]++;
   551:         if ((mfpImr & MFP_VDISP_MASK) != 0) {
   552:           if (MFP_DELAYED_INTERRUPT) {
   553:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   554:           } else {
   555:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   556:           }
   557:         }
   558:       }
   559:       if (mfpTaEventcount && --mfpTaCurrent <= 0) {
   560:         mfpTaCurrent = mfpTaInitial;
   561:         if ((mfpIer & MFP_TIMER_A_MASK) != 0) {
   562:           mfpInnerRequest[MFP_TIMER_A_LEVEL]++;
   563:           if ((mfpImr & MFP_TIMER_A_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:     }
   573:     //}
   574:   }  //mfpVdispRise()
   575:   public static void mfpVdispFall () {
   576:     //if (mfpGpipVdisp != 0) {  //1→0
   577:     mfpGpipVdisp = 0;
   578:     if ((mfpAer & MFP_GPIP_VDISP_MASK) == 0) {
   579:       if ((mfpIer & MFP_VDISP_MASK) != 0) {
   580:         mfpInnerRequest[MFP_VDISP_LEVEL]++;
   581:         if ((mfpImr & MFP_VDISP_MASK) != 0) {
   582:           if (MFP_DELAYED_INTERRUPT) {
   583:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   584:           } else {
   585:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   586:           }
   587:         }
   588:       }
   589:       if (mfpTaEventcount && --mfpTaCurrent <= 0) {
   590:         mfpTaCurrent = mfpTaInitial;
   591:         if ((mfpIer & MFP_TIMER_A_MASK) != 0) {
   592:           mfpInnerRequest[MFP_TIMER_A_LEVEL]++;
   593:           if ((mfpImr & MFP_TIMER_A_MASK) != 0) {
   594:             if (MFP_DELAYED_INTERRUPT) {
   595:               XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   596:             } else {
   597:               XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   598:             }
   599:           }
   600:         }
   601:       }
   602:     }
   603:     //}
   604:   }  //mfpVdispFall()
   605: 
   606:   //GPIP6
   607:   public static void mfpRintRise () {
   608:     //if (mfpGpipRint == 0) {  //0→1
   609:     mfpGpipRint = MFP_GPIP_RINT_MASK;
   610:     if ((mfpAer & MFP_GPIP_RINT_MASK) != 0 && (mfpIer & MFP_RINT_MASK) != 0) {
   611:       mfpInnerRequest[MFP_RINT_LEVEL]++;
   612:       if ((mfpImr & MFP_RINT_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:   }  //mfpRintRise()
   622:   public static void mfpRintFall () {
   623:     //if (mfpGpipRint != 0) {  //1→0
   624:     mfpGpipRint = 0;
   625:     if ((mfpAer & MFP_GPIP_RINT_MASK) == 0 && (mfpIer & MFP_RINT_MASK) != 0) {
   626:       mfpInnerRequest[MFP_RINT_LEVEL]++;
   627:       if ((mfpImr & MFP_RINT_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:   }  //mfpRintFall()
   637: 
   638:   //GPIP7
   639:   public static void mfpHsyncRise () {
   640:     //if (mfpGpipHsync == 0) {  //0→1
   641:     mfpGpipHsync = MFP_GPIP_HSYNC_MASK;
   642:     if ((mfpAer & MFP_GPIP_HSYNC_MASK) != 0 && (mfpIer & MFP_HSYNC_MASK) != 0) {
   643:       mfpInnerRequest[MFP_HSYNC_LEVEL]++;
   644:       if ((mfpImr & MFP_HSYNC_MASK) != 0) {
   645:         if (MFP_DELAYED_INTERRUPT) {
   646:           XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   647:         } else {
   648:           XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   649:         }
   650:       }
   651:     }
   652:     //}
   653:   }  //mfpHsyncRise()
   654:   public static void mfpHsyncFall () {
   655:     //if (mfpGpipHsync != 0) {  //1→0
   656:     mfpGpipHsync = 0;
   657:     if ((mfpAer & MFP_GPIP_HSYNC_MASK) == 0 && (mfpIer & MFP_HSYNC_MASK) != 0) {
   658:       mfpInnerRequest[MFP_HSYNC_LEVEL]++;
   659:       if ((mfpImr & MFP_HSYNC_MASK) != 0) {
   660:         if (MFP_DELAYED_INTERRUPT) {
   661:           XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   662:         } else {
   663:           XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   664:         }
   665:       }
   666:     }
   667:     //}
   668:   }  //mfpHsyncFall()
   669: 
   670:   //キー入力のリピートの処理をMFPで行う
   671:   //  キー入力バッファ
   672:   //    キー入力データが並んでいるリングバッファ
   673:   //    読み出しポインタ
   674:   //      次に読み出す位置
   675:   //      MFPが更新する
   676:   //    書き込みポインタ
   677:   //      次に書き込む位置
   678:   //      KBDが更新する
   679:   //    読み出しポインタと書き込みポインタが一致しているときバッファは空
   680:   //    読み出しポインタを進めると書き込みポインタと一致するとき読み出しポインタはバッファの末尾
   681:   //    書き込みポインタを進めると読み出しポインタと一致するときはバッファが一杯(なので書き込めない)
   682:   //  キー入力データ
   683:   //    1データにつきintを2個用いる
   684:   //    data  0x00+キーコード  キーが押されたデータ
   685:   //          0x80+キーコード  キーが離されたデータ
   686:   //    repeat  -1  リピート開始後のデータ
   687:   //                リピートするキーが押されて1回以上読み出されたデータ
   688:   //             0  リピートしないデータ
   689:   //                リピートしないキーが押されたかキーが離されたときのデータ
   690:   //             1  リピート開始前のデータ
   691:   //                リピートするキーが押されてまだ読み出されていないデータ
   692:   //  最後に読み出したデータ
   693:   //    キー入力バッファから最後に読み出したデータ
   694:   //    キー入力バッファが空のときUDRから読み出される
   695:   //  キーが押されたまたは離されたとき
   696:   //    バッファが一杯でないとき
   697:   //      キーが押されたとき
   698:   //        書き込みポインタの位置にリピート開始前のデータを書き込む
   699:   //      キーが離されたとき
   700:   //        書き込みポインタの位置にリピートしないデータを書き込む
   701:   //      書き込みポインタを進める
   702:   //    MFPのキー入力割り込みを要求する
   703:   //  UDR読み出し
   704:   //    バッファが空でないとき
   705:   //      バッファの末尾でなくて先頭がリピート開始後のデータのとき
   706:   //        読み出しポインタを進める
   707:   //      読み出しポインタの位置からデータを読み出して最後に読み出したデータとして保存する
   708:   //      バッファの末尾でないとき
   709:   //        読み出しポインタを進める
   710:   //        MFPのキー入力割り込みを要求する
   711:   //      バッファの末尾でリピートしないデータのとき
   712:   //        読み出しポインタを進める
   713:   //      バッファの末尾でリピート開始前のデータのとき
   714:   //        読み出しポインタの位置のデータをリピート開始後に変更する
   715:   //        現在時刻+リピート開始時間でMFPのTimer-Kをセットする
   716:   //      バッファの末尾でリピート開始後のデータのとき
   717:   //        現在時刻+リピート間隔時間でMFPのTimer-Kをセットする
   718:   //    最後に読み出したデータを返す
   719:   //  MFPのTimer-K
   720:   //    キー入力のリピート処理のためにMFPに追加されたタイマー
   721:   //    バッファが空でないとき
   722:   //      MFPのキー入力割り込みを要求する
   723:   //  UDR読み出しとMFPのTimer-Kはどちらもコアから呼ばれるので同時に呼び出されることはない
   724:   //  キー入力割り込みがIERAで禁止されているとタイマーで割り込みがかからないのでリピートが止まってしまうが、
   725:   //  キー入力割り込みを止めたいときはIMRAでマスクするのが原則なので通常は問題ないはず
   726:   public static final boolean MFP_KBD_ON = true;  //true=キー入力のリピートの処理をMFPで行う
   727:   public static final int MFP_KBD_LIMIT = 512;  //キー入力バッファのサイズ。2の累乗にすること
   728:   public static final int[] mfpKbdBuffer = new int[MFP_KBD_LIMIT];  //キー入力バッファ
   729:   public static int mfpKbdReadPointer;  //読み出しポインタ
   730:   public static int mfpKbdWritePointer;  //書き込みポインタ
   731:   public static int mfpKbdLastData;  //最後に読み出したデータ
   732:   public static long mfpTkClock;  //Timer-Kの次の呼び出し時刻
   733:   public static long mfpTaTkClock;  //Math.min(mfpTaClock,mfpTkClock)
   734:   public static long mfpTkTime;  //次にTimer-Kが呼び出されるべき時刻(ms)。mfpTkClockがXEiJ.FAR_FUTUREでないときだけ有効
   735: 
   736:   //mfpKbdInput (data, repeat)
   737:   //  キーが押されたまたは離されたとき
   738:   //  data  キーコード
   739:   //  repeat  リピートの有無。false=リピートしない,true=リピートする
   740:   public static void mfpKbdInput (int data, boolean repeat) {
   741:     int w = mfpKbdWritePointer;
   742:     int w1 = w + 2 & MFP_KBD_LIMIT - 2;
   743:     if (w1 != mfpKbdReadPointer) {  //バッファが一杯でないとき
   744:       mfpKbdBuffer[w] = data;  //書き込みポインタの位置にデータを書き込む
   745:       mfpKbdBuffer[w + 1] = repeat ? 1 : 0;  //0=リピートしないデータ,1=リピート開始前のデータ
   746:       mfpKbdWritePointer = w1;  //書き込みポインタを進める
   747:       if ((mfpIer & MFP_INPUT_FULL_MASK) != 0) {
   748:         mfpInnerRequest[MFP_INPUT_FULL_LEVEL]++;
   749:         if ((mfpImr & MFP_INPUT_FULL_MASK) != 0) {
   750:           //MFPのキー入力割り込みを要求する
   751:           if (MFP_DELAYED_INTERRUPT) {
   752:             XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   753:           } else {
   754:             XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   755:           }
   756:         }
   757:       }
   758:     }
   759:   }  //mfpKbdInput(int,boolean)
   760: 
   761:   //data = mfpKbdReadData ()
   762:   //  UDR読み出し
   763:   public static int mfpKbdReadData () {
   764:     int r = mfpKbdReadPointer;
   765:     int w = mfpKbdWritePointer;
   766:     if (r != w) {  //バッファが空でないとき
   767:       int r1 = r + 2 & MFP_KBD_LIMIT - 2;
   768:       int s = mfpKbdBuffer[r + 1];  //-1=リピート開始後,0=リピートしない,1=リピート開始前
   769:       if (r1 != w && s < 0) {  //バッファの末尾でなくて先頭がリピート開始後のデータのとき
   770:         mfpKbdReadPointer = r = r1;  //読み出しポインタを進める
   771:         r1 = r + 2 & MFP_KBD_LIMIT - 2;
   772:         s = mfpKbdBuffer[r + 1];
   773:       }
   774:       mfpKbdLastData = mfpKbdBuffer[r];  //読み出しポインタの位置からデータを読み出して最後に読み出したデータとして保存する
   775:       if (r1 != w) {  //バッファの末尾でないとき
   776:         mfpKbdReadPointer = r1;  //読み出しポインタを進める
   777:         if ((mfpIer & MFP_INPUT_FULL_MASK) != 0) {
   778:           mfpInnerRequest[MFP_INPUT_FULL_LEVEL]++;
   779:           if ((mfpImr & MFP_INPUT_FULL_MASK) != 0) {
   780:             //MFPのキー入力割り込みを要求する
   781:             if (MFP_DELAYED_INTERRUPT) {
   782:               XEiJ.mpuDIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   783:             } else {
   784:               XEiJ.mpuIRR |= XEiJ.MPU_MFP_INTERRUPT_MASK;
   785:             }
   786:           }
   787:         }
   788:       } else if (s == 0) {  //バッファの末尾でリピートしないデータのとき
   789:         mfpKbdReadPointer = r1;  //読み出しポインタを進める
   790:       } else if (s > 0) {  //バッファの末尾でリピート開始前のデータのとき
   791:         mfpKbdBuffer[r + 1] = -1;  //読み出しポインタの位置のデータをリピート開始後に変更する
   792:         if ((mfpIer & MFP_INPUT_FULL_MASK) != 0) {  //キー入力割り込みが許可されているとき
   793:           mfpTkClock = XEiJ.mpuClockTime + XEiJ.TMR_FREQ / 1000 * Keyboard.kbdRepeatDelay;  //現在時刻+リピート開始時間でMFPのTimer-Kをセットする
   794:           TickerQueue.tkqAdd (mfpTkTicker, mfpTkClock);
   795:           mfpTkTime = System.currentTimeMillis () + Keyboard.kbdRepeatDelay;  //次にTimer-Kが呼び出されるべき時刻(ms)
   796:         }
   797:       } else {  //バッファの末尾でリピート開始後のデータのとき
   798:         if ((mfpIer & MFP_INPUT_FULL_MASK) != 0) {  //キー入力割り込みが許可されているとき
   799:           mfpTkClock = XEiJ.mpuClockTime + XEiJ.TMR_FREQ / 1000 * Keyboard.kbdRepeatInterval;  //現在時刻+リピート間隔時間でMFPのTimer-Kをセットする
   800:           TickerQueue.tkqAdd (mfpTkTicker, mfpTkClock);
   801:           mfpTkTime = System.currentTimeMillis () + Keyboard.kbdRepeatInterval;  //次にTimer-Kが呼び出されるべき時刻(ms)
   802:         }
   803:       }
   804:     }
   805:     return mfpKbdLastData;  //最後に読み出したデータを返す
   806:   }  //mfpKbdReadData()
   807: 
   808: }  //class MC68901
   809: 
   810: 
   811: