BASIC compiler/interpreter for PIC32MX/MZ-80K (suspended)
| Revision | 148 (tree) |
|---|---|
| Time | 2016-08-05 03:35:13 |
| Author | kmorimatsu |
MachiKania type Z ver 1.00
| @@ -0,0 +1,1861 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by K.Tanaka | |
| 4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
| 5 | +*/ | |
| 6 | + | |
| 7 | +#include <xc.h> | |
| 8 | +#include "api.h" | |
| 9 | +#include "editor.h" | |
| 10 | +#include "keyinput.h" | |
| 11 | +#include "compiler.h" | |
| 12 | +#include "main.h" | |
| 13 | + | |
| 14 | +struct _TBUF{ | |
| 15 | +//リンク付きのテキストバッファ | |
| 16 | + struct _TBUF *prev;//前方へのリンク。NULLの場合先頭または空き | |
| 17 | + struct _TBUF *next;//後方へのリンク。NULLの場合最後 | |
| 18 | + unsigned short n;//現在の使用バイト数 | |
| 19 | + unsigned char Buf[TBUFSIZE];//バッファ | |
| 20 | +} ; | |
| 21 | +typedef struct _TBUF _tbuf; | |
| 22 | + | |
| 23 | +//_tbuf TextBuffer[TBUFMAXLINE]; //テキストバッファ | |
| 24 | +_tbuf *TextBuffer; //実体は配列RAM[]の中に確保する | |
| 25 | + | |
| 26 | +_tbuf *TBufstart; //テキストバッファの先頭位置 | |
| 27 | +_tbuf *cursorbp; //現在のカーソル位置のテキストバッファ | |
| 28 | +unsigned short cursorix; //現在のカーソル位置のテキストバッファ先頭からの位置 | |
| 29 | +_tbuf *disptopbp; //現在表示中画面左上のテキストバッファ | |
| 30 | +unsigned short disptopix; //現在表示中画面左上のテキストバッファ先頭からの位置 | |
| 31 | +int num; //現在バッファ内に格納されている文字数 | |
| 32 | +int cx,cy; //カーソル座標 | |
| 33 | +int cx2; //上下移動時の仮カーソルX座標 | |
| 34 | +_tbuf *cursorbp1; //範囲選択時のカーソルスタート位置のテキストバッファ、範囲選択モードでない場合NULL | |
| 35 | +unsigned short cursorix1; //範囲選択時のカーソルスタート位置のテキストバッファ先頭からの位置 | |
| 36 | +int cx1,cy1; //範囲選択時のカーソルスタート座標 | |
| 37 | + | |
| 38 | +// カーソル関連位置の一時避難用 | |
| 39 | +_tbuf *cursorbp_t; | |
| 40 | +unsigned short cursorix_t; | |
| 41 | +_tbuf *disptopbp_t; | |
| 42 | +unsigned short disptopix_t; | |
| 43 | +int cx_t,cy_t; | |
| 44 | + | |
| 45 | +//unsigned char clipboard[EDITWIDTHX*EDITWIDTHY]; //クリップボード、最大サイズは編集画面領域と同じ | |
| 46 | +unsigned char *clipboard; //実体は配列RAM[]の中に確保する | |
| 47 | + | |
| 48 | +int clipsize; //現在クリップボードに格納されている文字数 | |
| 49 | +int edited; //保存後に変更されたかを表すフラグ | |
| 50 | + | |
| 51 | +//unsigned char filebuf[FILEBUFSIZE]; //ファイルアクセス用バッファ | |
| 52 | +unsigned char *filebuf; //実体は配列RAM[]の中に確保する | |
| 53 | + | |
| 54 | +unsigned char currentfile[13],tempfile[13]; //編集中のファイル名、一時ファイル名 | |
| 55 | + | |
| 56 | +//unsigned char filenames[MAXFILENUM][13]; //ロード時のファイル名一覧バッファ | |
| 57 | +unsigned char (*filenames)[13]; //実体は配列RAM[]の中に確保する | |
| 58 | + | |
| 59 | +const unsigned char Message1[]="Hit Any Key\n"; | |
| 60 | +const unsigned char Message2[]="File System Error\n"; | |
| 61 | +const unsigned char Message3[]="Retry:[Enter] / Quit:[ESC]\n"; | |
| 62 | +void wait60thsec(unsigned short n){ | |
| 63 | + // 60分のn秒ウェイト(ビデオ画面の最下行信号出力終了まで待つ) | |
| 64 | + n+=drawcount; | |
| 65 | + while(drawcount!=n) asm(WAIT); | |
| 66 | +} | |
| 67 | + | |
| 68 | +unsigned int bpixtopos(_tbuf *bp,unsigned int ix){ | |
| 69 | +// テキストバッファ上の位置からテキスト全体の先頭から何文字目かを返す | |
| 70 | +// bp:テキストバッファポインタ | |
| 71 | +// ix:bp->Bufの先頭からの文字数 | |
| 72 | + unsigned int pos; | |
| 73 | + _tbuf *sbp; | |
| 74 | + pos=0; | |
| 75 | + sbp=TBufstart; | |
| 76 | + while(sbp!=bp){ | |
| 77 | + pos+=sbp->n; | |
| 78 | + sbp=sbp->next; | |
| 79 | + if(sbp==NULL) return 0; //エラー | |
| 80 | + } | |
| 81 | + return pos+ix; | |
| 82 | +} | |
| 83 | +_tbuf * postobpix(int pos,unsigned short *pix){ | |
| 84 | +// テキスト全体の先頭からpos文字目のテキストバッファ上の位置を返す | |
| 85 | +// 戻り値 テキストバッファポインタ | |
| 86 | +// *pix(戻り値):戻り値テキストバッファの先頭からの位置(ポインタ渡し) | |
| 87 | + _tbuf *bp; | |
| 88 | + bp=TBufstart; | |
| 89 | + while(pos >= bp->n){ | |
| 90 | + if(bp->next==NULL) break; //全体最後尾の場合 | |
| 91 | + pos-=bp->n; | |
| 92 | + bp=bp->next; | |
| 93 | + } | |
| 94 | + if(pos > bp->n){ | |
| 95 | + // オーバーランエラーの場合先頭を返す | |
| 96 | + *pix=0; | |
| 97 | + return TBufstart; | |
| 98 | + } | |
| 99 | + *pix=pos; | |
| 100 | + return bp; | |
| 101 | +} | |
| 102 | +_tbuf * linetobpix(int line,unsigned short *pix){ | |
| 103 | +// テキスト全体の先頭からline行目のテキストバッファ上の位置を返す | |
| 104 | +// 戻り値 テキストバッファポインタ | |
| 105 | +// *pix(戻り値):戻り値テキストバッファの先頭からの位置(ポインタ渡し) | |
| 106 | + _tbuf *bp,*bp2; | |
| 107 | + int ix,ix2; | |
| 108 | + bp=TBufstart; | |
| 109 | + bp2=TBufstart; | |
| 110 | + ix=0; | |
| 111 | + ix2=0; | |
| 112 | + while(line>1){ | |
| 113 | + while(1){ | |
| 114 | + if(ix>=bp->n){ | |
| 115 | + if(bp->next==NULL) break; | |
| 116 | + bp=bp->next; | |
| 117 | + ix=0; | |
| 118 | + continue; | |
| 119 | + } | |
| 120 | + if(bp->Buf[ix++] == '\n'){ | |
| 121 | + bp2=bp; | |
| 122 | + ix2=ix; | |
| 123 | + break; | |
| 124 | + } | |
| 125 | + } | |
| 126 | + line--; | |
| 127 | + } | |
| 128 | + *pix=ix2; | |
| 129 | + return bp2; | |
| 130 | +} | |
| 131 | + | |
| 132 | +_tbuf * newTBuf(_tbuf *prev){ | |
| 133 | +// 新しいテキストバッファ1行を生成 | |
| 134 | +// prev:挿入先の行(prevの後ろに追加) | |
| 135 | +// 戻り値 生成したバッファへのポインタ、生成できない場合NULL | |
| 136 | + _tbuf *bp,*next; | |
| 137 | + | |
| 138 | + //バッファの先頭から空きをサーチ | |
| 139 | + bp=TextBuffer; | |
| 140 | + while(1){ | |
| 141 | + if(bp->prev==NULL && bp!=TBufstart) break; | |
| 142 | + bp++; | |
| 143 | + if(bp>=TextBuffer+TBUFMAXLINE) return NULL;//最後まで空きなし | |
| 144 | + } | |
| 145 | + next=prev->next; | |
| 146 | + //行挿入 | |
| 147 | + bp->prev=prev; | |
| 148 | + bp->next=next; | |
| 149 | + prev->next=bp; | |
| 150 | + if(next!=NULL) next->prev=bp; | |
| 151 | + bp->n=0; | |
| 152 | + return bp; | |
| 153 | +} | |
| 154 | + | |
| 155 | +_tbuf * deleteTBuf(_tbuf *bp){ | |
| 156 | +// テキストバッファの削除 | |
| 157 | +// bp:削除する行のポインタ | |
| 158 | +// 戻り値 削除前の次のバッファへのポインタ、ない場合NULL | |
| 159 | + unsigned short a,b; | |
| 160 | + _tbuf *prev,*next; | |
| 161 | + prev=bp->prev; | |
| 162 | + next=bp->next; | |
| 163 | + if(prev==NULL){ | |
| 164 | + //先頭行の場合 | |
| 165 | + if(next==NULL) return next; //最後の1行の場合は削除しない | |
| 166 | + TBufstart=next; //次の行を先頭行設定 | |
| 167 | + } | |
| 168 | + else prev->next=next; //前を次にリンク(最終行ならNULLがコピーされる) | |
| 169 | + if(next!=NULL) next->prev=prev; //次があれば次を前にリンク | |
| 170 | + bp->prev=NULL; //空きフラグ設定 | |
| 171 | + return next; | |
| 172 | +} | |
| 173 | + | |
| 174 | +int insertchar(_tbuf *bp,unsigned int ix,unsigned char c){ | |
| 175 | +//テキストバッファbpの先頭からixバイトの位置にcを挿入 | |
| 176 | +//戻り値 成功:0、不正または容量オーバー:-1、空きがあるはずなのに失敗:1 | |
| 177 | + unsigned char *p; | |
| 178 | + | |
| 179 | + if(ix > bp->n) return -1; //不正指定 | |
| 180 | + if(num >= TBUFMAXSIZE) return -1; //バッファ容量オーバー | |
| 181 | + if(bp->n < TBUFSIZE){ | |
| 182 | + //ライン内だけで1バイト挿入可能// | |
| 183 | + for(p=bp->Buf + bp->n ; p > bp->Buf+ix ; p--) *p=*(p-1); | |
| 184 | + *p=c; | |
| 185 | + bp->n++; | |
| 186 | + num++; //バッファ使用量 | |
| 187 | +// if(bp->n >= TBUFSIZE && bp->next==NULL) newTBuf(bp); //バッファがいっぱいになったら新たにバッファ生成 | |
| 188 | + return 0; | |
| 189 | + } | |
| 190 | + //ラインがあふれる場合 | |
| 191 | + if(bp->next==NULL || bp->next->n >=TBUFSIZE){ | |
| 192 | + // 最終行または次のラインバッファがいっぱいだったら一行挿入 | |
| 193 | + if(newTBuf(bp)==NULL){ | |
| 194 | + // ラインバッファ挿入不可 | |
| 195 | + return 1; | |
| 196 | + } | |
| 197 | + } | |
| 198 | + if(ix==TBUFSIZE){ | |
| 199 | + insertchar(bp->next,0,c); | |
| 200 | + return 0; | |
| 201 | + } | |
| 202 | + p=bp->Buf + TBUFSIZE-1; | |
| 203 | + insertchar(bp->next,0,*p); //次の行の先頭に1文字挿入(必ず空きあり) | |
| 204 | + for( ; p > bp->Buf+ix ; p--) *p=*(p-1); | |
| 205 | + *p=c; | |
| 206 | + return 0; | |
| 207 | +} | |
| 208 | + | |
| 209 | +int overwritechar(_tbuf *bp,unsigned int ix,unsigned char c){ | |
| 210 | +//テキストバッファbpの先頭からixバイトの位置をcで上書き | |
| 211 | +//戻り値 成功:0、不正または容量オーバー:-1、空きがあるはずなのに失敗:1 | |
| 212 | + | |
| 213 | + //現在のバッファ位置の文字が終端または改行の場合、挿入モード | |
| 214 | + if(ix > bp->n) return -1; //不正指定 | |
| 215 | + while(ix >= bp->n){ | |
| 216 | + if(bp->next==NULL){ | |
| 217 | + //テキスト全体最後尾の場合は挿入 | |
| 218 | + return insertchar(bp,ix,c); | |
| 219 | + } | |
| 220 | + bp=bp->next; | |
| 221 | + ix=0; | |
| 222 | + } | |
| 223 | + if(bp->Buf[ix]=='\n') return insertchar(bp,ix,c); | |
| 224 | + else bp->Buf[ix]=c; | |
| 225 | + return 0; | |
| 226 | +} | |
| 227 | + | |
| 228 | +void deletechar(_tbuf *bp,unsigned int ix){ | |
| 229 | +//テキストバッファbpの先頭からkバイトの位置の1バイト削除 | |
| 230 | + unsigned char *p; | |
| 231 | + | |
| 232 | + if(ix > bp->n) return; //不正指定 | |
| 233 | + if(ix !=bp->n){ | |
| 234 | + //バッファの最後の文字より後ろでない場合 | |
| 235 | + for(p=bp->Buf+ix ; p< bp->Buf + bp->n-1 ; p++) *p=*(p+1); | |
| 236 | + bp->n--; | |
| 237 | + num--; //バッファ使用量 | |
| 238 | + return; | |
| 239 | + } | |
| 240 | + //行バッファの現在の最後の場合(削除する文字がない場合) | |
| 241 | + if(bp->next==NULL) return; //全体の最後の場合、何もしない | |
| 242 | + deletechar(bp->next,0); //次の行の先頭文字を削除 | |
| 243 | +} | |
| 244 | +int gabagecollect1(void){ | |
| 245 | +//断片化されたテキストバッファの隙間を埋めるガベージコレクション | |
| 246 | +//カーソルの前と後ろそれぞれ探索して最初の1バイト分のみ実施 | |
| 247 | +//戻り値 1バイトでも移動した場合:1、なかった場合:0 | |
| 248 | + | |
| 249 | + _tbuf *bp; | |
| 250 | + int f=0; | |
| 251 | + unsigned char *p,*p2; | |
| 252 | + | |
| 253 | + //カーソルがバッファの先頭にある場合、前のバッファの最後尾に変更 | |
| 254 | + //(ただし前に空きがない場合と先頭バッファの場合を除く) | |
| 255 | + while(cursorix==0 && cursorbp->prev!=NULL && cursorbp->prev->n <TBUFSIZE){ | |
| 256 | + cursorbp=cursorbp->prev; | |
| 257 | + cursorix=cursorbp->n; | |
| 258 | + } | |
| 259 | + //画面左上位置がバッファの先頭にある場合、前のバッファの最後尾に変更 | |
| 260 | + //(ただし先頭バッファの場合を除く) | |
| 261 | + while(disptopix==0 && disptopbp->prev!=NULL){ | |
| 262 | + disptopbp=disptopbp->prev; | |
| 263 | + disptopix=disptopbp->n; | |
| 264 | + } | |
| 265 | + //カーソルのあるバッファ以外の空バッファを全て削除 | |
| 266 | + bp=TBufstart; | |
| 267 | + while(bp!=NULL){ | |
| 268 | + if(bp->n == 0 && bp!=cursorbp) bp=deleteTBuf(bp); //空きバッファ削除 | |
| 269 | + else bp=bp->next; | |
| 270 | + } | |
| 271 | + | |
| 272 | + //カーソル位置より前の埋まっていないバッファを先頭からサーチ | |
| 273 | + bp=TBufstart; | |
| 274 | + while(bp->n >= TBUFSIZE){ | |
| 275 | + if(bp==cursorbp) break; | |
| 276 | + bp=bp->next; | |
| 277 | + } | |
| 278 | + if(bp!=cursorbp){ | |
| 279 | + //最初に見つけた空き場所に次のバッファから1バイト移動 | |
| 280 | + bp->Buf[bp->n++] = bp->next->Buf[0]; | |
| 281 | + bp=bp->next; | |
| 282 | + p=bp->Buf; | |
| 283 | + p2=p+bp->n-1; | |
| 284 | + for( ; p<p2 ; p++) *p=*(p+1); | |
| 285 | + bp->n--; | |
| 286 | + f=1; | |
| 287 | + if(bp == disptopbp) disptopix--; | |
| 288 | + if(bp == cursorbp) cursorix--; | |
| 289 | +// else if(bp->n == 0) deleteTBuf(bp); | |
| 290 | + } | |
| 291 | + if(cursorbp->next ==NULL) return f; //カーソル位置が最終バッファなら終了 | |
| 292 | + //カーソル位置の次のバッファから埋まっていないバッファをサーチ | |
| 293 | + bp=cursorbp; | |
| 294 | + do{ | |
| 295 | + bp=bp->next; | |
| 296 | + if(bp->next ==NULL) return f; //最終バッファに到達なら終了 | |
| 297 | + } while(bp->n >=TBUFSIZE); | |
| 298 | + | |
| 299 | + //最初に見つけた空き場所に次のバッファから1バイト移動 | |
| 300 | + bp->Buf[bp->n++] = bp->next->Buf[0]; | |
| 301 | + bp=bp->next; | |
| 302 | + p=bp->Buf; | |
| 303 | + p2=p+bp->n-1; | |
| 304 | + for( ; p<p2 ; p++) *p=*(p+1); | |
| 305 | + bp->n--; | |
| 306 | + f=1; | |
| 307 | + if(bp->n == 0) deleteTBuf(bp); | |
| 308 | + return f; | |
| 309 | +} | |
| 310 | +void gabagecollect2(void){ | |
| 311 | +// 変化がなくなるまで1バイト分のガベージコレクションを呼び出し | |
| 312 | + while(gabagecollect1()) ; | |
| 313 | +} | |
| 314 | +void inittextbuf(void){ | |
| 315 | +// テキストバッファの初期化 | |
| 316 | + _tbuf *bp; | |
| 317 | + for(bp=TextBuffer;bp<TextBuffer+TBUFMAXLINE;bp++) bp->prev=NULL; //未使用バッファ化 | |
| 318 | + TBufstart=TextBuffer; //リンクの先頭設定 | |
| 319 | + TBufstart->next=NULL; | |
| 320 | + TBufstart->n=0; | |
| 321 | + num=0; //バッファ使用量 | |
| 322 | + edited=0; //編集済みフラグクリア | |
| 323 | +} | |
| 324 | +void redraw(){ | |
| 325 | +//画面の再描画 | |
| 326 | + unsigned char *vp; | |
| 327 | + _tbuf *bp,*bp1,*bp2; | |
| 328 | + int ix,ix1,ix2; | |
| 329 | + int x,y; | |
| 330 | + unsigned char ch,cl; | |
| 331 | + | |
| 332 | + vp=TVRAM; | |
| 333 | + bp=disptopbp; | |
| 334 | + ix=disptopix; | |
| 335 | + cl=COLOR_NORMALTEXT; | |
| 336 | + if(cursorbp1==NULL){ | |
| 337 | + //範囲選択モードでない場合 | |
| 338 | + bp1=NULL; | |
| 339 | + bp2=NULL; | |
| 340 | + } | |
| 341 | + else{ | |
| 342 | + //範囲選択モードの場合、開始位置と終了の前後判断して | |
| 343 | + //bp1,ix1を開始位置、bp2,ix2を終了位置に設定 | |
| 344 | + if(cy<cy1 || (cy==cy1 && cx<cx1)){ | |
| 345 | + bp1=cursorbp; | |
| 346 | + ix1=cursorix; | |
| 347 | + bp2=cursorbp1; | |
| 348 | + ix2=cursorix1; | |
| 349 | + } | |
| 350 | + else{ | |
| 351 | + bp1=cursorbp1; | |
| 352 | + ix1=cursorix1; | |
| 353 | + bp2=cursorbp; | |
| 354 | + ix2=cursorix; | |
| 355 | + } | |
| 356 | + } | |
| 357 | + for(y=0;y<EDITWIDTHY;y++){ | |
| 358 | + if(bp==NULL) break; | |
| 359 | + for(x=0;x<EDITWIDTHX;x++){ | |
| 360 | + //文字がある位置までサーチ | |
| 361 | + while(ix>=bp->n){ | |
| 362 | + if(bp==bp1 && ix==ix1) cl=COLOR_AREASELECTTEXT; | |
| 363 | + if(bp==bp2 && ix==ix2) cl=COLOR_NORMALTEXT; | |
| 364 | + bp=bp->next; | |
| 365 | + ix=0; | |
| 366 | + if(bp==NULL) break; | |
| 367 | + } | |
| 368 | + if(bp==NULL) break; //バッファ最終 | |
| 369 | + if(bp==bp1 && ix==ix1) cl=COLOR_AREASELECTTEXT; | |
| 370 | + if(bp==bp2 && ix==ix2) cl=COLOR_NORMALTEXT; | |
| 371 | + ch=bp->Buf[ix++]; | |
| 372 | + if(ch=='\n') break; | |
| 373 | + *(vp+ATTROFFSET)=cl; | |
| 374 | + *vp++=ch; | |
| 375 | + } | |
| 376 | + //改行およびバッファ最終以降の右側表示消去 | |
| 377 | + for(;x<EDITWIDTHX;x++){ | |
| 378 | + *(vp+ATTROFFSET)=0; | |
| 379 | + *vp++=0; | |
| 380 | + } | |
| 381 | + } | |
| 382 | + //バッファ最終以降の下側表示消去 | |
| 383 | + for(;y<EDITWIDTHY;y++){ | |
| 384 | + for(x=0;x<EDITWIDTHX;x++){ | |
| 385 | + *(vp+ATTROFFSET)=0; | |
| 386 | + *vp++=0; | |
| 387 | + } | |
| 388 | + } | |
| 389 | +} | |
| 390 | + | |
| 391 | +void cursor_left(void){ | |
| 392 | +//カーソルを1つ前に移動 | |
| 393 | +//出力:下記変数を移動先の値に変更 | |
| 394 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
| 395 | +//cx,cy 画面上のカーソル位置 | |
| 396 | +//cx2 cxと同じ | |
| 397 | +//disptopbp,disptopix 画面左上のバッファ上の位置 | |
| 398 | + | |
| 399 | + _tbuf *bp; | |
| 400 | + int ix; | |
| 401 | + int i; | |
| 402 | + int x; | |
| 403 | + | |
| 404 | + //バッファ上のカーソル位置を1つ前に移動 | |
| 405 | + if(cursorix!=0) cursorix--; | |
| 406 | + else while(1) { | |
| 407 | + //1つ前のバッファの最後尾に移動、ただし空バッファは飛ばす | |
| 408 | + if(cursorbp->prev==NULL) return; //テキスト全体先頭なので移動しない | |
| 409 | + cursorbp=cursorbp->prev; | |
| 410 | + if(cursorbp->n >0){ | |
| 411 | + cursorix=cursorbp->n-1;//バッファ最後尾 | |
| 412 | + break; | |
| 413 | + } | |
| 414 | + } | |
| 415 | + | |
| 416 | + //カーソルおよび画面左上位置の更新 | |
| 417 | + if(cx>0){ | |
| 418 | + //左端でなければカーソルを単純に1つ左に移動して終了 | |
| 419 | + cx--; | |
| 420 | + cx2=cx; | |
| 421 | + return; | |
| 422 | + } | |
| 423 | + if(cy>0){ | |
| 424 | + //左端だが上端ではない場合 | |
| 425 | + if(cursorbp->Buf[cursorix]!='\n'){ | |
| 426 | + // 移動先が改行コードでない場合、カーソルは1つ上の行の右端に移動 | |
| 427 | + cx=EDITWIDTHX-1; | |
| 428 | + cx2=cx; | |
| 429 | + cy--; | |
| 430 | + return; | |
| 431 | + } | |
| 432 | + //画面左上位置から最後尾のX座標をサーチ | |
| 433 | + bp=disptopbp; | |
| 434 | + ix=disptopix; | |
| 435 | + x=0; | |
| 436 | + while(ix!=cursorix || bp!=cursorbp){ | |
| 437 | + if(bp->n==0){ | |
| 438 | + //空バッファの場合次へ | |
| 439 | + bp=bp->next; | |
| 440 | + ix=0; | |
| 441 | + continue; | |
| 442 | + } | |
| 443 | + if(bp->Buf[ix++]=='\n' || x>=EDITWIDTHX-1) x=0; | |
| 444 | + else x++; | |
| 445 | + if(ix >= bp->n){ | |
| 446 | + bp=bp->next; | |
| 447 | + ix=0; | |
| 448 | + } | |
| 449 | + } | |
| 450 | + cx=x; | |
| 451 | + cx2=cx; | |
| 452 | + cy--; | |
| 453 | + return; | |
| 454 | + } | |
| 455 | + | |
| 456 | + //左端かつ上端の場合 | |
| 457 | + if(cursorbp->Buf[cursorix]!='\n'){ | |
| 458 | + // 移動先が改行コードでない場合、カーソルは右端に移動 | |
| 459 | + // 画面左上位置は画面横幅分前に移動 | |
| 460 | + cx=EDITWIDTHX-1; | |
| 461 | + cx2=cx; | |
| 462 | + } | |
| 463 | + else{ | |
| 464 | + //移動先が改行コードの場合 | |
| 465 | + //行頭(改行の次の文字またはバッファ先頭)と現在位置の文字数差を | |
| 466 | + //画面横幅で割った余りがカーソルX座標 | |
| 467 | + bp=cursorbp; | |
| 468 | + ix=cursorix; | |
| 469 | + i=0; | |
| 470 | + while(1){ | |
| 471 | + if(ix==0){ | |
| 472 | + if(bp->prev==NULL) break; | |
| 473 | + bp=bp->prev; | |
| 474 | + ix=bp->n; | |
| 475 | + continue; | |
| 476 | + } | |
| 477 | + ix--; | |
| 478 | + if(bp->Buf[ix]=='\n') break; | |
| 479 | + i++; | |
| 480 | + } | |
| 481 | + cx=i % EDITWIDTHX; | |
| 482 | + cx2=cx; | |
| 483 | + } | |
| 484 | + //画面左上位置は現在位置からX座標分引いたところ | |
| 485 | + bp=cursorbp; | |
| 486 | + ix=cursorix; | |
| 487 | + x=cx; | |
| 488 | + while(x>0){ | |
| 489 | + if(ix==0){ | |
| 490 | + bp=bp->prev; | |
| 491 | + ix=bp->n; | |
| 492 | + continue; | |
| 493 | + } | |
| 494 | + ix--; | |
| 495 | + x--; | |
| 496 | + } | |
| 497 | + disptopbp=bp; | |
| 498 | + disptopix=ix; | |
| 499 | +} | |
| 500 | +void cursor_right(void){ | |
| 501 | +//カーソルを1つ後ろに移動 | |
| 502 | +//出力:下記変数を移動先の値に変更 | |
| 503 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
| 504 | +//cx,cy 画面上のカーソル位置 | |
| 505 | +//cx2 cxと同じ | |
| 506 | +//disptopbp,disptopix 画面左上のバッファ上の位置 | |
| 507 | + | |
| 508 | + _tbuf *bp; | |
| 509 | + int ix; | |
| 510 | + int i; | |
| 511 | + int x; | |
| 512 | + unsigned char c; | |
| 513 | + | |
| 514 | + if(cursorix >= cursorbp->n){ | |
| 515 | + //バッファ最後尾の場合、次の先頭に移動 | |
| 516 | + bp=cursorbp; | |
| 517 | + while(1) { | |
| 518 | + //空バッファは飛ばす | |
| 519 | + if(bp->next==NULL) return; //テキスト全体最後尾なので移動しない | |
| 520 | + bp=bp->next; | |
| 521 | + if(bp->n >0) break; | |
| 522 | + } | |
| 523 | + cursorbp=bp; | |
| 524 | + cursorix=0;//バッファ先頭 | |
| 525 | + } | |
| 526 | + c=cursorbp->Buf[cursorix++]; //バッファ上のカーソル位置のコードを読んで1つ後ろに移動 | |
| 527 | + if(c!='\n' && cx<EDITWIDTHX-1){ | |
| 528 | + //カーソル位置が改行でも右端でもない場合単純に1つ右に移動して終了 | |
| 529 | + cx++; | |
| 530 | + cx2=cx; | |
| 531 | + return; | |
| 532 | + } | |
| 533 | + cx=0; //カーソルを右端に移動 | |
| 534 | + cx2=cx; | |
| 535 | + if(cy<EDITWIDTHY-1){ | |
| 536 | + //下端でなければカーソルを次行に移動して終了 | |
| 537 | + cy++; | |
| 538 | + return; | |
| 539 | + } | |
| 540 | + //下端の場合 | |
| 541 | + //画面左上位置を更新 | |
| 542 | + //改行コードまたは画面横幅超えるまでサーチ | |
| 543 | + bp=disptopbp; | |
| 544 | + ix=disptopix; | |
| 545 | + x=0; | |
| 546 | + while(x<EDITWIDTHX){ | |
| 547 | + if(ix >= bp->n){ | |
| 548 | + bp=bp->next; | |
| 549 | + ix=0; | |
| 550 | + continue; | |
| 551 | + } | |
| 552 | + if(bp->Buf[ix++]=='\n') break; | |
| 553 | + x++; | |
| 554 | + } | |
| 555 | + disptopbp=bp; | |
| 556 | + disptopix=ix; | |
| 557 | +} | |
| 558 | +void cursor_up(void){ | |
| 559 | +//カーソルを1つ上に移動 | |
| 560 | +//出力:下記変数を移動先の値に変更 | |
| 561 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
| 562 | +//cx,cy 画面上のカーソル位置 | |
| 563 | +//cx2 移動前のcxと同じ | |
| 564 | +//disptopbp,disptopix 画面左上のバッファ上の位置 | |
| 565 | + | |
| 566 | + _tbuf *bp; | |
| 567 | + int ix; | |
| 568 | + int i; | |
| 569 | + int x; | |
| 570 | + unsigned char c; | |
| 571 | + | |
| 572 | + //画面幅分前に戻ったところがバッファ上カーソルの移動先 | |
| 573 | + //途中で改行コードがあれば別の手段で検索 | |
| 574 | + bp=cursorbp; | |
| 575 | + ix=cursorix; | |
| 576 | + i=cx2-cx; | |
| 577 | + while(i<EDITWIDTHX){ | |
| 578 | + if(ix==0){ | |
| 579 | + if(bp->prev==NULL) return; //バッファ先頭までサーチしたら移動なし | |
| 580 | + bp=bp->prev; | |
| 581 | + ix=bp->n; | |
| 582 | + continue; | |
| 583 | + } | |
| 584 | + ix--; | |
| 585 | + if(bp->Buf[ix]=='\n') break; | |
| 586 | + i++; | |
| 587 | + } | |
| 588 | + cursorbp=bp; | |
| 589 | + cursorix=ix; | |
| 590 | + //画面幅の間に改行コードがなかった場合 | |
| 591 | + if(i==EDITWIDTHX){ | |
| 592 | + cx=cx2; | |
| 593 | + //画面上端でなければカーソルを1つ上に移動して終了 | |
| 594 | + if(cy>0){ | |
| 595 | + cy--; | |
| 596 | + return; | |
| 597 | + } | |
| 598 | + //画面上端の場合、カーソル位置からX座標分戻ったところが画面左上位置 | |
| 599 | + x=cx; | |
| 600 | + while(x>0){ | |
| 601 | + if(ix==0){ | |
| 602 | + bp=bp->prev; | |
| 603 | + ix=bp->n; | |
| 604 | + continue; | |
| 605 | + } | |
| 606 | + ix--; | |
| 607 | + x--; | |
| 608 | + } | |
| 609 | + disptopbp=bp; | |
| 610 | + disptopix=ix; | |
| 611 | + return; | |
| 612 | + } | |
| 613 | + //改行が見つかった場合 | |
| 614 | + //行頭(改行の次の文字またはバッファ先頭)と現在位置の文字数差を | |
| 615 | + //画面横幅で割った余りを求める | |
| 616 | + i=0; | |
| 617 | + while(1){ | |
| 618 | + if(ix==0){ | |
| 619 | + if(bp->prev==NULL) break; | |
| 620 | + bp=bp->prev; | |
| 621 | + ix=bp->n; | |
| 622 | + continue; | |
| 623 | + } | |
| 624 | + ix--; | |
| 625 | + if(bp->Buf[ix]=='\n') break; | |
| 626 | + i++; | |
| 627 | + } | |
| 628 | + x=i % EDITWIDTHX; //改行ブロックの最終行の右端 | |
| 629 | + bp=cursorbp; | |
| 630 | + ix=cursorix; | |
| 631 | + //バッファ上のカーソル位置は改行ブロックの最終行右端からカーソルX座標分戻る | |
| 632 | + //最終行右端のほうが小さい場合、その場所をバッファ上のカーソル位置とする | |
| 633 | + while(x>cx2){ | |
| 634 | + if(ix==0){ | |
| 635 | + bp=bp->prev; | |
| 636 | + ix=bp->n; | |
| 637 | + continue; | |
| 638 | + } | |
| 639 | + ix--; | |
| 640 | + x--; | |
| 641 | + } | |
| 642 | + cursorbp=bp; | |
| 643 | + cursorix=ix; | |
| 644 | + cx=x; //cx2または改行ブロック最終行右端 | |
| 645 | + if(cy>0){ | |
| 646 | + //画面上端でなければカーソルを1つ上に移動して終了 | |
| 647 | + cy--; | |
| 648 | + return; | |
| 649 | + } | |
| 650 | + //画面上端の場合 | |
| 651 | + //画面左上位置は現在位置からX座標分引いたところ | |
| 652 | + while(x>0){ | |
| 653 | + if(ix==0){ | |
| 654 | + bp=bp->prev; | |
| 655 | + ix=bp->n; | |
| 656 | + continue; | |
| 657 | + } | |
| 658 | + ix--; | |
| 659 | + x--; | |
| 660 | + } | |
| 661 | + disptopbp=bp; | |
| 662 | + disptopix=ix; | |
| 663 | +} | |
| 664 | +void cursor_down(void){ | |
| 665 | +//カーソルを1つ下に移動 | |
| 666 | +//出力:下記変数を移動先の値に変更 | |
| 667 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
| 668 | +//cx,cy 画面上のカーソル位置 | |
| 669 | +//cx2 移動前のcxと同じ | |
| 670 | +//disptopbp,disptopix 画面左上のバッファ上の位置 | |
| 671 | + | |
| 672 | + _tbuf *bp; | |
| 673 | + int ix; | |
| 674 | + int x; | |
| 675 | + unsigned char c; | |
| 676 | + | |
| 677 | + //次行の先頭サーチ | |
| 678 | + //カーソル位置から画面右端までの間に改行コードがあれば次の文字が先頭 | |
| 679 | + bp=cursorbp; | |
| 680 | + ix=cursorix; | |
| 681 | + x=cx; | |
| 682 | + while(x<EDITWIDTHX){ | |
| 683 | + if(ix>=bp->n){ | |
| 684 | + if(bp->next==NULL) return; //バッファ最後までサーチしたら移動なし | |
| 685 | + bp=bp->next; | |
| 686 | + ix=0; | |
| 687 | + continue; | |
| 688 | + } | |
| 689 | + c=bp->Buf[ix]; | |
| 690 | + ix++; | |
| 691 | + x++; | |
| 692 | + if(c=='\n') break; | |
| 693 | + } | |
| 694 | + //次行先頭からcx2文字数分後ろにサーチ | |
| 695 | + x=0; | |
| 696 | + while(x<cx2){ | |
| 697 | + if(ix>=bp->n){ | |
| 698 | + if(bp->next==NULL) break; //バッファ最後の場合そこに移動 | |
| 699 | + bp=bp->next; | |
| 700 | + ix=0; | |
| 701 | + continue; | |
| 702 | + } | |
| 703 | + if(bp->Buf[ix]=='\n') break; //改行コードの場合そこに移動 | |
| 704 | + ix++; | |
| 705 | + x++; | |
| 706 | + } | |
| 707 | + cursorbp=bp; | |
| 708 | + cursorix=ix; | |
| 709 | + cx=x; | |
| 710 | + //画面下端でなければカーソルを1つ下に移動して終了 | |
| 711 | + if(cy<EDITWIDTHY-1){ | |
| 712 | + cy++; | |
| 713 | + return; | |
| 714 | + } | |
| 715 | + //下端の場合 | |
| 716 | + //画面左上位置を更新 | |
| 717 | + //改行コードまたは画面横幅超えるまでサーチ | |
| 718 | + bp=disptopbp; | |
| 719 | + ix=disptopix; | |
| 720 | + x=0; | |
| 721 | + while(x<EDITWIDTHX){ | |
| 722 | + if(ix >= bp->n){ | |
| 723 | + bp=bp->next; | |
| 724 | + ix=0; | |
| 725 | + continue; | |
| 726 | + } | |
| 727 | + if(bp->Buf[ix++]=='\n') break; | |
| 728 | + x++; | |
| 729 | + } | |
| 730 | + disptopbp=bp; | |
| 731 | + disptopix=ix; | |
| 732 | +} | |
| 733 | +void cursor_home(void){ | |
| 734 | +//カーソルを行先頭に移動 | |
| 735 | +//出力:下記変数を移動先の値に変更 | |
| 736 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
| 737 | +//cx,cx2 0 | |
| 738 | +//cy 変更なし | |
| 739 | +//disptopbp,disptopix 画面左上のバッファ上の位置(変更なし) | |
| 740 | + | |
| 741 | + //カーソルX座標分前に移動 | |
| 742 | + while(cx>0){ | |
| 743 | + if(cursorix==0){ | |
| 744 | + //空バッファは飛ばす | |
| 745 | + cursorbp=cursorbp->prev; | |
| 746 | + cursorix=cursorbp->n; | |
| 747 | + continue; | |
| 748 | + } | |
| 749 | + cursorix--; | |
| 750 | + cx--; | |
| 751 | + } | |
| 752 | + cx2=0; | |
| 753 | +} | |
| 754 | +void cursor_end(void){ | |
| 755 | +//カーソルを行末に移動 | |
| 756 | +//出力:下記変数を移動先の値に変更 | |
| 757 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
| 758 | +//cx,cx2 行末 | |
| 759 | +//cy 変更なし | |
| 760 | +//disptopbp,disptopix 画面左上のバッファ上の位置(変更なし) | |
| 761 | + | |
| 762 | + //カーソルX座標を画面幅分後ろに移動 | |
| 763 | + //改行コードまたはバッファ最終があればそこに移動 | |
| 764 | + while(cx<EDITWIDTHX-1){ | |
| 765 | + if(cursorix>=cursorbp->n){ | |
| 766 | + //空バッファは飛ばす | |
| 767 | + if(cursorbp->next==NULL) break; | |
| 768 | + cursorbp=cursorbp->next; | |
| 769 | + cursorix=0; | |
| 770 | + continue; | |
| 771 | + } | |
| 772 | + if(cursorbp->Buf[cursorix]=='\n') break; | |
| 773 | + cursorix++; | |
| 774 | + cx++; | |
| 775 | + } | |
| 776 | + cx2=cx; | |
| 777 | +} | |
| 778 | +void cursor_pageup(void){ | |
| 779 | +//PageUpキー | |
| 780 | +//最上行が最下行になるまでスクロール | |
| 781 | +//出力:下記変数を移動先の値に変更 | |
| 782 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
| 783 | +//cx,cx2 | |
| 784 | +//cy | |
| 785 | +//disptopbp,disptopix 画面左上のバッファ上の位置 | |
| 786 | + | |
| 787 | + _tbuf *bp; | |
| 788 | + int ix; | |
| 789 | + int i; | |
| 790 | + int cy_old; | |
| 791 | + | |
| 792 | + cy_old=cy; | |
| 793 | + while(cy>0) cursor_up(); // cy==0になるまでカーソルを上に移動 | |
| 794 | + for(i=0;i<EDITWIDTHY-1;i++){ | |
| 795 | + //画面行数-1行分カーソルを上に移動 | |
| 796 | + bp=disptopbp; | |
| 797 | + ix=disptopix; | |
| 798 | + cursor_up(); | |
| 799 | + if(bp==disptopbp && ix==disptopix) break; //最上行で移動できなかった場合抜ける | |
| 800 | + } | |
| 801 | + //元のY座標までカーソルを下に移動、1行も動かなかった場合は最上行に留まる | |
| 802 | + if(i>0) while(cy<cy_old) cursor_down(); | |
| 803 | +} | |
| 804 | +void cursor_pagedown(void){ | |
| 805 | +//PageDownキー | |
| 806 | +//最下行が最上行になるまでスクロール | |
| 807 | +//出力:下記変数を移動先の値に変更 | |
| 808 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
| 809 | +//cx,cx2 | |
| 810 | +//cy | |
| 811 | +//disptopbp,disptopix 画面左上のバッファ上の位置 | |
| 812 | + | |
| 813 | + _tbuf *bp; | |
| 814 | + int ix; | |
| 815 | + int i; | |
| 816 | + int y; | |
| 817 | + int cy_old; | |
| 818 | + | |
| 819 | + cy_old=cy; | |
| 820 | + while(cy<EDITWIDTHY-1){ | |
| 821 | + // cy==EDITWIDTH-1になるまでカーソルを下に移動 | |
| 822 | + y=cy; | |
| 823 | + cursor_down(); | |
| 824 | + if(y==cy) break;// バッファ最下行で移動できなかった場合抜ける | |
| 825 | + } | |
| 826 | + for(i=0;i<EDITWIDTHY-1;i++){ | |
| 827 | + //画面行数-1行分カーソルを下に移動 | |
| 828 | + bp=disptopbp; | |
| 829 | + ix=disptopix; | |
| 830 | + cursor_down(); | |
| 831 | + if(bp==disptopbp && ix==disptopix) break; //最下行で移動できなかった場合抜ける | |
| 832 | + } | |
| 833 | + //下端からさらに移動した行数分、カーソルを上に移動、1行も動かなかった場合は最下行に留まる | |
| 834 | + if(i>0) while(cy>cy_old) cursor_up(); | |
| 835 | +} | |
| 836 | +void cursor_top(void){ | |
| 837 | +//カーソルをテキストバッファの先頭に移動 | |
| 838 | + cursorbp=TBufstart; | |
| 839 | + cursorix=0; | |
| 840 | + cursorbp1=NULL; //範囲選択モード解除 | |
| 841 | + disptopbp=cursorbp; | |
| 842 | + disptopix=cursorix; | |
| 843 | + cx=0; | |
| 844 | + cx2=0; | |
| 845 | + cy=0; | |
| 846 | +} | |
| 847 | + | |
| 848 | +int countarea(void){ | |
| 849 | +//テキストバッファの指定範囲の文字数をカウント | |
| 850 | +//範囲は(cursorbp,cursorix)と(cursorbp1,cursorix1)で指定 | |
| 851 | +//後ろ側の一つ前の文字までをカウント | |
| 852 | + _tbuf *bp1,*bp2; | |
| 853 | + int ix1,ix2; | |
| 854 | + int n; | |
| 855 | + | |
| 856 | + //範囲選択モードの場合、開始位置と終了の前後判断して | |
| 857 | + //bp1,ix1を開始位置、bp2,ix2を終了位置に設定 | |
| 858 | + if(cy<cy1 || (cy==cy1 && cx<cx1)){ | |
| 859 | + bp1=cursorbp; | |
| 860 | + ix1=cursorix; | |
| 861 | + bp2=cursorbp1; | |
| 862 | + ix2=cursorix1; | |
| 863 | + } | |
| 864 | + else{ | |
| 865 | + bp1=cursorbp1; | |
| 866 | + ix1=cursorix1; | |
| 867 | + bp2=cursorbp; | |
| 868 | + ix2=cursorix; | |
| 869 | + } | |
| 870 | + n=0; | |
| 871 | + while(1){ | |
| 872 | + if(bp1==bp2 && ix1==ix2) return n; | |
| 873 | + if(ix1 < bp1->n){ | |
| 874 | + n++; | |
| 875 | + ix1++; | |
| 876 | + } | |
| 877 | + else{ | |
| 878 | + bp1=bp1->next; | |
| 879 | + ix1=0; | |
| 880 | + } | |
| 881 | + } | |
| 882 | +} | |
| 883 | +void deletearea(void){ | |
| 884 | +//テキストバッファの指定範囲を削除 | |
| 885 | +//範囲は(cursorbp,cursorix)と(cursorbp1,cursorix1)で指定 | |
| 886 | +//後ろ側の一つ前の文字までを削除 | |
| 887 | +//削除後のカーソル位置は選択範囲の先頭にし、範囲選択モード解除する | |
| 888 | + | |
| 889 | + _tbuf *bp; | |
| 890 | + int ix; | |
| 891 | + int n; | |
| 892 | + | |
| 893 | + n=countarea(); //選択範囲の文字数カウント | |
| 894 | + | |
| 895 | + //範囲選択の開始位置と終了位置の前後を判断してカーソルを開始位置に設定 | |
| 896 | + if(cy>cy1 || (cy==cy1 && cx>cx1)){ | |
| 897 | + cursorbp=cursorbp1; | |
| 898 | + cursorix=cursorix1; | |
| 899 | + cx=cx1; | |
| 900 | + cy=cy1; | |
| 901 | + } | |
| 902 | + cx2=cx; | |
| 903 | + cursorbp1=NULL; //範囲選択モード解除 | |
| 904 | + | |
| 905 | + //bp,ixを開始位置に設定 | |
| 906 | + bp=cursorbp; | |
| 907 | + ix=cursorix; | |
| 908 | + | |
| 909 | + //選択範囲が最初のバッファの最後まである場合 | |
| 910 | + if(n>=(bp->n - ix)){ | |
| 911 | + n -= bp->n - ix; //削除文字数減 | |
| 912 | + num-=bp->n - ix; //バッファ使用量を減数 | |
| 913 | + bp->n=ix; //ix以降を削除 | |
| 914 | + bp=bp->next; | |
| 915 | + if(bp==NULL) return; | |
| 916 | + ix=0; | |
| 917 | + } | |
| 918 | + //次のバッファ以降、選択範囲の終了位置が含まれないバッファは削除 | |
| 919 | + while(n>=bp->n){ | |
| 920 | + n-=bp->n; //削除文字数減 | |
| 921 | + num-=bp->n; //バッファ使用量を減数 | |
| 922 | + bp=deleteTBuf(bp); //バッファ削除して次のバッファに進む | |
| 923 | + if(bp==NULL) return; | |
| 924 | + } | |
| 925 | + //選択範囲の終了位置を含む場合、1文字ずつ削除 | |
| 926 | + while(n>0){ | |
| 927 | + deletechar(bp,ix); //バッファから1文字削除(numは関数内で1減される) | |
| 928 | + n--; | |
| 929 | + } | |
| 930 | +} | |
| 931 | +void clipcopy(void){ | |
| 932 | +// 選択範囲をクリップボードにコピー | |
| 933 | + _tbuf *bp1,*bp2; | |
| 934 | + int ix1,ix2; | |
| 935 | + char *ps,*pd; | |
| 936 | + | |
| 937 | + //範囲選択モードの場合、開始位置と終了の前後判断して | |
| 938 | + //bp1,ix1を開始位置、bp2,ix2を終了位置に設定 | |
| 939 | + if(cy<cy1 || (cy==cy1 && cx<cx1)){ | |
| 940 | + bp1=cursorbp; | |
| 941 | + ix1=cursorix; | |
| 942 | + bp2=cursorbp1; | |
| 943 | + ix2=cursorix1; | |
| 944 | + } | |
| 945 | + else{ | |
| 946 | + bp1=cursorbp1; | |
| 947 | + ix1=cursorix1; | |
| 948 | + bp2=cursorbp; | |
| 949 | + ix2=cursorix; | |
| 950 | + } | |
| 951 | + ps=bp1->Buf+ix1; | |
| 952 | + pd=clipboard; | |
| 953 | + clipsize=0; | |
| 954 | + while(bp1!=bp2 || ix1!=ix2){ | |
| 955 | + if(ix1 < bp1->n){ | |
| 956 | + *pd++=*ps++; | |
| 957 | + clipsize++; | |
| 958 | + ix1++; | |
| 959 | + } | |
| 960 | + else{ | |
| 961 | + bp1=bp1->next; | |
| 962 | + ps=bp1->Buf; | |
| 963 | + ix1=0; | |
| 964 | + } | |
| 965 | + } | |
| 966 | +} | |
| 967 | +void clippaste(void){ | |
| 968 | +// クリップボードから貼り付け | |
| 969 | + int n,i; | |
| 970 | + unsigned char *p; | |
| 971 | + | |
| 972 | + p=clipboard; | |
| 973 | + for(n=clipsize;n>0;n--){ | |
| 974 | + i=insertchar(cursorbp,cursorix,*p); | |
| 975 | + if(i>0){ | |
| 976 | + //バッファ空きがあるのに挿入失敗の場合 | |
| 977 | + gabagecollect2(); //全体ガベージコレクション | |
| 978 | + i=insertchar(cursorbp,cursorix,*p);//テキストバッファに1文字挿入 | |
| 979 | + } | |
| 980 | + if(i!=0) return;//挿入失敗 | |
| 981 | + cursor_right();//画面上、バッファ上のカーソル位置を1つ後ろに移動 | |
| 982 | + p++; | |
| 983 | + } | |
| 984 | +} | |
| 985 | +void set_areamode(){ | |
| 986 | +//範囲選択モード開始時のカーソル開始位置グローバル変数設定 | |
| 987 | + cursorbp1=cursorbp; | |
| 988 | + cursorix1=cursorix; | |
| 989 | + cx1=cx; | |
| 990 | + cy1=cy; | |
| 991 | +} | |
| 992 | +void save_cursor(void){ | |
| 993 | +//カーソル関連グローバル変数を一時避難 | |
| 994 | + cursorbp_t=cursorbp; | |
| 995 | + cursorix_t=cursorix; | |
| 996 | + disptopbp_t=disptopbp; | |
| 997 | + disptopix_t=disptopix; | |
| 998 | + cx_t=cx; | |
| 999 | + cy_t=cy; | |
| 1000 | +} | |
| 1001 | +void restore_cursor(void){ | |
| 1002 | +//カーソル関連グローバル変数を一時避難場所から戻す | |
| 1003 | + cursorbp=cursorbp_t; | |
| 1004 | + cursorix=cursorix_t; | |
| 1005 | + disptopbp=disptopbp_t; | |
| 1006 | + disptopix=disptopix_t; | |
| 1007 | + cx=cx_t; | |
| 1008 | + cy=cy_t; | |
| 1009 | +} | |
| 1010 | + | |
| 1011 | +int filesystemretry(){ | |
| 1012 | +// SDファイルシステムの再初期化確認と実施 | |
| 1013 | +// SDファイルへの保存や読み込み時にファイルエラーが発生した場合に呼び出す | |
| 1014 | +// 戻り値 0:初期化成功、-1:成功することなくEscapeで抜けた | |
| 1015 | + unsigned short vk; | |
| 1016 | + while(1){ | |
| 1017 | + setcursorcolor(COLOR_NORMALTEXT); | |
| 1018 | + printstr((unsigned char *)Message3); //Retry / Quit | |
| 1019 | + while(1){ | |
| 1020 | + inputchar(); //1文字入力待ち | |
| 1021 | + vk=vkey & 0xff; | |
| 1022 | + if(vk==VK_RETURN || vk==VK_SEPARATOR) break; | |
| 1023 | + if(vk==VK_ESCAPE) return -1; | |
| 1024 | + } | |
| 1025 | + //ファイルシステム初期化 | |
| 1026 | + if(FSInit()!=FALSE) return 0; //成功 | |
| 1027 | + //エラーの場合 | |
| 1028 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 1029 | + printstr((unsigned char *)Message2);//File System Error | |
| 1030 | + } | |
| 1031 | +} | |
| 1032 | + | |
| 1033 | +int sdfilecopy(char *sourcefile,char *distfile){ | |
| 1034 | +// SDカード上のファイルをコピー | |
| 1035 | +// soucefile:コピー元ファイル名 | |
| 1036 | +// distfile:コピー先ファイル名 | |
| 1037 | +// 戻り値:正常終了 0、エラー終了時エラー番号 | |
| 1038 | + FSFILE *sfp,*dfp; | |
| 1039 | + int n,er,c; | |
| 1040 | + er=0; | |
| 1041 | + sfp=FSfopen(sourcefile,"r"); | |
| 1042 | + if(sfp==NULL) return ERR_CANTFILEOPEN; | |
| 1043 | + dfp=FSfopen(distfile,"w"); | |
| 1044 | + if(dfp==NULL){ | |
| 1045 | + FSfclose(sfp); | |
| 1046 | + return ERR_CANTFILEOPEN; | |
| 1047 | + } | |
| 1048 | + c=0; | |
| 1049 | + while(1){ | |
| 1050 | + if(c==0){ | |
| 1051 | + printchar('.'); | |
| 1052 | + c=100; | |
| 1053 | + } | |
| 1054 | + c--; | |
| 1055 | + n=FSfread(filebuf,1,FILEBUFSIZE,sfp); | |
| 1056 | + if(n==0) break; | |
| 1057 | + if(FSfwrite(filebuf,1,n,dfp)!=n){ | |
| 1058 | + er=ERR_CANTWRITEFILE; | |
| 1059 | + break; | |
| 1060 | + } | |
| 1061 | + } | |
| 1062 | + FSfclose(sfp); | |
| 1063 | + FSfclose(dfp); | |
| 1064 | + return er; | |
| 1065 | +} | |
| 1066 | +int savetextfile(char *filename){ | |
| 1067 | +// テキストバッファをテキストファイルに書き込み | |
| 1068 | +// 書き込み成功で0、失敗でエラーコード(負数)を返す | |
| 1069 | + FSFILE *fp; | |
| 1070 | + _tbuf *bp; | |
| 1071 | + int ix,n,i,er; | |
| 1072 | + unsigned char *ps,*pd; | |
| 1073 | + er=0;//エラーコード | |
| 1074 | + i=-1; | |
| 1075 | + fp=FSfopen(filename,"w"); | |
| 1076 | + if(fp==NULL) return ERR_CANTFILEOPEN; | |
| 1077 | + bp=TBufstart; | |
| 1078 | + ix=0; | |
| 1079 | + ps=bp->Buf; | |
| 1080 | + do{ | |
| 1081 | + pd=filebuf; | |
| 1082 | + n=0; | |
| 1083 | + while(n<FILEBUFSIZE-1){ | |
| 1084 | + //改行コードが2バイトになることを考慮してバッファサイズ-1までとする | |
| 1085 | + while(ix>=bp->n){ | |
| 1086 | + bp=bp->next; | |
| 1087 | + if(bp==NULL){ | |
| 1088 | + break; | |
| 1089 | + } | |
| 1090 | + ix=0; | |
| 1091 | + ps=bp->Buf; | |
| 1092 | + } | |
| 1093 | + if(bp==NULL) break; | |
| 1094 | + if(*ps=='\n'){ | |
| 1095 | + *pd++='\r'; //改行コード0A→0D 0Aにする | |
| 1096 | + n++; | |
| 1097 | + } | |
| 1098 | + *pd++=*ps++; | |
| 1099 | + ix++; | |
| 1100 | + n++; | |
| 1101 | + } | |
| 1102 | + if(n>0){ | |
| 1103 | + i=FSfwrite(filebuf,1,n,fp); | |
| 1104 | + if(i!=n) er=ERR_CANTWRITEFILE; | |
| 1105 | + } | |
| 1106 | + } while(bp!=NULL && er==0); | |
| 1107 | + FSfclose(fp); | |
| 1108 | + return er; | |
| 1109 | +} | |
| 1110 | +int loadtextfile(char *filename){ | |
| 1111 | +// テキストファイルをテキストバッファに読み込み | |
| 1112 | +// 読み込み成功で0、失敗でエラーコード(負数)を返す | |
| 1113 | + FSFILE *fp; | |
| 1114 | + _tbuf *bp; | |
| 1115 | + int ix,n,i,er; | |
| 1116 | + unsigned char *ps,*pd; | |
| 1117 | + er=0;//エラーコード | |
| 1118 | + fp=FSfopen(filename,"r"); | |
| 1119 | + if(fp==NULL) return ERR_CANTFILEOPEN; | |
| 1120 | + inittextbuf(); | |
| 1121 | + bp=TextBuffer; | |
| 1122 | + ix=0; | |
| 1123 | + pd=bp->Buf; | |
| 1124 | + do{ | |
| 1125 | + n=FSfread(filebuf,1,FILEBUFSIZE,fp); | |
| 1126 | + ps=filebuf; | |
| 1127 | + for(i=0;i<n;i++){ | |
| 1128 | + if(ix>=TBUFSIZE){ | |
| 1129 | + bp->n=TBUFSIZE; | |
| 1130 | + bp=newTBuf(bp); | |
| 1131 | + if(bp==NULL){ | |
| 1132 | + er=ERR_FILETOOBIG; | |
| 1133 | + break; | |
| 1134 | + } | |
| 1135 | + ix=0; | |
| 1136 | + pd=bp->Buf; | |
| 1137 | + } | |
| 1138 | + if(*ps=='\r') ps++; //改行コード0D 0A→0Aにする(単純に0D無視) | |
| 1139 | + else{ | |
| 1140 | + *pd++=*ps++; | |
| 1141 | + ix++; | |
| 1142 | + num++;//バッファ総文字数 | |
| 1143 | + if(num>TBUFMAXSIZE){ | |
| 1144 | + er=ERR_FILETOOBIG; | |
| 1145 | + break; | |
| 1146 | + } | |
| 1147 | + } | |
| 1148 | + } | |
| 1149 | + } while(n==FILEBUFSIZE && er==0); | |
| 1150 | + if(bp!=NULL) bp->n=ix;//最後のバッファの文字数 | |
| 1151 | + FSfclose(fp); | |
| 1152 | + if(er) inittextbuf();//エラー発生の場合バッファクリア | |
| 1153 | + return er; | |
| 1154 | +} | |
| 1155 | +int overwritecheck(char *fn){ | |
| 1156 | +// ファイルの上書き確認 | |
| 1157 | +// ファイルの存在をチェックし、存在する場合キーボードから上書き確認する | |
| 1158 | +// fn:ファイル名へのポインタ | |
| 1159 | +// 戻り値 0:存在しないまたは上書き、-1:上書きしない | |
| 1160 | + SearchRec sr; | |
| 1161 | + unsigned short vk; | |
| 1162 | + if(FindFirst(tempfile,ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE,&sr)) return 0; //ファイルが存在しない | |
| 1163 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 1164 | + printstr(tempfile); | |
| 1165 | + printstr(": File Exists\n"); | |
| 1166 | + setcursorcolor(COLOR_NORMALTEXT); | |
| 1167 | + printstr("Ovewrite:[Enter] / Stop:[ESC]\n"); | |
| 1168 | + while(1){ | |
| 1169 | + inputchar(); //1文字入力待ち | |
| 1170 | + vk=vkey & 0xff; | |
| 1171 | + if(vk==VK_RETURN || vk==VK_SEPARATOR) return 0; | |
| 1172 | + if(vk==VK_ESCAPE) return -1; | |
| 1173 | + } | |
| 1174 | +} | |
| 1175 | +void save_as(int ow){ | |
| 1176 | +// 現在のテキストバッファの内容をSDカードに保存 | |
| 1177 | +// ow 0:名前を付けて保存 1:上書き保存 | |
| 1178 | +// ファイル名はグローバル変数currentfile[] | |
| 1179 | +// ファイル名はキーボードから変更可能 | |
| 1180 | +// 成功した場合currentfileを更新 | |
| 1181 | + | |
| 1182 | + int er; | |
| 1183 | + unsigned char *ps,*pd; | |
| 1184 | + | |
| 1185 | + cls(); | |
| 1186 | + setcursor(0,0,COLOR_NORMALTEXT); | |
| 1187 | + printstr("Save To SD Card\n"); | |
| 1188 | + if(currentfile[0]==0) ow=0; //ファイル名が設定されていない場合名前を付けて保存 | |
| 1189 | + | |
| 1190 | + //currentfileからtempfileにコピー | |
| 1191 | + ps=currentfile; | |
| 1192 | + pd=tempfile; | |
| 1193 | + while(*ps!=0) *pd++=*ps++; | |
| 1194 | + *pd=0; | |
| 1195 | + | |
| 1196 | + while(1){ | |
| 1197 | + if(ow==0){ | |
| 1198 | + printstr("File Name + [Enter] / [ESC]\n"); | |
| 1199 | + if(lineinput(tempfile,8+1+3)<0) return; //ESCキーが押された | |
| 1200 | + if(tempfile[0]==0) continue; //NULL文字列の場合 | |
| 1201 | + if(overwritecheck(tempfile)) continue; | |
| 1202 | + } | |
| 1203 | + printstr("Writing...\n"); | |
| 1204 | + er=savetextfile(tempfile); //ファイル保存、er:エラーコード | |
| 1205 | + if(er==0){ | |
| 1206 | + printstr("OK"); | |
| 1207 | + FSremove(TEMPFILENAME); //実行時に生成する一時ファイルを削除 | |
| 1208 | + //tempfileからcurrentfileにコピーして終了 | |
| 1209 | + ps=tempfile; | |
| 1210 | + pd=currentfile; | |
| 1211 | + while(*ps!=0) *pd++=*ps++; | |
| 1212 | + *pd=0; | |
| 1213 | + edited=0; //編集済みフラグクリア | |
| 1214 | + wait60thsec(60);//1秒待ち | |
| 1215 | + return; | |
| 1216 | + } | |
| 1217 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 1218 | + if(er==ERR_CANTFILEOPEN) printstr("Bad File Name or File Error\n"); | |
| 1219 | + else printstr("Cannot Write\n"); | |
| 1220 | + if(filesystemretry()) return; //ファイルシステム再初期化、あきらめた場合はreturnする | |
| 1221 | + } | |
| 1222 | +} | |
| 1223 | + | |
| 1224 | +void msra(void){ | |
| 1225 | +// Make Self-Running Application (自己実行アプリケーションの作成) | |
| 1226 | +// 最初にソースファイルを名前を付けて保存 | |
| 1227 | +// 次にBASICシステムのHEXファイルをソースファイル名の拡張子をHEXにした名前でコピー | |
| 1228 | + | |
| 1229 | + int er; | |
| 1230 | + unsigned char vk; | |
| 1231 | + unsigned char *ps,*pd; | |
| 1232 | + cls(); | |
| 1233 | + setcursor(0,0,COLOR_NORMALTEXT); | |
| 1234 | + printstr("Make Self-Running Application\n\n"); | |
| 1235 | + | |
| 1236 | + //currentfileからtempfileにコピー | |
| 1237 | + ps=currentfile; | |
| 1238 | + pd=tempfile; | |
| 1239 | + while(*ps!=0) *pd++=*ps++; | |
| 1240 | + *pd=0; | |
| 1241 | + | |
| 1242 | + while(1){ | |
| 1243 | + setcursorcolor(COLOR_NORMALTEXT); | |
| 1244 | + printstr("Input File Name (xxx.BAS)\n"); | |
| 1245 | + if(lineinput(tempfile,8+1+3)<0) return; //ESCキーが押された | |
| 1246 | + ps=tempfile; | |
| 1247 | + while(*ps!='.' && *ps!=0) ps++; | |
| 1248 | + if(ps+4>=tempfile+13 || | |
| 1249 | + *ps!='.' || | |
| 1250 | + (*(ps+1)!='b' && *(ps+1)!='B') || | |
| 1251 | + (*(ps+2)!='a' && *(ps+2)!='A') || | |
| 1252 | + (*(ps+3)!='s' && *(ps+3)!='S') || | |
| 1253 | + *(ps+4)!=0){ | |
| 1254 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 1255 | + printstr("File Name Must Be xxx.BAS\n"); | |
| 1256 | + continue; | |
| 1257 | + } | |
| 1258 | + if(overwritecheck(tempfile)) continue; | |
| 1259 | + printstr("Writing BASIC File\n"); | |
| 1260 | + er=savetextfile(tempfile); //ファイル保存、er:エラーコード | |
| 1261 | + if(er==0) break; | |
| 1262 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 1263 | + if(er==ERR_CANTFILEOPEN) printstr("Bad File Name or File Error\n"); | |
| 1264 | + else printstr("Cannot Write\n"); | |
| 1265 | + if(filesystemretry()) return; //ファイルシステム再初期化、あきらめた場合はreturnする | |
| 1266 | + } | |
| 1267 | + printstr("OK\n\n"); | |
| 1268 | + FSremove(TEMPFILENAME); //実行時に生成する一時ファイルを削除 | |
| 1269 | + //tempfileからcurrentfileにコピーして終了 | |
| 1270 | + ps=tempfile; | |
| 1271 | + pd=currentfile; | |
| 1272 | + while(*ps!=0) *pd++=*ps++; | |
| 1273 | + *pd=0; | |
| 1274 | + edited=0; //編集済みフラグクリア | |
| 1275 | + // 拡張子をHEXにしてBASICシステムファイルをコピー | |
| 1276 | + *(ps-3)='H'; | |
| 1277 | + *(ps-2)='E'; | |
| 1278 | + *(ps-1)='X'; | |
| 1279 | + if(overwritecheck(tempfile)) return; | |
| 1280 | + printstr("Copying\n"); | |
| 1281 | + printstr(HEXFILE); | |
| 1282 | + printstr(" To "); | |
| 1283 | + printstr(tempfile); | |
| 1284 | + printstr("\nWait For A While"); | |
| 1285 | + er=sdfilecopy(HEXFILE,tempfile); | |
| 1286 | + if(er==0){ | |
| 1287 | + printstr("\nDone"); | |
| 1288 | + wait60thsec(120);//2秒待ち | |
| 1289 | + return; | |
| 1290 | + } | |
| 1291 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 1292 | + if(er==ERR_CANTFILEOPEN){ | |
| 1293 | + printstr(HEXFILE); | |
| 1294 | + printstr(" Not Found\n"); | |
| 1295 | + } | |
| 1296 | + else if(er==ERR_CANTWRITEFILE){ | |
| 1297 | + printstr("Write Error\n"); | |
| 1298 | + } | |
| 1299 | + setcursorcolor(COLOR_NORMALTEXT); | |
| 1300 | + printstr((unsigned char *)Message1);// Hit Any Key | |
| 1301 | + inputchar(); //1文字入力待ち | |
| 1302 | + return; | |
| 1303 | +} | |
| 1304 | + | |
| 1305 | +int selectfile(void){ | |
| 1306 | +// SDカードからファイルを選択して読み込み | |
| 1307 | +// currenfile[]にファイル名を記憶 | |
| 1308 | +// 対象ファイル拡張子 BASおよびTXT | |
| 1309 | +// 戻り値 0:読み込みを行った -1:読み込みなし | |
| 1310 | + unsigned int filenum,top,f; | |
| 1311 | + int er; | |
| 1312 | + unsigned char *ps,*pd; | |
| 1313 | + unsigned char x,y; | |
| 1314 | + unsigned char vk; | |
| 1315 | + SearchRec sr; | |
| 1316 | + | |
| 1317 | + //ファイルの一覧をSDカードから読み出し | |
| 1318 | + cls(); | |
| 1319 | + if(edited && num){ | |
| 1320 | + //最終保存後に編集済みの場合、保存の確認 | |
| 1321 | + setcursorcolor(COLOR_NORMALTEXT); | |
| 1322 | + printstr("Save Program Before Load?\n"); | |
| 1323 | + printstr("Save:[Enter] / Not Save:[ESC]\n"); | |
| 1324 | + while(1){ | |
| 1325 | + inputchar(); //1文字キー入力待ち | |
| 1326 | + vk=vkey & 0xff; | |
| 1327 | + if(vk==VK_RETURN || vk==VK_SEPARATOR){ | |
| 1328 | + save_as(0); //名前を付けて保存 | |
| 1329 | + break; | |
| 1330 | + } | |
| 1331 | + else if(vk==VK_ESCAPE) break; | |
| 1332 | + } | |
| 1333 | + } | |
| 1334 | + filenum=0; | |
| 1335 | + while(1){ | |
| 1336 | + //拡張子 BASファイルのサーチ | |
| 1337 | + if(FindFirst("*.BAS",ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE,&sr)==0){ | |
| 1338 | + do{ | |
| 1339 | + //filenames[]にファイル名の一覧を読み込み | |
| 1340 | + ps=sr.filename; | |
| 1341 | + pd=filenames[filenum]; | |
| 1342 | + while(*ps!=0) *pd++=*ps++; | |
| 1343 | + *pd=0; | |
| 1344 | + filenum++; | |
| 1345 | + } | |
| 1346 | + while(!FindNext(&sr) && filenum<MAXFILENUM); | |
| 1347 | + } | |
| 1348 | + if(filenum>=MAXFILENUM) break; | |
| 1349 | + //拡張子 TXTファイルのサーチ | |
| 1350 | + if(FindFirst("*.TXT",ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE,&sr)==0){ | |
| 1351 | + do{ | |
| 1352 | + //filenames[]にファイル名の一覧を読み込み | |
| 1353 | + ps=sr.filename; | |
| 1354 | + pd=filenames[filenum]; | |
| 1355 | + while(*ps!=0) *pd++=*ps++; | |
| 1356 | + *pd=0; | |
| 1357 | + filenum++; | |
| 1358 | + } | |
| 1359 | + while(!FindNext(&sr) && filenum<MAXFILENUM); | |
| 1360 | + } | |
| 1361 | + if(filenum>=MAXFILENUM) break; | |
| 1362 | + //拡張子 INIファイルのサーチ | |
| 1363 | + if(FindFirst("*.INI",ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE,&sr)==0){ | |
| 1364 | + do{ | |
| 1365 | + //filenames[]にファイル名の一覧を読み込み | |
| 1366 | + ps=sr.filename; | |
| 1367 | + pd=filenames[filenum]; | |
| 1368 | + while(*ps!=0) *pd++=*ps++; | |
| 1369 | + *pd=0; | |
| 1370 | + filenum++; | |
| 1371 | + } | |
| 1372 | + while(!FindNext(&sr) && filenum<MAXFILENUM); | |
| 1373 | + } | |
| 1374 | + if(filenum>0) break; | |
| 1375 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 1376 | + printstr(".BAS or .TXT File Not Found\n"); | |
| 1377 | + if(filesystemretry()) return; //ファイルシステム再初期化、あきらめた場合はreturnする | |
| 1378 | + } | |
| 1379 | + | |
| 1380 | + //ファイル一覧を画面に表示 | |
| 1381 | + cls(); | |
| 1382 | + setcursor(0,0,COLOR_NORMALTEXT); | |
| 1383 | + printstr("Load: "); | |
| 1384 | + setcursorcolor(4); | |
| 1385 | + printstr("Select&[Enter] / [ESC]\n"); | |
| 1386 | + for(f=0;f<filenum;f++){ | |
| 1387 | + x=(f&1)*15+1; | |
| 1388 | + y=f/2+1; | |
| 1389 | + if(y>=WIDTH_Y-1) break; | |
| 1390 | + setcursor(x,y,COLOR_NORMALTEXT); | |
| 1391 | + printstr(filenames[f]); | |
| 1392 | + } | |
| 1393 | + | |
| 1394 | + //ファイルの選択 | |
| 1395 | + top=0;//画面一番先頭のファイル番号 | |
| 1396 | + f=0;//現在選択中のファイル番号 | |
| 1397 | + setcursor(0,1,5); | |
| 1398 | + printchar(0x1c); // Right Arrow | |
| 1399 | + cursor--; | |
| 1400 | + while(1){ | |
| 1401 | + inputchar(); | |
| 1402 | + vk=vkey & 0xff; | |
| 1403 | + if(vk==0) continue; | |
| 1404 | + printchar(' '); | |
| 1405 | + setcursor(0,WIDTH_Y-1,COLOR_NORMALTEXT); | |
| 1406 | + for(x=0;x<WIDTH_X-1;x++) printchar(' '); //最下行のステータス表示を消去 | |
| 1407 | + switch(vk){ | |
| 1408 | + case VK_UP: | |
| 1409 | + case VK_NUMPAD8: | |
| 1410 | + //上矢印キー | |
| 1411 | + if(f>=2){ | |
| 1412 | + f-=2; | |
| 1413 | + if(f<top){ | |
| 1414 | + //画面最上部の場合、下にスクロールして最上部にファイル名2つ表示 | |
| 1415 | + setcursor(WIDTH_X-1,WIDTH_Y-2,COLOR_NORMALTEXT); | |
| 1416 | + while(cursor>=TVRAM+WIDTH_X*2){ | |
| 1417 | + *cursor=*(cursor-WIDTH_X); | |
| 1418 | + *(cursor+ATTROFFSET)=*(cursor+ATTROFFSET-WIDTH_X); | |
| 1419 | + cursor--; | |
| 1420 | + } | |
| 1421 | + while(cursor>=TVRAM+WIDTH_X) *cursor--=' '; | |
| 1422 | + top-=2; | |
| 1423 | + setcursor(1,1,COLOR_NORMALTEXT); | |
| 1424 | + printstr(filenames[top]); | |
| 1425 | + setcursor(16,1,COLOR_NORMALTEXT); | |
| 1426 | + printstr(filenames[top+1]); | |
| 1427 | + } | |
| 1428 | + } | |
| 1429 | + break; | |
| 1430 | + case VK_DOWN: | |
| 1431 | + case VK_NUMPAD2: | |
| 1432 | + //下矢印キー | |
| 1433 | + if(f+2<filenum){ | |
| 1434 | + f+=2; | |
| 1435 | + if(f-top>=(WIDTH_Y-2)*2){ | |
| 1436 | + //画面最下部の場合、上にスクロールして最下部にファイル名1つor2つ表示 | |
| 1437 | + setcursor(0,1,COLOR_NORMALTEXT); | |
| 1438 | + while(cursor<TVRAM+WIDTH_X*(WIDTH_Y-2)){ | |
| 1439 | + *cursor=*(cursor+WIDTH_X); | |
| 1440 | + *(cursor+ATTROFFSET)=*(cursor+ATTROFFSET+WIDTH_X); | |
| 1441 | + cursor++; | |
| 1442 | + } | |
| 1443 | + while(cursor<TVRAM+WIDTH_X*(WIDTH_Y-1)) *cursor++=' '; | |
| 1444 | + top+=2; | |
| 1445 | + setcursor(1,WIDTH_Y-2,COLOR_NORMALTEXT); | |
| 1446 | + printstr(filenames[f&0xfffe]); | |
| 1447 | + if((f|1)<filenum){ | |
| 1448 | + setcursor(16,WIDTH_Y-2,COLOR_NORMALTEXT); | |
| 1449 | + printstr(filenames[f|1]); | |
| 1450 | + } | |
| 1451 | + } | |
| 1452 | + } | |
| 1453 | + break; | |
| 1454 | + case VK_LEFT: | |
| 1455 | + case VK_NUMPAD4: | |
| 1456 | + //左矢印キー | |
| 1457 | + if(f&1) f--; | |
| 1458 | + break; | |
| 1459 | + case VK_RIGHT: | |
| 1460 | + case VK_NUMPAD6: | |
| 1461 | + //右矢印キー | |
| 1462 | + if((f&1)==0 && f+1<filenum) f++; | |
| 1463 | + break; | |
| 1464 | + case VK_RETURN: //Enterキー | |
| 1465 | + case VK_SEPARATOR: //テンキーのEnter | |
| 1466 | + //ファイル名決定。読み込んで終了 | |
| 1467 | + er=loadtextfile(filenames[f]); //テキストバッファにファイル読み込み | |
| 1468 | + if(er==0){ | |
| 1469 | + //currenfile[]変数にファイル名をコピーして終了 | |
| 1470 | + ps=filenames[f]; | |
| 1471 | + pd=currentfile; | |
| 1472 | + while(*ps!=0) *pd++=*ps++; | |
| 1473 | + *pd=0; | |
| 1474 | + return 0; | |
| 1475 | + } | |
| 1476 | + setcursor(0,WIDTH_Y-1,COLOR_ERRORTEXT); | |
| 1477 | + if(er==ERR_CANTFILEOPEN) printstr("Cannot Open File"); | |
| 1478 | + else if(er=ERR_FILETOOBIG) printstr("File Too Big"); | |
| 1479 | + break; | |
| 1480 | + case VK_ESCAPE: | |
| 1481 | + //ESCキー、ファイル読み込みせず終了 | |
| 1482 | + return -1; | |
| 1483 | + } | |
| 1484 | + setcursor((f&1)*15,(f-top)/2+1,5); | |
| 1485 | + printchar(0x1c);// Right Arrow | |
| 1486 | + cursor--; | |
| 1487 | + } | |
| 1488 | +} | |
| 1489 | +void newtext(void){ | |
| 1490 | +// 新規テキスト作成 | |
| 1491 | + unsigned char vk; | |
| 1492 | + if(edited && num){ | |
| 1493 | + //最終保存後に編集済みの場合、保存の確認 | |
| 1494 | + cls(); | |
| 1495 | + setcursorcolor(COLOR_NORMALTEXT); | |
| 1496 | + printstr("Save Editing File?\n"); | |
| 1497 | + printstr("Save:[Enter] / Not Save:[ESC]\n"); | |
| 1498 | + while(1){ | |
| 1499 | + inputchar(); //1文字キー入力待ち | |
| 1500 | + vk=vkey & 0xff; | |
| 1501 | + if(vk==VK_RETURN || vk==VK_SEPARATOR){ | |
| 1502 | + save_as(0); //名前を付けて保存 | |
| 1503 | + break; | |
| 1504 | + } | |
| 1505 | + else if(vk==VK_ESCAPE) break; | |
| 1506 | + } | |
| 1507 | + } | |
| 1508 | + inittextbuf(); //テキストバッファ初期化 | |
| 1509 | + cursor_top(); //カーソルをテキストバッファの先頭に設定 | |
| 1510 | + currentfile[0]=0; //作業中ファイル名クリア | |
| 1511 | +} | |
| 1512 | +void run(int test){ | |
| 1513 | +//KM-BASICコンパイル&実行 | |
| 1514 | +// test 0:コンパイルと実行、0以外:コンパイルのみで終了 | |
| 1515 | + int er,er2; | |
| 1516 | + unsigned char vk; | |
| 1517 | + unsigned int disptoppos,cursorpos; | |
| 1518 | + int i,edited1; | |
| 1519 | + _tbuf *bp; | |
| 1520 | + unsigned short ix; | |
| 1521 | + | |
| 1522 | + cls(); | |
| 1523 | + setcursor(0,0,COLOR_NORMALTEXT); | |
| 1524 | + while(1){ | |
| 1525 | + er=savetextfile(TEMPFILENAME); //一時ファイルに保存、er:エラーコード | |
| 1526 | + if(er==0) break; | |
| 1527 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 1528 | + printstr("Cannot Write To SD Card\n"); | |
| 1529 | + if(filesystemretry()) return; //ファイルシステム再初期化、あきらめた場合はreturnする | |
| 1530 | + } | |
| 1531 | + | |
| 1532 | + //カーソル位置、画面表示位置の保存 | |
| 1533 | + disptoppos=bpixtopos(disptopbp,disptopix); | |
| 1534 | + cursorpos=bpixtopos(cursorbp,cursorix); | |
| 1535 | + edited1=edited; //編集済みフラグの一時退避 | |
| 1536 | + // Enable Break key | |
| 1537 | + g_disable_break=0; | |
| 1538 | + //KM-BASIC実行 | |
| 1539 | + er2=runbasic(TEMPFILENAME,test); | |
| 1540 | + | |
| 1541 | + stopPCG();//システムフォントに戻す | |
| 1542 | + setcursorcolor(COLOR_NORMALTEXT); | |
| 1543 | + printchar('\n'); | |
| 1544 | + printstr((unsigned char *)Message1);// Hit Any Key | |
| 1545 | + do ps2readkey(); //キーバッファが空になるまで読み出し | |
| 1546 | + while(vkey!=0); | |
| 1547 | + ps2mode(); //キーボード有効化 | |
| 1548 | + inputchar(); //1文字入力待ち | |
| 1549 | + init_composite(); //パレット初期化のため画面初期化 | |
| 1550 | + while(1){ | |
| 1551 | + er=loadtextfile(TEMPFILENAME); //一時ファイルから戻す | |
| 1552 | + if(er==0) break; | |
| 1553 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 1554 | + printstr("Cannot Load From SD Card\n"); | |
| 1555 | + filesystemretry(); //ファイルシステム再初期化 | |
| 1556 | + } | |
| 1557 | + if(er2<=0){ | |
| 1558 | + //正常終了またはファイルエラーまたはリンクエラーの場合 | |
| 1559 | + //カーソルを元の位置に設定 | |
| 1560 | + disptopbp=postobpix(disptoppos,&disptopix); | |
| 1561 | + cursorbp=postobpix(cursorpos,&cursorix); | |
| 1562 | + } | |
| 1563 | + else{ | |
| 1564 | + //コンパイルエラーの場合 | |
| 1565 | + //カーソルをエラー行で画面トップに移動 | |
| 1566 | + disptopbp=linetobpix(er2,&disptopix); | |
| 1567 | + cursorbp=disptopbp; | |
| 1568 | + cursorix=disptopix; | |
| 1569 | + cx=0; | |
| 1570 | + cx2=0; | |
| 1571 | + cy=0; | |
| 1572 | + //中央になるようスクロール | |
| 1573 | + for(i=0;i<EDITWIDTHY/2;i++){ | |
| 1574 | + //画面行数半分カーソルを上に移動 | |
| 1575 | + bp=disptopbp; | |
| 1576 | + ix=disptopix; | |
| 1577 | + cursor_up(); | |
| 1578 | + if(bp==disptopbp && ix==disptopix) break; //最上行で移動できなかった場合抜ける | |
| 1579 | + } | |
| 1580 | + for(;i>0;i--) cursor_down(); //元のY座標までカーソルを下に移動 | |
| 1581 | + } | |
| 1582 | + cursorbp1=NULL; //範囲選択モード解除 | |
| 1583 | + clipsize=0; //クリップボードクリア | |
| 1584 | + edited=edited1; | |
| 1585 | + FSremove(TEMPFILENAME); //一時ファイル削除 | |
| 1586 | +} | |
| 1587 | +void displaybottomline(void){ | |
| 1588 | +//エディター画面最下行の表示 | |
| 1589 | + unsigned char *p; | |
| 1590 | + unsigned char c; | |
| 1591 | + p=cursor; //カーソル位置の退避 | |
| 1592 | + c=cursorcolor; | |
| 1593 | + setcursor(0,WIDTH_Y-1,COLOR_BOTTOMLINE); | |
| 1594 | + if(shiftkeys() & CHK_SHIFT) | |
| 1595 | + printstr("NEW |MSRA| |TEST| "); | |
| 1596 | + else | |
| 1597 | + printstr("LOAD|SAVE| |RUN | "); | |
| 1598 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 1599 | + printnum2(TBUFMAXSIZE-num,5); | |
| 1600 | + cursor=p; //カーソル位置戻し | |
| 1601 | + cursorcolor=c; | |
| 1602 | +} | |
| 1603 | +void normal_code_process(unsigned char k){ | |
| 1604 | +// 通常文字入力処理 | |
| 1605 | +// k:入力された文字コード | |
| 1606 | + int i; | |
| 1607 | + | |
| 1608 | + edited=1; //編集済みフラグ | |
| 1609 | + if(insertmode || k=='\n' || cursorbp1!=NULL){ //挿入モード | |
| 1610 | + if(cursorbp1!=NULL) deletearea();//選択範囲を削除 | |
| 1611 | + i=insertchar(cursorbp,cursorix,k);//テキストバッファに1文字挿入 | |
| 1612 | + if(i>0){ | |
| 1613 | + //バッファ空きがあるのに挿入失敗の場合 | |
| 1614 | + gabagecollect2(); //全体ガベージコレクション | |
| 1615 | + i=insertchar(cursorbp,cursorix,k);//テキストバッファに1文字挿入 | |
| 1616 | + } | |
| 1617 | + if(i==0) cursor_right();//画面上、バッファ上のカーソル位置を1つ後ろに移動 | |
| 1618 | + } | |
| 1619 | + else{ //上書きモード | |
| 1620 | + i=overwritechar(cursorbp,cursorix,k);//テキストバッファに1文字上書き | |
| 1621 | + if(i>0){ | |
| 1622 | + //バッファ空きがあるのに上書き(挿入)失敗の場合 | |
| 1623 | + //(行末やバッファ最後尾では挿入) | |
| 1624 | + gabagecollect2(); //全体ガベージコレクション | |
| 1625 | + i=overwritechar(cursorbp,cursorix,k);//テキストバッファに1文字上書き | |
| 1626 | + } | |
| 1627 | + if(i==0) cursor_right();//画面上、バッファ上のカーソル位置を1つ後ろに移動 | |
| 1628 | + } | |
| 1629 | +} | |
| 1630 | +void control_code_process(unsigned char k,unsigned char sh){ | |
| 1631 | +// 制御文字入力処理 | |
| 1632 | +// k:制御文字の仮想キーコード | |
| 1633 | +// sh:シフト関連キー状態 | |
| 1634 | + | |
| 1635 | + save_cursor(); //カーソル関連変数退避(カーソル移動できなかった場合戻すため) | |
| 1636 | + switch(k){ | |
| 1637 | + case VK_LEFT: | |
| 1638 | + case VK_NUMPAD4: | |
| 1639 | + //シフトキー押下していなければ範囲選択モード解除(NumLock+シフト+テンキーでも解除) | |
| 1640 | + if((sh & CHK_SHIFT)==0 || (k==VK_NUMPAD4) && (sh & CHK_NUMLK)) cursorbp1=NULL; | |
| 1641 | + else if(cursorbp1==NULL) set_areamode(); //範囲選択モードでなければ範囲選択モード開始 | |
| 1642 | + if(sh & CHK_CTRL){ | |
| 1643 | + //CTRL+左矢印でHome | |
| 1644 | + cursor_home(); | |
| 1645 | + break; | |
| 1646 | + } | |
| 1647 | + cursor_left(); | |
| 1648 | + if(cursorbp1!=NULL && (disptopbp!=disptopbp_t || disptopix!=disptopix_t)){ | |
| 1649 | + //範囲選択モードで画面スクロールがあった場合 | |
| 1650 | + if(cy1<EDITWIDTHY-1) cy1++; //範囲スタート位置もスクロール | |
| 1651 | + else restore_cursor(); //カーソル位置を戻す(画面範囲外の範囲選択禁止) | |
| 1652 | + } | |
| 1653 | + break; | |
| 1654 | + case VK_RIGHT: | |
| 1655 | + case VK_NUMPAD6: | |
| 1656 | + //シフトキー押下していなければ範囲選択モード解除(NumLock+シフト+テンキーでも解除) | |
| 1657 | + if((sh & CHK_SHIFT)==0 || (k==VK_NUMPAD6) && (sh & CHK_NUMLK)) cursorbp1=NULL; | |
| 1658 | + else if(cursorbp1==NULL) set_areamode(); //範囲選択モードでなければ範囲選択モード開始 | |
| 1659 | + if(sh & CHK_CTRL){ | |
| 1660 | + //CTRL+右矢印でEnd | |
| 1661 | + cursor_end(); | |
| 1662 | + break; | |
| 1663 | + } | |
| 1664 | + cursor_right(); | |
| 1665 | + if(cursorbp1!=NULL && (disptopbp!=disptopbp_t || disptopix!=disptopix_t)){ | |
| 1666 | + //範囲選択モードで画面スクロールがあった場合 | |
| 1667 | + if(cy1>0) cy1--; //範囲スタート位置もスクロール | |
| 1668 | + else restore_cursor(); //カーソル位置を戻す(画面範囲外の範囲選択禁止) | |
| 1669 | + } | |
| 1670 | + break; | |
| 1671 | + case VK_UP: | |
| 1672 | + case VK_NUMPAD8: | |
| 1673 | + //シフトキー押下していなければ範囲選択モード解除(NumLock+シフト+テンキーでも解除) | |
| 1674 | + if((sh & CHK_SHIFT)==0 || (k==VK_NUMPAD8) && (sh & CHK_NUMLK)) cursorbp1=NULL; | |
| 1675 | + else if(cursorbp1==NULL) set_areamode(); //範囲選択モードでなければ範囲選択モード開始 | |
| 1676 | + cursor_up(); | |
| 1677 | + if(cursorbp1!=NULL && (disptopbp!=disptopbp_t || disptopix!=disptopix_t)){ | |
| 1678 | + //範囲選択モードで画面スクロールがあった場合 | |
| 1679 | + if(cy1<EDITWIDTHY-1) cy1++; //範囲スタート位置もスクロール | |
| 1680 | + else restore_cursor(); //カーソル位置を戻す(画面範囲外の範囲選択禁止) | |
| 1681 | + } | |
| 1682 | + break; | |
| 1683 | + case VK_DOWN: | |
| 1684 | + case VK_NUMPAD2: | |
| 1685 | + //シフトキー押下していなければ範囲選択モード解除(NumLock+シフト+テンキーでも解除) | |
| 1686 | + if((sh & CHK_SHIFT)==0 || (k==VK_NUMPAD2) && (sh & CHK_NUMLK)) cursorbp1=NULL; | |
| 1687 | + else if(cursorbp1==NULL) set_areamode(); //範囲選択モードでなければ範囲選択モード開始 | |
| 1688 | + cursor_down(); | |
| 1689 | + if(cursorbp1!=NULL && (disptopbp!=disptopbp_t || disptopix!=disptopix_t)){ | |
| 1690 | + //範囲選択モードで画面スクロールがあった場合 | |
| 1691 | + if(cy1>0) cy1--; //範囲スタート位置もスクロール | |
| 1692 | + else restore_cursor(); //カーソル位置を戻す(画面範囲外の範囲選択禁止) | |
| 1693 | + } | |
| 1694 | + break; | |
| 1695 | + case VK_HOME: | |
| 1696 | + case VK_NUMPAD7: | |
| 1697 | + //シフトキー押下していなければ範囲選択モード解除(NumLock+シフト+テンキーでも解除) | |
| 1698 | + if((sh & CHK_SHIFT)==0 || (k==VK_NUMPAD7) && (sh & CHK_NUMLK)) cursorbp1=NULL; | |
| 1699 | + else if(cursorbp1==NULL) set_areamode(); //範囲選択モードでなければ範囲選択モード開始 | |
| 1700 | + cursor_home(); | |
| 1701 | + break; | |
| 1702 | + case VK_END: | |
| 1703 | + case VK_NUMPAD1: | |
| 1704 | + //シフトキー押下していなければ範囲選択モード解除(NumLock+シフト+テンキーでも解除) | |
| 1705 | + if((sh & CHK_SHIFT)==0 || (k==VK_NUMPAD1) && (sh & CHK_NUMLK)) cursorbp1=NULL; | |
| 1706 | + else if(cursorbp1==NULL) set_areamode(); //範囲選択モードでなければ範囲選択モード開始 | |
| 1707 | + cursor_end(); | |
| 1708 | + break; | |
| 1709 | + case VK_PRIOR: // PageUpキー | |
| 1710 | + case VK_NUMPAD9: | |
| 1711 | + //シフト+PageUpは無効(NumLock+シフト+「9」除く) | |
| 1712 | + if((sh & CHK_SHIFT) && ((k!=VK_NUMPAD9) || ((sh & CHK_NUMLK)==0))) break; | |
| 1713 | + cursorbp1=NULL; //範囲選択モード解除 | |
| 1714 | + cursor_pageup(); | |
| 1715 | + break; | |
| 1716 | + case VK_NEXT: // PageDownキー | |
| 1717 | + case VK_NUMPAD3: | |
| 1718 | + //シフト+PageDownは無効(NumLock+シフト+「3」除く) | |
| 1719 | + if((sh & CHK_SHIFT) && ((k!=VK_NUMPAD3) || ((sh & CHK_NUMLK)==0))) break; | |
| 1720 | + cursorbp1=NULL; //範囲選択モード解除 | |
| 1721 | + cursor_pagedown(); | |
| 1722 | + break; | |
| 1723 | + case VK_DELETE: //Deleteキー | |
| 1724 | + case VK_DECIMAL: //テンキーの「.」 | |
| 1725 | + edited=1; //編集済みフラグ | |
| 1726 | + if(cursorbp1!=NULL) deletearea();//選択範囲を削除 | |
| 1727 | + else deletechar(cursorbp,cursorix); | |
| 1728 | + break; | |
| 1729 | + case VK_BACK: //BackSpaceキー | |
| 1730 | + edited=1; //編集済みフラグ | |
| 1731 | + if(cursorbp1!=NULL){ | |
| 1732 | + deletearea();//選択範囲を削除 | |
| 1733 | + break; | |
| 1734 | + } | |
| 1735 | + if(cursorix==0 && cursorbp->prev==NULL) break; //バッファ先頭では無視 | |
| 1736 | + cursor_left(); | |
| 1737 | + deletechar(cursorbp,cursorix); | |
| 1738 | + break; | |
| 1739 | + case VK_INSERT: | |
| 1740 | + case VK_NUMPAD0: | |
| 1741 | + insertmode^=1; //挿入モード、上書きモードを切り替え | |
| 1742 | + break; | |
| 1743 | + case 'C': | |
| 1744 | + //CTRL+C、クリップボードにコピー | |
| 1745 | + if(cursorbp1!=NULL && (sh & CHK_CTRL)) clipcopy(); | |
| 1746 | + break; | |
| 1747 | + case 'X': | |
| 1748 | + //CTRL+X、クリップボードに切り取り | |
| 1749 | + if(cursorbp1!=NULL && (sh & CHK_CTRL)){ | |
| 1750 | + clipcopy(); | |
| 1751 | + deletearea(); //選択範囲の削除 | |
| 1752 | + edited=1; //編集済みフラグ | |
| 1753 | + } | |
| 1754 | + break; | |
| 1755 | + case 'V': | |
| 1756 | + //CTRL+V、クリップボードから貼り付け | |
| 1757 | + if((sh & CHK_CTRL)==0) break; | |
| 1758 | + if(clipsize==0) break; | |
| 1759 | + edited=1; //編集済みフラグ | |
| 1760 | + if(cursorbp1!=NULL){ | |
| 1761 | + //範囲選択している時は削除してから貼り付け | |
| 1762 | + if(num-countarea()+clipsize<=TBUFMAXSIZE){ //バッファ空き容量チェック | |
| 1763 | + deletearea();//選択範囲を削除 | |
| 1764 | + clippaste();//クリップボード貼り付け | |
| 1765 | + } | |
| 1766 | + } | |
| 1767 | + else{ | |
| 1768 | + if(num+clipsize<=TBUFMAXSIZE){ //バッファ空き容量チェック | |
| 1769 | + clippaste();//クリップボード貼り付け | |
| 1770 | + } | |
| 1771 | + } | |
| 1772 | + break; | |
| 1773 | + case 'S': | |
| 1774 | + //CTRL+S、SDカードに保存 | |
| 1775 | + if(num==0) break; | |
| 1776 | + if(sh & CHK_CTRL) save_as(1); //上書き保存 | |
| 1777 | + break; | |
| 1778 | + case 'O': | |
| 1779 | + //CTRL+O、ファイル読み込み | |
| 1780 | + if(sh & CHK_CTRL){ | |
| 1781 | + if(selectfile()==0){ //ファイルを選択して読み込み | |
| 1782 | + //読み込みを行った場合、カーソル位置を先頭に | |
| 1783 | + cursor_top(); | |
| 1784 | + } | |
| 1785 | + } | |
| 1786 | + break; | |
| 1787 | + case 'N': | |
| 1788 | + //CTRL+N、新規作成 | |
| 1789 | + if(sh & CHK_CTRL) newtext(); | |
| 1790 | + break; | |
| 1791 | + case VK_F1: //F1キー | |
| 1792 | + if(sh & CHK_SHIFT) newtext();//SHIFT+F1キー 新規作成 | |
| 1793 | + else{ | |
| 1794 | + //ファイル読み込み | |
| 1795 | + if(selectfile()==0){ //ファイルを選択して読み込み | |
| 1796 | + //読み込みを行った場合、カーソル位置を先頭に | |
| 1797 | + cursor_top(); | |
| 1798 | + } | |
| 1799 | + } | |
| 1800 | + break; | |
| 1801 | + case VK_F2: //F2キー | |
| 1802 | + if(num==0) break; | |
| 1803 | + if(sh & CHK_SHIFT) msra(); //create direct running file | |
| 1804 | + else save_as(0); //ファイル名を付けて保存 | |
| 1805 | + break; | |
| 1806 | + case VK_F4: //F4キー | |
| 1807 | + if(num==0) break; | |
| 1808 | + if(sh & CHK_SHIFT) run(1); //コンパイルテスト | |
| 1809 | + else run(0); //コンパイル&実行 | |
| 1810 | + break; | |
| 1811 | + } | |
| 1812 | +} | |
| 1813 | +void texteditor(void){ | |
| 1814 | +//テキストエディター本体 | |
| 1815 | + unsigned char k1,k2,k3,sh; | |
| 1816 | + | |
| 1817 | + TextBuffer=(_tbuf *)RAM; | |
| 1818 | + clipboard=(unsigned char *)TextBuffer+sizeof(_tbuf)*TBUFMAXLINE; | |
| 1819 | + filebuf=clipboard+EDITWIDTHX*EDITWIDTHY; | |
| 1820 | + filenames=(unsigned char (*)[])(filebuf+FILEBUFSIZE); | |
| 1821 | + | |
| 1822 | + inittextbuf(); //テキストバッファ初期化 | |
| 1823 | + currentfile[0]=0; //作業中ファイル名クリア | |
| 1824 | + | |
| 1825 | + //実行時生成一時ファイルがあった場合は読み込む | |
| 1826 | + if(loadtextfile(TEMPFILENAME)==0){ | |
| 1827 | + edited=1; | |
| 1828 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 1829 | + printstr("Temporary File Loaded\n"); | |
| 1830 | + printstr("Save To SD Card If Necessary\n"); | |
| 1831 | + setcursorcolor(COLOR_NORMALTEXT); | |
| 1832 | + printstr((unsigned char *)Message1); //Hit Any Key | |
| 1833 | + inputchar(); //1文字入力待ち | |
| 1834 | + } | |
| 1835 | + cursor_top(); //カーソルをテキストバッファの先頭に移動 | |
| 1836 | + insertmode=1; //0:上書き、1:挿入 | |
| 1837 | + clipsize=0; //クリップボードクリア | |
| 1838 | + blinktimer=0; //カーソル点滅タイマークリア | |
| 1839 | + | |
| 1840 | + while(1){ | |
| 1841 | + redraw();//画面再描画 | |
| 1842 | + setcursor(cx,cy,COLOR_NORMALTEXT); | |
| 1843 | + getcursorchar(); //カーソル位置の文字を退避(カーソル点滅用) | |
| 1844 | + while(1){ | |
| 1845 | + //キー入力待ちループ | |
| 1846 | + wait60thsec(1); //60分の1秒ウェイト | |
| 1847 | + blinkcursorchar(); //カーソル点滅させる | |
| 1848 | + k1=ps2readkey(); //キーバッファから読み込み、k1:通常文字入力の場合ASCIIコード | |
| 1849 | + displaybottomline(); //画面最下行にファンクションキー機能表示 | |
| 1850 | + if(vkey) break; //キーが押された場合ループから抜ける | |
| 1851 | + if(cursorbp1==NULL) gabagecollect1(); //1バイトガベージコレクション(範囲選択時はしない) | |
| 1852 | + } | |
| 1853 | + resetcursorchar(); //カーソルを元の文字表示に戻す | |
| 1854 | + k2=(unsigned char)vkey; //k2:仮想キーコード | |
| 1855 | + sh=vkey>>8; //sh:シフト関連キー状態 | |
| 1856 | + if(k2==VK_RETURN || k2==VK_SEPARATOR) k1='\n'; //Enter押下は単純に改行文字を入力とする | |
| 1857 | + if(k1) normal_code_process(k1); //通常文字が入力された場合 | |
| 1858 | + else control_code_process(k2,sh); //制御文字が入力された場合 | |
| 1859 | + if(cursorbp1!=NULL && cx==cx1 && cy==cy1) cursorbp1=NULL;//選択範囲の開始と終了が重なったら範囲選択モード解除 | |
| 1860 | + } | |
| 1861 | +} |
| @@ -0,0 +1,21 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by K.Tanaka & Katsumi | |
| 4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
| 5 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#define SYSVER1 "Zoea" | |
| 9 | +#define SYSVER2 "1.0" | |
| 10 | +#define BASVER "KM-1200" | |
| 11 | + | |
| 12 | +#define INIFILE "MACHIKAZ.INI" // 初期設定ファイル | |
| 13 | +#define HEXFILE "MACHIKAZ.HEX" // 実行中HEXファイル名がこれと一致した場合はエディタ起動 | |
| 14 | + | |
| 15 | +#define FILENAME_FLASH_ADDRESS 0x9D005800 | |
| 16 | +#define PIC32MX_RAMSIZE 0x10000 | |
| 17 | +#define PIC32MX_FLASHSIZE 0x40000 | |
| 18 | + | |
| 19 | +void printhex8(unsigned char d); | |
| 20 | +void printhex16(unsigned short d); | |
| 21 | +void printhex32(unsigned int d); |
| @@ -0,0 +1,29 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by K.Tanaka | |
| 4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
| 5 | +*/ | |
| 6 | + | |
| 7 | +#define TBUFMAXLINE 201 //テキストバッファ数 | |
| 8 | + | |
| 9 | +#define TBUFSIZE 200 //テキストバッファ1つのサイズ | |
| 10 | +#define TBUFMAXSIZE (TBUFSIZE*(TBUFMAXLINE-1)) //最大バッファ容量(バッファ1行分空ける) | |
| 11 | +#define EDITWIDTHX 30 //エディタ画面横幅 | |
| 12 | +#define EDITWIDTHY 26 //エディタ画面縦幅 | |
| 13 | +#define COLOR_NORMALTEXT 7 //通常テキスト色 | |
| 14 | +#define COLOR_ERRORTEXT 4 //エラーメッセージテキスト色 | |
| 15 | +#define COLOR_AREASELECTTEXT 4 //範囲選択テキスト色 | |
| 16 | +#define COLOR_BOTTOMLINE 5 //画面最下行の色 | |
| 17 | +#define FILEBUFSIZE 256 //ファイルアクセス用バッファサイズ | |
| 18 | +#define MAXFILENUM 200 //利用可能ファイル最大数 | |
| 19 | + | |
| 20 | +#define ERR_FILETOOBIG -1 | |
| 21 | +#define ERR_CANTFILEOPEN -2 | |
| 22 | +#define ERR_CANTWRITEFILE -3 | |
| 23 | + | |
| 24 | +#define TEMPFILENAME "~TEMP.BAS" | |
| 25 | + | |
| 26 | +void texteditor(void); //テキストエディタ本体 | |
| 27 | +int runbasic(char *s,int test); //コンパイルして実行 | |
| 28 | +extern unsigned char tempfile[13]; | |
| 29 | +void wait60thsec(unsigned short n); |
| @@ -0,0 +1,160 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by K.Tanaka & Katsumi | |
| 4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
| 5 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#ifdef __DEBUG | |
| 9 | + | |
| 10 | +#include <xc.h> | |
| 11 | +#include "api.h" | |
| 12 | +#include "main.h" | |
| 13 | + | |
| 14 | + | |
| 15 | +// Pseudo reading config setting for debug mode | |
| 16 | +unsigned int g_DEVCFG1=0xFF7F4DDB; | |
| 17 | + | |
| 18 | +// Construct jump assembly in boot area. | |
| 19 | +const unsigned int _debug_boot[] __attribute__((address(0xBFC00000))) ={ | |
| 20 | + 0x0B401C00,// j 0x9d007000 | |
| 21 | + 0x00000000,// nop | |
| 22 | +}; | |
| 23 | + | |
| 24 | +// Use DEBUG.HEX as file name of this program. | |
| 25 | +const unsigned char _debug_filename[] __attribute__((address(FILENAME_FLASH_ADDRESS))) ="DEBUG.HEX"; | |
| 26 | + | |
| 27 | +static const char initext[]; | |
| 28 | +static const char bastext[]; | |
| 29 | + | |
| 30 | +static char* readtext; | |
| 31 | +static int filepos; | |
| 32 | + | |
| 33 | +/* | |
| 34 | + Override libsdfsio functions. | |
| 35 | + Here, don't use SD card, but the vertual files | |
| 36 | + (initext[] and bastext[]) are used. | |
| 37 | +*/ | |
| 38 | + | |
| 39 | +FSFILE fsfile; | |
| 40 | + | |
| 41 | +size_t FSfread(void *ptr, size_t size, size_t n, FSFILE *stream){ | |
| 42 | + char b; | |
| 43 | + size_t ret=0; | |
| 44 | + if (!readtext) return 0; | |
| 45 | + while(b=readtext[filepos]){ | |
| 46 | + filepos++; | |
| 47 | + ((char*)ptr)[ret]=b; | |
| 48 | + ret++; | |
| 49 | + if (n<=ret) break; | |
| 50 | + } | |
| 51 | + return ret; | |
| 52 | +} | |
| 53 | +FSFILE* FSfopen(const char * fileName, const char *mode){ | |
| 54 | + int i; | |
| 55 | + for(i=0;i<13;i++){ | |
| 56 | + if (fileName[i]=='.') break; | |
| 57 | + } | |
| 58 | + if (i==13) { | |
| 59 | + // Unknown file name | |
| 60 | + // Force BAS file | |
| 61 | + readtext=(char*)&bastext[0]; | |
| 62 | + } else if (fileName[i+1]=='I' && fileName[i+2]=='N' && fileName[i+3]=='I') { | |
| 63 | + // INI file | |
| 64 | + readtext=(char*)&initext[0]; | |
| 65 | + } else if (fileName[i+1]=='B' && fileName[i+2]=='A' && fileName[i+3]=='S') { | |
| 66 | + // BAS file | |
| 67 | + readtext=(char*)&bastext[0]; | |
| 68 | + } else { | |
| 69 | + readtext=0; | |
| 70 | + return 0; | |
| 71 | + } | |
| 72 | + filepos=0; | |
| 73 | + return &fsfile; | |
| 74 | +} | |
| 75 | +int FSfeof( FSFILE * stream ){ | |
| 76 | + return readtext[filepos]?1:0; | |
| 77 | +} | |
| 78 | +int FSfclose(FSFILE *fo){ | |
| 79 | + return 0; | |
| 80 | +} | |
| 81 | +int FSInit(void){ | |
| 82 | + return 1; | |
| 83 | +} | |
| 84 | +int FSremove (const char * fileName){ | |
| 85 | + return 0; | |
| 86 | +} | |
| 87 | +size_t FSfwrite(const void *ptr, size_t size, size_t n, FSFILE *stream){ | |
| 88 | + return 0; | |
| 89 | +} | |
| 90 | + | |
| 91 | +int FindFirst (const char * fileName, unsigned int attr, SearchRec * rec){ | |
| 92 | + return 0; | |
| 93 | +} | |
| 94 | +int FindNext (SearchRec * rec){ | |
| 95 | + return 0; | |
| 96 | +} | |
| 97 | + | |
| 98 | +/* | |
| 99 | + ps2init() is not called. | |
| 100 | + Instead, not_ps2init_but_init_Timer1() is called. | |
| 101 | + Timer1 is used to update drawcount and drawing gloval variables. | |
| 102 | +*/ | |
| 103 | + | |
| 104 | +int not_ps2init_but_init_Timer1(){ | |
| 105 | + PR1=0x0FFF; | |
| 106 | + TMR1=0; | |
| 107 | + IFS0bits.T1IF=0; | |
| 108 | + T1CON=0x8000; | |
| 109 | + // Timer1 interrupt: priority 4 | |
| 110 | + IPC1bits.T1IP=4; | |
| 111 | + IPC1bits.T1IS=0; | |
| 112 | + IEC0bits.T1IE=1; | |
| 113 | + | |
| 114 | + return 0; | |
| 115 | +} | |
| 116 | + | |
| 117 | +#pragma interrupt timer1Int IPL4SOFT vector 4 | |
| 118 | + | |
| 119 | +void timer1Int(){ | |
| 120 | + IFS0bits.T1IF=0; | |
| 121 | + if (drawing) { | |
| 122 | + drawing=0; | |
| 123 | + drawcount++; | |
| 124 | + } else { | |
| 125 | + drawing=1; | |
| 126 | + } | |
| 127 | +} | |
| 128 | + | |
| 129 | +/* | |
| 130 | + initext[] and bastext[] are vertual files | |
| 131 | + as "MACHIKAN.INI" and "DEBUG.BAS". | |
| 132 | +*/ | |
| 133 | + | |
| 134 | + | |
| 135 | +static const char initext[]= | |
| 136 | +"#PRINT\n" | |
| 137 | +"#PRINT\n"; | |
| 138 | + | |
| 139 | + | |
| 140 | +static const char bastext[]= | |
| 141 | +"CLS\n" | |
| 142 | +"\n"; | |
| 143 | + | |
| 144 | +/* | |
| 145 | + Test function for constructing assemblies from C codes. | |
| 146 | +*/ | |
| 147 | + | |
| 148 | +int _debug_test(int a0, int a1){ | |
| 149 | +// if (a0<0xa0008192) return 0xa0000000; | |
| 150 | + asm volatile("lw $v1,0($v1)"); | |
| 151 | +} | |
| 152 | + | |
| 153 | +/* | |
| 154 | + Break point used for debugging object code. | |
| 155 | + | |
| 156 | +g_object[g_objpos++]=0x0000000d;// break 0x0 | |
| 157 | + | |
| 158 | +*/ | |
| 159 | + | |
| 160 | +#endif // __DEBUG |
| @@ -0,0 +1,984 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include <xc.h> | |
| 9 | +#include "main.h" | |
| 10 | +#include "compiler.h" | |
| 11 | +#include "api.h" | |
| 12 | +#include "keyinput.h" | |
| 13 | +#include "stdlib.h" | |
| 14 | +#include "math.h" | |
| 15 | + | |
| 16 | +/* | |
| 17 | + Local global variables used for graphic | |
| 18 | + */ | |
| 19 | + | |
| 20 | +static int g_gcolor=7; | |
| 21 | +static int g_prev_x=0; | |
| 22 | +static int g_prev_y=0; | |
| 23 | + | |
| 24 | +int lib_read(int mode, unsigned int label){ | |
| 25 | + unsigned int i,code,code2; | |
| 26 | + static unsigned int pos=0; | |
| 27 | + static unsigned int in_data=0; | |
| 28 | + static unsigned char skip=0; | |
| 29 | + if (label) { | |
| 30 | + // RESTORE function | |
| 31 | + switch(mode){ | |
| 32 | + case 0: | |
| 33 | + // label is label data | |
| 34 | + i=(int)search_label(label); | |
| 35 | + if (!i) { | |
| 36 | + err_data_not_found(); | |
| 37 | + return 0; | |
| 38 | + } | |
| 39 | + break; | |
| 40 | + case 1: | |
| 41 | + // label is pointer | |
| 42 | + i=label; | |
| 43 | + break; | |
| 44 | + case 2: | |
| 45 | + default: | |
| 46 | + // Reset data/read | |
| 47 | + pos=0; | |
| 48 | + in_data=0; | |
| 49 | + skip=0; | |
| 50 | + return 0; | |
| 51 | + } | |
| 52 | + i-=(int)(&g_object[0]); | |
| 53 | + pos=i/4; | |
| 54 | + in_data=0; | |
| 55 | + } | |
| 56 | + // Get data | |
| 57 | + if (in_data==0) { | |
| 58 | + for(i=pos;i<g_objpos;i++){ | |
| 59 | + code=g_object[i]; | |
| 60 | + code2=g_object[i+1]; | |
| 61 | + if ((code&0xFFFF0000)!=0x04110000) continue; | |
| 62 | + // "bgezal zero," assembly found. | |
| 63 | + // Check if 0x00000020,0x00000021,0x00000022, or 0x00000023 follows | |
| 64 | + if ((code2&0xfffffffc)!=0x00000020) {// add/addu/sub/subu zero,zero,zero | |
| 65 | + // If not, skip following block (it's strig). | |
| 66 | + i+=code&0x0000FFFF; | |
| 67 | + i--; | |
| 68 | + continue; | |
| 69 | + } | |
| 70 | + // DATA region found. | |
| 71 | + in_data=(code&0x0000FFFF)-1; | |
| 72 | + pos=i+2; | |
| 73 | + skip=code2&0x03; | |
| 74 | + break; | |
| 75 | + } | |
| 76 | + if (g_objpos<=i) { | |
| 77 | + err_data_not_found(); | |
| 78 | + return 0; | |
| 79 | + } | |
| 80 | + } | |
| 81 | + if (label) { | |
| 82 | + // RESTORE function. Return pointer. | |
| 83 | + return ((int)&g_object[pos])+skip; | |
| 84 | + } else { | |
| 85 | + switch(mode){ | |
| 86 | + case 0: | |
| 87 | + // READ() function | |
| 88 | + in_data--; | |
| 89 | + return g_object[pos++]; | |
| 90 | + case 1: | |
| 91 | + default: | |
| 92 | + // CREAD() function | |
| 93 | + i=g_object[pos]; | |
| 94 | + i>>=skip*8; | |
| 95 | + i&=0xff; | |
| 96 | + if ((++skip)==4) { | |
| 97 | + skip=0; | |
| 98 | + in_data--; | |
| 99 | + pos++; | |
| 100 | + } | |
| 101 | + return i; | |
| 102 | + } | |
| 103 | + } | |
| 104 | +} | |
| 105 | + | |
| 106 | +void reset_dataread(){ | |
| 107 | + lib_read(2,1); | |
| 108 | +} | |
| 109 | + | |
| 110 | +char* lib_midstr(int var_num, int pos, int len){ | |
| 111 | + int i; | |
| 112 | + char* str; | |
| 113 | + char* ret; | |
| 114 | + if (0<=pos) { | |
| 115 | + // String after "pos" position. | |
| 116 | + str=(char*)(g_var_mem[var_num]+pos); | |
| 117 | + } else { | |
| 118 | + // String right "pos" characters. | |
| 119 | + // Determine length | |
| 120 | + str=(char*)g_var_mem[var_num]; | |
| 121 | + for(i=0;str[i];i++); | |
| 122 | + if (0<=(i+pos)) { | |
| 123 | + str=(char*)(g_var_mem[var_num]+i+pos); | |
| 124 | + } | |
| 125 | + } | |
| 126 | + if (len<0) { | |
| 127 | + // Length is not specified. | |
| 128 | + // Return the string to the end. | |
| 129 | + return str; | |
| 130 | + } | |
| 131 | + // Length is specified. | |
| 132 | + // Construct temporary string containing specified number of characters. | |
| 133 | + ret=alloc_memory((len+1+3)/4,-1); | |
| 134 | + // Copy string. | |
| 135 | + for(i=0;(ret[i]=str[i])&&(i<len);i++); | |
| 136 | + ret[len]=0x00; | |
| 137 | + return ret; | |
| 138 | +} | |
| 139 | + | |
| 140 | +void lib_clear(void){ | |
| 141 | + int i; | |
| 142 | + // All variables will be integer 0 | |
| 143 | + for(i=0;i<26;i++){ | |
| 144 | + g_var_mem[i]=0; | |
| 145 | + } | |
| 146 | + // Clear memory allocation area | |
| 147 | + for(i=0;i<ALLOC_BLOCK_NUM;i++){ | |
| 148 | + g_var_size[i]=0; | |
| 149 | + } | |
| 150 | + // Cancel PCG | |
| 151 | + stopPCG(); | |
| 152 | + g_pcg_font=0; | |
| 153 | +} | |
| 154 | + | |
| 155 | +void lib_let_str(char* str, int var_num){ | |
| 156 | + int begin,end,size; | |
| 157 | + // Save pointer | |
| 158 | + g_var_mem[var_num]=(int)str; | |
| 159 | + // Determine size | |
| 160 | + for(size=0;str[size];size++); | |
| 161 | + // Check if str is in heap area. | |
| 162 | + begin=(int)str; | |
| 163 | + end=(int)(&str[size]); | |
| 164 | + if (begin<(int)(&g_heap_mem[0]) || (int)(&g_heap_mem[g_max_mem])<=end) { | |
| 165 | + // String is not within allcated block | |
| 166 | + return; | |
| 167 | + } | |
| 168 | + // Str is in heap area. Calculate values stored in heap data dimension | |
| 169 | + begin-=(int)(&g_heap_mem[0]); | |
| 170 | + begin>>=2; | |
| 171 | + end-=(int)(&g_heap_mem[0]); | |
| 172 | + end>>=2; | |
| 173 | + size=end-begin+1; | |
| 174 | + g_var_pointer[var_num]=begin; | |
| 175 | + g_var_size[var_num]=size; | |
| 176 | +} | |
| 177 | + | |
| 178 | +int lib_rnd(){ | |
| 179 | + int y; | |
| 180 | + y=g_rnd_seed; | |
| 181 | + y = y ^ (y << 13); | |
| 182 | + y = y ^ (y >> 17); | |
| 183 | + y = y ^ (y << 5); | |
| 184 | + g_rnd_seed=y; | |
| 185 | + return y&0x7fff; | |
| 186 | +} | |
| 187 | + | |
| 188 | +char* lib_chr(int num){ | |
| 189 | + char* str; | |
| 190 | + str=alloc_memory(1,-1); | |
| 191 | + str[0]=num&0x000000FF; | |
| 192 | + str[1]=0x00; | |
| 193 | + return str; | |
| 194 | +} | |
| 195 | + | |
| 196 | +char* lib_dec(int num){ | |
| 197 | + char* str; | |
| 198 | + int i,j,minus; | |
| 199 | + char b[12]; | |
| 200 | + b[11]=0x00; | |
| 201 | + if (num<0) { | |
| 202 | + minus=1; | |
| 203 | + num=0-num; | |
| 204 | + } else { | |
| 205 | + minus=0; | |
| 206 | + } | |
| 207 | + for (i=10;0<i;i--) { | |
| 208 | + if (num==0 && i<10) break; | |
| 209 | + b[i]='0'+rem10_32(num); | |
| 210 | + num=div10_32(num); | |
| 211 | + } | |
| 212 | + if (minus) { | |
| 213 | + b[i]='-'; | |
| 214 | + } else { | |
| 215 | + i++; | |
| 216 | + } | |
| 217 | + str=alloc_memory(3,-1); | |
| 218 | + for(j=0;str[j]=b[i++];j++); | |
| 219 | + return str; | |
| 220 | +} | |
| 221 | + | |
| 222 | +char* lib_hex(int num, int width){ | |
| 223 | + char* str; | |
| 224 | + int i,j,minus; | |
| 225 | + char b[8]; | |
| 226 | + str=alloc_memory(3,-1); | |
| 227 | + for(i=0;i<8;i++){ | |
| 228 | + b[i]="0123456789ABCDEF"[(num>>(i<<2))&0x0F]; | |
| 229 | + } | |
| 230 | + // Width must be between 0 and 8; | |
| 231 | + if (width<0||8<width) width=8; | |
| 232 | + if (width==0) { | |
| 233 | + // Width not asigned. Use minimum width. | |
| 234 | + for(i=7;0<i;i--){ | |
| 235 | + if ('0'<b[i]) break; | |
| 236 | + } | |
| 237 | + } else { | |
| 238 | + // Constant width | |
| 239 | + i=width-1; | |
| 240 | + } | |
| 241 | + // Copy string to allocated block. | |
| 242 | + for(j=0;0<=i;i--){ | |
| 243 | + str[j++]=b[i]; | |
| 244 | + } | |
| 245 | + str[j]=0x00; | |
| 246 | + return str; | |
| 247 | +} | |
| 248 | + | |
| 249 | +char* lib_connect_string(char* str1, char* str2){ | |
| 250 | + int i,j; | |
| 251 | + char b; | |
| 252 | + char* result; | |
| 253 | + // Determine total length | |
| 254 | + for(i=0;str1[i];i++); | |
| 255 | + for(j=0;str2[j];j++); | |
| 256 | + // Allocate a block for new string | |
| 257 | + result=alloc_memory((i+j+1+3)/4,-1); | |
| 258 | + // Create connected strings | |
| 259 | + for(i=0;b=str1[i];i++) result[i]=b; | |
| 260 | + for(j=0;b=str2[j];j++) result[i+j]=b; | |
| 261 | + result[i+j]=0x00; | |
| 262 | + free_temp_str(str1); | |
| 263 | + free_temp_str(str2); | |
| 264 | + return result; | |
| 265 | +} | |
| 266 | + | |
| 267 | +void lib_string(int mode){ | |
| 268 | + int i; | |
| 269 | + switch(mode){ | |
| 270 | + case 0: | |
| 271 | + // CR | |
| 272 | + printchar('\n'); | |
| 273 | + return; | |
| 274 | + case 1: | |
| 275 | + // , | |
| 276 | + i=rem10_32((unsigned int)(cursor-TVRAM)); | |
| 277 | + printstr(" "+i); | |
| 278 | + return; | |
| 279 | + default: | |
| 280 | + return; | |
| 281 | + } | |
| 282 | +} | |
| 283 | + | |
| 284 | +void* lib_label(unsigned int label){ | |
| 285 | + // This routine is used to jump to address dynamically determined | |
| 286 | + // in the code; for example: "GOTO 100+I" | |
| 287 | + unsigned int i,code,search; | |
| 288 | + void* ret; | |
| 289 | + if (label&0xFFFF0000) { | |
| 290 | + // Label is not supported. | |
| 291 | + // Line number must bs less than 65536. | |
| 292 | + err_label_not_found(); | |
| 293 | + } else { | |
| 294 | + // Line number | |
| 295 | + ret=search_label(label); | |
| 296 | + if (ret) return ret; | |
| 297 | + // Line number not found. | |
| 298 | + err_label_not_found(); | |
| 299 | + } | |
| 300 | +} | |
| 301 | + | |
| 302 | +int lib_keys(int mask){ | |
| 303 | + int keys; | |
| 304 | + // Enable tact switches | |
| 305 | + if (inPS2MODE()) { | |
| 306 | + buttonmode(); | |
| 307 | + } | |
| 308 | + | |
| 309 | + keys=KEYPORT; | |
| 310 | + keys= | |
| 311 | + ((keys&KEYUP)? 0:1)| | |
| 312 | + ((keys&KEYDOWN)? 0:2)| | |
| 313 | + ((keys&KEYLEFT)? 0:4)| | |
| 314 | + ((keys&KEYRIGHT)? 0:8)| | |
| 315 | + ((keys&KEYSTART)? 0:16)| | |
| 316 | + ((keys&KEYFIRE)? 0:32); | |
| 317 | + return mask&keys; | |
| 318 | +} | |
| 319 | + | |
| 320 | +int lib_val(char* str){ | |
| 321 | + int i; | |
| 322 | + int val=0; | |
| 323 | + int sign=1; | |
| 324 | + char b; | |
| 325 | + // Skip blanc | |
| 326 | + for(i=0;0<=str[i] && str[i]<0x21;i++); | |
| 327 | + // Skip '+' | |
| 328 | + if (str[i]=='+') i++; | |
| 329 | + // Check '-' | |
| 330 | + if (str[i]=='-') { | |
| 331 | + sign=-1; | |
| 332 | + i++; | |
| 333 | + } | |
| 334 | + // Check '0x' or '$' | |
| 335 | + if (str[i]=='$' || str[i]=='0' && (str[i+1]=='x' || str[i+1]=='X')) { | |
| 336 | + // Hexadecimal | |
| 337 | + if (str[i++]=='0') i++; | |
| 338 | + while(1) { | |
| 339 | + b=str[i++]; | |
| 340 | + if ('0'<=b && b<='9') { | |
| 341 | + val<<=4; | |
| 342 | + val+=b-'0'; | |
| 343 | + } else if ('a'<=b && b<='f') { | |
| 344 | + val<<=4; | |
| 345 | + val+=b-'a'+10; | |
| 346 | + } else if ('A'<=b && b<='F') { | |
| 347 | + val<<=4; | |
| 348 | + val+=b-'A'+10; | |
| 349 | + } else { | |
| 350 | + break; | |
| 351 | + } | |
| 352 | + } | |
| 353 | + } else { | |
| 354 | + // Decimal | |
| 355 | + while(1) { | |
| 356 | + b=str[i++]; | |
| 357 | + if ('0'<=b && b<='9') { | |
| 358 | + val*=10; | |
| 359 | + val+=b-'0'; | |
| 360 | + } else { | |
| 361 | + break; | |
| 362 | + } | |
| 363 | + } | |
| 364 | + } | |
| 365 | + return val*sign; | |
| 366 | +} | |
| 367 | + | |
| 368 | +char* lib_input(){ | |
| 369 | + // Allocate memory for strings with 63 characters | |
| 370 | + char *str=calloc_memory((63+1)/4,-1); | |
| 371 | + // Enable PS/2 keyboard | |
| 372 | + if (!inPS2MODE()) { | |
| 373 | + ps2mode(); | |
| 374 | + ps2init(); | |
| 375 | + } | |
| 376 | + // Clear key buffer | |
| 377 | + do ps2readkey(); | |
| 378 | + while(vkey!=0); | |
| 379 | + // Get string as a line | |
| 380 | + lineinput(str,63); | |
| 381 | + check_break(); | |
| 382 | + return str; | |
| 383 | +} | |
| 384 | + | |
| 385 | +unsigned char lib_inkey(int key){ | |
| 386 | + int i; | |
| 387 | + // Enable PS/2 keyboard | |
| 388 | + if (!inPS2MODE()) { | |
| 389 | + ps2mode(); | |
| 390 | + ps2init(); | |
| 391 | + } | |
| 392 | + if (key) { | |
| 393 | + return ps2keystatus[key&0xff]; | |
| 394 | + } else { | |
| 395 | + for(i=0;i<256;i++){ | |
| 396 | + if (ps2keystatus[i]) return i; | |
| 397 | + } | |
| 398 | + return 0; | |
| 399 | + } | |
| 400 | +} | |
| 401 | + | |
| 402 | +void lib_usepcg(int mode){ | |
| 403 | + // Modes; 0: stop PCG, 1: use PCG, 2: reset PCG and use it | |
| 404 | + switch(mode){ | |
| 405 | + case 0: | |
| 406 | + // Stop PCG | |
| 407 | + stopPCG(); | |
| 408 | + break; | |
| 409 | + case 2: | |
| 410 | + // Reset PCG and use it | |
| 411 | + if (g_pcg_font) { | |
| 412 | + free_temp_str(g_pcg_font); | |
| 413 | + g_pcg_font=0; | |
| 414 | + } | |
| 415 | + // Continue to case 1: | |
| 416 | + case 1: | |
| 417 | + default: | |
| 418 | + // Use PCG | |
| 419 | + if (g_pcg_font) { | |
| 420 | + startPCG(g_pcg_font,0); | |
| 421 | + } else { | |
| 422 | + g_pcg_font=alloc_memory(256*8/4,ALLOC_PCG_BLOCK); | |
| 423 | + startPCG(g_pcg_font,1); | |
| 424 | + } | |
| 425 | + break; | |
| 426 | + } | |
| 427 | +} | |
| 428 | + | |
| 429 | +void lib_pcg(unsigned int ascii,unsigned int fontdata1,unsigned int fontdata2){ | |
| 430 | + unsigned int* pcg; | |
| 431 | + // If USEPCG has not yet executed, do now. | |
| 432 | + if (!g_pcg_font) lib_usepcg(1); | |
| 433 | + pcg=(unsigned int*)g_pcg_font; | |
| 434 | + // 0 <= ascii <= 0xff | |
| 435 | + ascii&=0xff; | |
| 436 | + // Update font data | |
| 437 | + ascii<<=1; | |
| 438 | + pcg[ascii]=(fontdata1>>24)|((fontdata1&0xff0000)>>8)|((fontdata1&0xff00)<<8)|(fontdata1<<24); | |
| 439 | + pcg[ascii+1]=(fontdata2>>24)|((fontdata2&0xff0000)>>8)|((fontdata2&0xff00)<<8)|(fontdata2<<24); | |
| 440 | +} | |
| 441 | + | |
| 442 | +void lib_scroll(int x,int y){ | |
| 443 | + int i,j; | |
| 444 | + int vector=y*WIDTH_X+x; | |
| 445 | + if (vector<0) { | |
| 446 | + // Copy data from upper address to lower address | |
| 447 | + for(i=0-vector;i<WIDTH_X*WIDTH_Y;i++){ | |
| 448 | + TVRAM[i+vector]=TVRAM[i]; | |
| 449 | + TVRAM[WIDTH_X*WIDTH_Y+i+vector]=TVRAM[WIDTH_X*WIDTH_Y+i]; | |
| 450 | + } | |
| 451 | + } else if (0<vector) { | |
| 452 | + // Copy data from lower address to upper address | |
| 453 | + for(i=WIDTH_X*WIDTH_Y-vector-1;0<=i;i--){ | |
| 454 | + TVRAM[i+vector]=TVRAM[i]; | |
| 455 | + TVRAM[WIDTH_X*WIDTH_Y+i+vector]=TVRAM[WIDTH_X*WIDTH_Y+i]; | |
| 456 | + } | |
| 457 | + } else { | |
| 458 | + return; | |
| 459 | + } | |
| 460 | + if (x<0) { | |
| 461 | + // Fill blanc at right | |
| 462 | + for(i=x;i<0;i++){ | |
| 463 | + for(j=WIDTH_X+i;j<WIDTH_X*WIDTH_Y;j+=WIDTH_X){ | |
| 464 | + TVRAM[j]=0x00; | |
| 465 | + TVRAM[WIDTH_X*WIDTH_Y+j]=cursorcolor; | |
| 466 | + } | |
| 467 | + } | |
| 468 | + } else if (0<x) { | |
| 469 | + // Fill blanc at left | |
| 470 | + for(i=0;i<x;i++){ | |
| 471 | + for(j=i;j<WIDTH_X*WIDTH_Y;j+=WIDTH_X){ | |
| 472 | + TVRAM[j]=0x00; | |
| 473 | + TVRAM[WIDTH_X*WIDTH_Y+j]=cursorcolor; | |
| 474 | + } | |
| 475 | + } | |
| 476 | + } | |
| 477 | + if (y<0) { | |
| 478 | + // Fill blanc at bottom | |
| 479 | + for(i=WIDTH_X*(WIDTH_Y+y);i<WIDTH_X*WIDTH_Y;i++){ | |
| 480 | + TVRAM[i]=0x00; | |
| 481 | + TVRAM[WIDTH_X*WIDTH_Y+i]=cursorcolor; | |
| 482 | + } | |
| 483 | + } else if (0<y) { | |
| 484 | + // Fill blanc at top | |
| 485 | + for(i=0;i<WIDTH_X*y;i++){ | |
| 486 | + TVRAM[i]=0x00; | |
| 487 | + TVRAM[WIDTH_X*WIDTH_Y+i]=cursorcolor; | |
| 488 | + } | |
| 489 | + } | |
| 490 | +} | |
| 491 | + | |
| 492 | +void lib_wait(int period){ | |
| 493 | + int i; | |
| 494 | + unsigned short dcount; | |
| 495 | + for(i=0;i<period;i++){ | |
| 496 | + dcount=drawcount; | |
| 497 | + while(dcount==drawcount){ | |
| 498 | + asm (WAIT); | |
| 499 | + check_break(); | |
| 500 | + } | |
| 501 | + } | |
| 502 | +} | |
| 503 | + | |
| 504 | +void allocate_graphic_area(){ | |
| 505 | + if (!g_graphic_area) { | |
| 506 | + // Use this pointer like unsigned short GVRAM[G_H_WORD*G_Y_RES] __attribute__ ((aligned (4))); | |
| 507 | + g_graphic_area=(unsigned short*)alloc_memory(G_H_WORD*G_Y_RES/2,ALLOC_GRAPHIC_BLOCK); | |
| 508 | + // Start graphic and clear screen | |
| 509 | + init_graphic(g_graphic_area); | |
| 510 | + // Move current point to (0,0) | |
| 511 | + g_prev_x=g_prev_y=0; | |
| 512 | + } | |
| 513 | +} | |
| 514 | + | |
| 515 | +void lib_usegraphic(int mode){ | |
| 516 | + // Modes; 0: stop GRAPHIC, 1: use GRAPHIC, 2: reset GRAPHIC and use it | |
| 517 | + switch(mode){ | |
| 518 | + case 0: | |
| 519 | + if (g_use_graphic){ | |
| 520 | + // Stop GRAPHIC if used | |
| 521 | + set_graphmode(0); | |
| 522 | + g_use_graphic=0; | |
| 523 | + // Set timer4 for tempo | |
| 524 | + PR4=59473; // 3632*262/16-1 | |
| 525 | + } else { | |
| 526 | + // Prepare GRAPHIC area if not used and not allcated. | |
| 527 | + allocate_graphic_area(); | |
| 528 | + } | |
| 529 | + break; | |
| 530 | + case 2: | |
| 531 | + // Reset GRAPHIC and use it | |
| 532 | + g_graphic_area=0; | |
| 533 | + // Continue to case 1: | |
| 534 | + case 1: | |
| 535 | + case 3: | |
| 536 | + default: | |
| 537 | + // Use GRAPHIC | |
| 538 | + allocate_graphic_area(); | |
| 539 | + // Start showing GRAPHIC with mode 1, but not with mode 3 | |
| 540 | + if (mode !=3 && !g_use_graphic){ | |
| 541 | + set_graphmode(1); | |
| 542 | + g_use_graphic=1; | |
| 543 | + // Set timer4 for tempo | |
| 544 | + PR4=55756; // ~=3405*262/16-1(55755.875) | |
| 545 | + } | |
| 546 | + break; | |
| 547 | + } | |
| 548 | +} | |
| 549 | + | |
| 550 | +int lib_graphic(int a0, int a1, int v0){ | |
| 551 | + unsigned char b; | |
| 552 | + enum functions func=(enum functions)(a0>>24); | |
| 553 | + int x1=(a0>>12)&0x0FFF; | |
| 554 | + int y1=a0&0x0FFF; | |
| 555 | + int x2=(a1>>12)&0x0FFF; | |
| 556 | + int y2=a1&0x0FFF; | |
| 557 | + // Disable if graphic area is not defined. | |
| 558 | + if (!g_graphic_area) return; | |
| 559 | + // Support 12 bit signed integer. | |
| 560 | + if (x1&0x0800) x1|=0x0FFFFF000; | |
| 561 | + if (y1&0x0800) y1|=0x0FFFFF000; | |
| 562 | + if (x2&0x0800) x2|=0x0FFFFF000; | |
| 563 | + if (y2&0x0800) y2|=0x0FFFFF000; | |
| 564 | + // If C is omitted in parameters, use current color. | |
| 565 | + if (v0==-1) { | |
| 566 | + v0=g_gcolor; | |
| 567 | + } | |
| 568 | + // If X1 or Y1 is -2048 (0xFFFFF800/0x0800), use the previous values. | |
| 569 | + if (x1==-2048) x1=g_prev_x; | |
| 570 | + if (y1==-2048) y1=g_prev_y; | |
| 571 | + switch(func){ | |
| 572 | + case FUNC_POINT:// X1,Y1 | |
| 573 | + g_prev_x=x1; | |
| 574 | + g_prev_y=y1; | |
| 575 | + break; | |
| 576 | + case FUNC_PSET:// X1,Y1[,C] | |
| 577 | + g_pset(x1,y1,v0&0x0F); | |
| 578 | + g_prev_x=x1; | |
| 579 | + g_prev_y=y1; | |
| 580 | + break; | |
| 581 | + case FUNC_LINE:// X1,Y1,X2,Y2[,C] | |
| 582 | + if (y1==y2) g_hline(x1,x2,y1,v0&0x0F); | |
| 583 | + else g_gline(x1,y1,x2,y2,v0&0x0F); | |
| 584 | + g_prev_x=x2; | |
| 585 | + g_prev_y=y2; | |
| 586 | + break; | |
| 587 | + case FUNC_BOXFILL:// X1,Y1,X2,Y2[,C] | |
| 588 | + g_boxfill(x1,y1,x2,y2,v0&0x0F); | |
| 589 | + g_prev_x=x2; | |
| 590 | + g_prev_y=y2; | |
| 591 | + break; | |
| 592 | + case FUNC_CIRCLE:// X1,Y1,R[,C] | |
| 593 | + g_circle(x1,y1,x2,v0&0x0F); | |
| 594 | + g_prev_x=x1; | |
| 595 | + g_prev_y=y1; | |
| 596 | + break; | |
| 597 | + case FUNC_CIRCLEFILL:// X1,Y1,R[,C] | |
| 598 | + g_circlefill(x1,y1,x2,v0&0x0F); | |
| 599 | + g_prev_x=x1; | |
| 600 | + g_prev_y=y1; | |
| 601 | + break; | |
| 602 | + case FUNC_GPRINT:// X1,Y1,C,BC,S$ | |
| 603 | + g_printstr(x1,y1,x2,y2,(unsigned char*)v0); | |
| 604 | + // Move current X,Y according to the string | |
| 605 | + while(b=((unsigned char*)v0)[0]){ | |
| 606 | + v0++; | |
| 607 | + if (b==0x0d) { | |
| 608 | + x1=0; | |
| 609 | + y1+=8; | |
| 610 | + } else { | |
| 611 | + x1+=8; | |
| 612 | + } | |
| 613 | + } | |
| 614 | + g_prev_x=x1; | |
| 615 | + g_prev_y=y1; | |
| 616 | + break; | |
| 617 | + case FUNC_PUTBMP2:// X1,Y1,M,N,BMP(label) | |
| 618 | + // Search CDATA | |
| 619 | + // It starts from either 0x00000020,0x00000021,0x00000022, or 0x00000023. | |
| 620 | + while((((unsigned int*)v0)[0]&0xfffffffc)!=0x00000020) v0+=4; | |
| 621 | + // CDATA starts from next word. | |
| 622 | + // MLB 3 bytes show skip byte(s). | |
| 623 | + v0+=4+(((unsigned int*)v0)[0]&0x03); | |
| 624 | + // Contunue to FUNC_PUTBMP. | |
| 625 | + case FUNC_PUTBMP:// X1,Y1,M,N,BMP(pointer) | |
| 626 | + g_putbmpmn(x1,y1,x2,y2,(const unsigned char*)v0); | |
| 627 | + g_prev_x=x1; | |
| 628 | + g_prev_y=y1; | |
| 629 | + break; | |
| 630 | + case FUNC_GCOLOR:// (X1,Y1) | |
| 631 | + v0=g_color(x1,y1); | |
| 632 | + break; | |
| 633 | + default: | |
| 634 | + break; | |
| 635 | + } | |
| 636 | + return v0; | |
| 637 | +} | |
| 638 | + | |
| 639 | +void lib_var_push(int* sp,unsigned int flags){ | |
| 640 | + unsigned int strflags=0; | |
| 641 | + int varnum; | |
| 642 | + int stack=0; | |
| 643 | + // Store flags in stack | |
| 644 | + // Note that sp[1] is used for string return address | |
| 645 | + sp[2]=flags; | |
| 646 | + for(varnum=0;varnum<26;varnum++){ | |
| 647 | + if (flags&1) { | |
| 648 | + sp[(stack++)+4]=g_var_mem[varnum]; | |
| 649 | + if (g_var_size[varnum] && g_var_mem[varnum]==(int)(&g_var_pointer[varnum])) { | |
| 650 | + // strflags change using varnum | |
| 651 | + strflags|=1<<varnum; | |
| 652 | + // Copy to VAR_BLOCK | |
| 653 | + move_to_perm_block(varnum); | |
| 654 | + } | |
| 655 | + // Clear variable | |
| 656 | + g_var_mem[varnum]=0; | |
| 657 | + } | |
| 658 | + flags>>=1; | |
| 659 | + } | |
| 660 | + sp[3]=strflags; | |
| 661 | +} | |
| 662 | +void lib_var_pop(int* sp){ | |
| 663 | + // Note that sp is 4 bytes larger than that in lib_var_push | |
| 664 | + unsigned int flags; | |
| 665 | + unsigned int strflags; | |
| 666 | + int varnum; | |
| 667 | + int stack=0; | |
| 668 | + flags=sp[1]; | |
| 669 | + strflags=sp[2]; | |
| 670 | + for(varnum=0;varnum<26;varnum++){ | |
| 671 | + if (flags&1) { | |
| 672 | + g_var_mem[varnum]=sp[(stack++)+3]; | |
| 673 | + if (strflags&1) { | |
| 674 | + // Restore from VAR_BLOCK | |
| 675 | + move_from_perm_block(varnum); | |
| 676 | + } | |
| 677 | + } | |
| 678 | + flags>>=1; | |
| 679 | + strflags>>=1; | |
| 680 | + } | |
| 681 | +} | |
| 682 | + | |
| 683 | +int lib_system(int a0,int v0){ | |
| 684 | + switch(a0){ | |
| 685 | + // Version info | |
| 686 | + case 0: return (int)SYSVER1; | |
| 687 | + case 1: return (int)SYSVER2; | |
| 688 | + case 2: return (int)BASVER; | |
| 689 | + case 3: return (int)FILENAME_FLASH_ADDRESS; | |
| 690 | + // Display info | |
| 691 | + case 20: return WIDTH_X; | |
| 692 | + case 21: return WIDTH_Y; | |
| 693 | + case 22: return G_X_RES; | |
| 694 | + case 23: return G_Y_RES; | |
| 695 | + case 24: return cursorcolor; | |
| 696 | + case 25: return g_gcolor; | |
| 697 | + case 26: return ((int)(cursor-TVRAM))%WIDTH_X; | |
| 698 | + case 27: return ((int)(cursor-TVRAM))/WIDTH_X; | |
| 699 | + case 28: return g_prev_x; | |
| 700 | + case 29: return g_prev_y; | |
| 701 | + // Keyboard info | |
| 702 | + case 40: return (int)inPS2MODE(); | |
| 703 | + case 41: return (int)vkey; | |
| 704 | + case 42: return (int)lockkey; | |
| 705 | + case 43: return (int)keytype; | |
| 706 | + // Pointers to gloval variables | |
| 707 | + case 100: return (int)&g_var_mem[0]; | |
| 708 | + case 101: return (int)&g_rnd_seed; | |
| 709 | + case 102: return (int)&TVRAM[0]; | |
| 710 | + case 103: return (int)&FontData[0]; | |
| 711 | + case 104: return (int)g_var_mem[ALLOC_PCG_BLOCK]; | |
| 712 | + case 105: return (int)g_var_mem[ALLOC_GRAPHIC_BLOCK]; | |
| 713 | + // Change system settings | |
| 714 | + case 200: | |
| 715 | + // ON/OFF monitor | |
| 716 | + if (v0) { | |
| 717 | + start_composite(); | |
| 718 | + } else { | |
| 719 | + stop_composite(); | |
| 720 | + } | |
| 721 | + break; | |
| 722 | + default: | |
| 723 | + break; | |
| 724 | + } | |
| 725 | + return 0; | |
| 726 | +} | |
| 727 | + | |
| 728 | +char* lib_sprintf(char* format, int data){ | |
| 729 | + char* str; | |
| 730 | + int i; | |
| 731 | + char temp[4]; | |
| 732 | + if (!format) format="%g"; | |
| 733 | + i=snprintf((char*)(&temp[0]),4,format,data)+1; | |
| 734 | + str=alloc_memory((i+3)/4,-1); | |
| 735 | + snprintf(str,i,format,data); | |
| 736 | + return str; | |
| 737 | +} | |
| 738 | + | |
| 739 | +int lib_floatfuncs(int ia0,int iv0,enum functions a1){ | |
| 740 | + volatile float a0,v0; | |
| 741 | + ((int*)(&a0))[0]=ia0; | |
| 742 | + ((int*)(&v0))[0]=iv0; | |
| 743 | + switch(a1){ | |
| 744 | + case FUNC_FLOAT: | |
| 745 | + v0=(float)iv0; | |
| 746 | + break; | |
| 747 | + case FUNC_INT: | |
| 748 | + return (int)v0; | |
| 749 | + case FUNC_VALSHARP: | |
| 750 | + v0=strtof((const char*)iv0,0); | |
| 751 | + break; | |
| 752 | + case FUNC_SIN: | |
| 753 | + v0=sinf(v0); | |
| 754 | + break; | |
| 755 | + case FUNC_COS: | |
| 756 | + v0=cosf(v0); | |
| 757 | + break; | |
| 758 | + case FUNC_TAN: | |
| 759 | + v0=tanf(v0); | |
| 760 | + break; | |
| 761 | + case FUNC_ASIN: | |
| 762 | + v0=asinf(v0); | |
| 763 | + break; | |
| 764 | + case FUNC_ACOS: | |
| 765 | + v0=acosf(v0); | |
| 766 | + break; | |
| 767 | + case FUNC_ATAN: | |
| 768 | + v0=atanf(v0); | |
| 769 | + break; | |
| 770 | + case FUNC_SINH: | |
| 771 | + v0=sinhf(v0); | |
| 772 | + break; | |
| 773 | + case FUNC_COSH: | |
| 774 | + v0=coshf(v0); | |
| 775 | + break; | |
| 776 | + case FUNC_TANH: | |
| 777 | + v0=tanhf(v0); | |
| 778 | + break; | |
| 779 | + case FUNC_EXP: | |
| 780 | + v0=expf(v0); | |
| 781 | + break; | |
| 782 | + case FUNC_LOG: | |
| 783 | + v0=logf(v0); | |
| 784 | + break; | |
| 785 | + case FUNC_LOG10: | |
| 786 | + v0=log10f(v0); | |
| 787 | + break; | |
| 788 | + case FUNC_POW: | |
| 789 | + v0=powf(v0,a0); | |
| 790 | + break; | |
| 791 | + case FUNC_SQRT: | |
| 792 | + v0=sqrtf(v0); | |
| 793 | + break; | |
| 794 | + case FUNC_CEIL: | |
| 795 | + v0=ceilf(v0); | |
| 796 | + break; | |
| 797 | + case FUNC_FLOOR: | |
| 798 | + v0=floorf(v0); | |
| 799 | + break; | |
| 800 | + case FUNC_FABS: | |
| 801 | + v0=fabsf(v0); | |
| 802 | + break; | |
| 803 | + case FUNC_MODF: | |
| 804 | + v0=modff(v0,(void*)&a0); | |
| 805 | + break; | |
| 806 | + case FUNC_FMOD: | |
| 807 | + v0=fmodf(v0,a0); | |
| 808 | + break; | |
| 809 | + default: | |
| 810 | + err_unknown(); | |
| 811 | + break; | |
| 812 | + } | |
| 813 | + return ((int*)(&v0))[0]; | |
| 814 | +}; | |
| 815 | + | |
| 816 | +int* lib_dim(int varnum, int argsnum, int* sp){ | |
| 817 | + int i,j; | |
| 818 | + static int* heap; | |
| 819 | + // Calculate total length. | |
| 820 | + int len=0; // Total length | |
| 821 | + int size=1; // Size of current block | |
| 822 | + for(i=1;i<=argsnum;i++){ | |
| 823 | + size*=sp[i]+1; | |
| 824 | + len+=size; | |
| 825 | + } | |
| 826 | + // Allocate memory | |
| 827 | + heap=calloc_memory(len,varnum); | |
| 828 | + // Construct pointers | |
| 829 | + len=0; | |
| 830 | + size=1; | |
| 831 | + for(i=1;i<argsnum;i++){ | |
| 832 | + size*=sp[i]+1; | |
| 833 | + for(j=0;j<size;j++){ | |
| 834 | + heap[len+j]=(int)&heap[len+size+(sp[i+1]+1)*j]; | |
| 835 | + } | |
| 836 | + len+=size; | |
| 837 | + } | |
| 838 | + return heap; | |
| 839 | +}; | |
| 840 | + | |
| 841 | +int _call_library(int a0,int a1,int a2,enum libs a3); | |
| 842 | + | |
| 843 | +void call_library(void){ | |
| 844 | + // Store s6 in g_s6 | |
| 845 | + asm volatile("la $a2,%0"::"i"(&g_s6)); | |
| 846 | + asm volatile("sw $s6,0($a2)"); | |
| 847 | + // Copy $v0 to $a2 as 3rd argument of function | |
| 848 | + asm volatile("addu $a2,$v0,$zero"); | |
| 849 | + asm volatile("j _call_library"); | |
| 850 | +} | |
| 851 | + | |
| 852 | +int _call_library(int a0,int a1,int v0,enum libs a3){ | |
| 853 | + // usage: call_lib_code(LIB_XXXX); | |
| 854 | + // Above code takes 2 words. | |
| 855 | + check_break(); | |
| 856 | + switch(a3){ | |
| 857 | + case LIB_FLOAT: | |
| 858 | + return lib_float(a0,v0,(enum operator)a1); // see operator.c | |
| 859 | + case LIB_FLOATFUNCS: | |
| 860 | + return lib_floatfuncs(a0,v0,(enum functions)a1); | |
| 861 | + case LIB_STRNCMP: | |
| 862 | + return strncmp((char*)a0,(char*)a1,v0); | |
| 863 | + case LIB_MIDSTR: | |
| 864 | + return (int)lib_midstr(a1,v0,a0); | |
| 865 | + case LIB_RND: | |
| 866 | + return (int)lib_rnd(); | |
| 867 | + case LIB_DEC: | |
| 868 | + return (int)lib_dec(v0); | |
| 869 | + case LIB_HEX: | |
| 870 | + return (int)lib_hex(v0,a0); | |
| 871 | + case LIB_CHR: | |
| 872 | + return (int)lib_chr(v0); | |
| 873 | + case LIB_VAL: | |
| 874 | + return lib_val((char*)v0); | |
| 875 | + case LIB_LETSTR: | |
| 876 | + lib_let_str((char*)v0,a0); | |
| 877 | + return; | |
| 878 | + case LIB_CONNECT_STRING: | |
| 879 | + return (int)lib_connect_string((char*)a0, (char*)v0); | |
| 880 | + case LIB_STRING: | |
| 881 | + lib_string(a0); | |
| 882 | + return v0; | |
| 883 | + case LIB_PRINTSTR: | |
| 884 | + printstr((char*)v0); | |
| 885 | + return v0; | |
| 886 | + case LIB_GRAPHIC: | |
| 887 | + return lib_graphic(a0,a1,v0); | |
| 888 | + case LIB_SPRINTF: | |
| 889 | + return (int)lib_sprintf((char*)v0,a0); | |
| 890 | + case LIB_VAR_PUSH: | |
| 891 | + lib_var_push((int*)a1,a0); | |
| 892 | + return v0; | |
| 893 | + case LIB_VAR_POP: | |
| 894 | + lib_var_pop((int*)a1); | |
| 895 | + return v0; | |
| 896 | + case LIB_SCROLL: | |
| 897 | + lib_scroll(a0,v0); | |
| 898 | + return v0; | |
| 899 | + case LIB_KEYS: | |
| 900 | + return lib_keys(v0); | |
| 901 | + case LIB_INKEY: | |
| 902 | + return (int)lib_inkey(v0); | |
| 903 | + case LIB_CURSOR: | |
| 904 | + setcursor(a0,v0,cursorcolor); | |
| 905 | + return v0; | |
| 906 | + case LIB_SOUND: | |
| 907 | + set_sound((unsigned long*)v0); | |
| 908 | + return v0; | |
| 909 | + case LIB_MUSICFUNC: | |
| 910 | + return musicRemaining(); | |
| 911 | + case LIB_MUSIC: | |
| 912 | + set_music((char*)v0); | |
| 913 | + return v0; | |
| 914 | + case LIB_SETDRAWCOUNT: | |
| 915 | + drawcount=(v0&0x0000FFFF); | |
| 916 | + return v0; | |
| 917 | + case LIB_DRAWCOUNT: | |
| 918 | + return drawcount; | |
| 919 | + case LIB_SYSTEM: | |
| 920 | + return lib_system(a0,v0); | |
| 921 | + case LIB_RESTORE: | |
| 922 | + return lib_read(0,v0); | |
| 923 | + case LIB_RESTORE2: | |
| 924 | + return lib_read(1,v0); | |
| 925 | + case LIB_READ: | |
| 926 | + return lib_read(0,0); | |
| 927 | + case LIB_CREAD: | |
| 928 | + return lib_read(1,0); | |
| 929 | + case LIB_LABEL: | |
| 930 | + return (int)lib_label(v0); | |
| 931 | + case LIB_INPUT: | |
| 932 | + return (int)lib_input(); | |
| 933 | + case LIB_USEGRAPHIC: | |
| 934 | + lib_usegraphic(v0); | |
| 935 | + return v0; | |
| 936 | + case LIB_USEPCG: | |
| 937 | + lib_usepcg(v0); | |
| 938 | + return v0; | |
| 939 | + case LIB_PCG: | |
| 940 | + lib_pcg(a0,a1,v0); | |
| 941 | + return v0; | |
| 942 | + case LIB_BGCOLOR: // BGCOLOR R,G,B | |
| 943 | + set_bgcolor(v0,a0,a1); //set_bgcolor(b,r,g); | |
| 944 | + return v0; | |
| 945 | + case LIB_PALETTE: // PALETTE N,R,G,B | |
| 946 | + set_palette(a0,v0,(a1>>16)&255,a1&255); // set_palette(n,b,r,g); | |
| 947 | + return v0; | |
| 948 | + case LIB_GPALETTE:// GPALETTE N,R,G,B | |
| 949 | + if (g_graphic_area) g_set_palette(a0,v0,(a1>>16)&255,a1&255); // g_set_palette(n,b,r,g); | |
| 950 | + return v0; | |
| 951 | + case LIB_CLS: | |
| 952 | + clearscreen(); | |
| 953 | + return v0; | |
| 954 | + case LIB_GCLS: | |
| 955 | + if (g_graphic_area) g_clearscreen(); | |
| 956 | + g_prev_x=g_prev_y=0; | |
| 957 | + return v0; | |
| 958 | + case LIB_COLOR: | |
| 959 | + setcursorcolor(v0); | |
| 960 | + return v0; | |
| 961 | + case LIB_GCOLOR: | |
| 962 | + g_gcolor=v0; | |
| 963 | + return v0; | |
| 964 | + case LIB_WAIT: | |
| 965 | + lib_wait(v0); | |
| 966 | + return v0; | |
| 967 | + case LIB_CLEAR: | |
| 968 | + lib_clear(); | |
| 969 | + return v0; | |
| 970 | + case LIB_DIM: | |
| 971 | + return (int)lib_dim(a0,a1,(int*)v0); | |
| 972 | +#ifdef __DEBUG | |
| 973 | + case LIB_DEBUG: | |
| 974 | + asm volatile("nop"); | |
| 975 | + return v0; | |
| 976 | +#endif | |
| 977 | + case LIB_DIV0: | |
| 978 | + err_div_zero(); | |
| 979 | + return v0; | |
| 980 | + default: | |
| 981 | + err_unknown(); | |
| 982 | + return v0; | |
| 983 | + } | |
| 984 | +} | |
| \ No newline at end of file |
| @@ -0,0 +1,483 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include <xc.h> | |
| 9 | +#include "compiler.h" | |
| 10 | +#include "api.h" | |
| 11 | + | |
| 12 | +/* | |
| 13 | + Timer3: 1/32 prescaler, toggle mode : 894886.25 Hz | |
| 14 | + PR3=2047 <-> 437 Hz | |
| 15 | + Timer4: 1/32 prescaler: 1789772.5 Hz | |
| 16 | + Timer4 29737 counts: 262 NTSC lines. | |
| 17 | +*/ | |
| 18 | + | |
| 19 | +/* | |
| 20 | + c: 1722 | |
| 21 | + B: 1825 | |
| 22 | + A#: 1933 | |
| 23 | + A: 2048 | |
| 24 | + G#: 2170 | |
| 25 | + G: 2299 | |
| 26 | + F#: 2435 | |
| 27 | + F: 2580 | |
| 28 | + E: 2734 | |
| 29 | + D#: 2896 | |
| 30 | + D: 3067 | |
| 31 | + C#: 3251 | |
| 32 | + C: 3444 | |
| 33 | + Cb: 3650 | |
| 34 | +*/ | |
| 35 | + | |
| 36 | +const static int g_keys[]={ | |
| 37 | + 1933,1722,3251,2896,2580,2435,2170,// 0 7# C# A#m | |
| 38 | + 1933,1825,3251,2896,2580,2435,2170,// 7 6# F# D#m | |
| 39 | + 1933,1825,3251,2896,2734,2435,2170,// 14 5# B G#m | |
| 40 | + 2048,1825,3251,2896,2734,2435,2170,// 21 4# E C#m | |
| 41 | + 2048,1825,3251,3067,2734,2435,2170,// 28 3# A F#m | |
| 42 | + 2048,1825,3251,3067,2734,2435,2299,// 35 2# D Bm | |
| 43 | + 2048,1825,3444,3067,2734,2435,2299,// 42 1# G Em | |
| 44 | + 2048,1825,3444,3067,2734,2580,2299,// 49 0 C Am | |
| 45 | + 2048,1933,3444,3067,2734,2580,2299,// 56 1b F Dm | |
| 46 | + 2048,1933,3444,3067,2896,2580,2299,// 63 2b Bb Gm | |
| 47 | + 2170,1933,3444,3067,2896,2580,2299,// 70 3b Eb Cm | |
| 48 | + 2170,1933,3444,3251,2896,2580,2299,// 77 4b Ab Fm | |
| 49 | + 2170,1933,3444,3251,2896,2580,2435,// 84 5b Db Bbm | |
| 50 | + 2170,1933,3650,3251,2896,2580,2435,// 91 6b Gb Ebm | |
| 51 | + 2170,1933,3650,3251,2896,2734,2435 // 98 7b Cb Abm | |
| 52 | +}; | |
| 53 | + | |
| 54 | +/* | |
| 55 | + 2^(1/12) ~= 69433/(2^16) | |
| 56 | + 1/(2^(1/12) ~= 1933/(2^11) | |
| 57 | +*/ | |
| 58 | + | |
| 59 | +#define toneFlat(x) ((((unsigned long)x)*69433)>>16) | |
| 60 | +#define toneSharp(x) ((((unsigned long)x)*1933)>>11) | |
| 61 | + | |
| 62 | +/* local global vars */ | |
| 63 | +static int* g_tones; | |
| 64 | +static int g_qvalue; | |
| 65 | +static int g_lvalue; | |
| 66 | +static int g_mpoint; | |
| 67 | +static char* g_mstr; | |
| 68 | +static int g_mspos; | |
| 69 | +static unsigned short g_music[32]; | |
| 70 | +static unsigned short g_sound[32]; | |
| 71 | +static unsigned short g_musiclen[32]; | |
| 72 | +static unsigned char g_soundlen[32]; | |
| 73 | +static int g_musicstart; | |
| 74 | +static int g_musicend; | |
| 75 | +static int g_musicwait; | |
| 76 | +static int g_soundstart; | |
| 77 | +static int g_soundend; | |
| 78 | +static int g_soundwait; | |
| 79 | +static int g_soundrepeat; | |
| 80 | + | |
| 81 | +int musicRemaining(){ | |
| 82 | + return (g_musicend-g_musicstart)&31; | |
| 83 | +} | |
| 84 | + | |
| 85 | +#pragma interrupt timer4int IPL3SOFT vector 16 | |
| 86 | +void timer4int(){ | |
| 87 | + unsigned int i; | |
| 88 | + // This function is called every 1/60 sec. | |
| 89 | + IFS0CLR=_IFS0_T4IF_MASK; //IFS0bits.T4IF=0; | |
| 90 | + if (g_soundstart!=g_soundend){ | |
| 91 | + // Start timer & OC4 | |
| 92 | + i=g_sound[g_soundstart]; | |
| 93 | + if (i<0xffff) { | |
| 94 | + T3CONSET=0x8000; | |
| 95 | + PR3=i; | |
| 96 | + if (i<TMR3) TMR3=0; | |
| 97 | + } else { | |
| 98 | + T3CONCLR=0x8000; | |
| 99 | + } | |
| 100 | + if ((--g_soundwait)<=0) { | |
| 101 | + g_soundstart++; | |
| 102 | + if (g_soundstart==g_soundend || 31<g_soundstart) { | |
| 103 | + g_soundstart=0; | |
| 104 | + g_soundrepeat--; | |
| 105 | + if (0<g_soundrepeat) { | |
| 106 | + g_soundwait=g_soundlen[g_soundstart]; | |
| 107 | + } else { | |
| 108 | + g_soundend=g_soundrepeat=g_soundwait=0; | |
| 109 | + } | |
| 110 | + } else { | |
| 111 | + g_soundwait=g_soundlen[g_soundstart]; | |
| 112 | + } | |
| 113 | + } | |
| 114 | + // Shift music data even though without output. | |
| 115 | + if (g_musicstart!=g_musicend) { | |
| 116 | + if ((--g_musicwait)<=0) { | |
| 117 | + g_musicstart++; | |
| 118 | + g_musicstart&=31; | |
| 119 | + g_musicwait=g_musiclen[g_musicstart]; | |
| 120 | + } | |
| 121 | + } | |
| 122 | + } else if (g_musicstart!=g_musicend) { | |
| 123 | + // Start timer & OC4 | |
| 124 | + i=g_music[g_musicstart]; | |
| 125 | + if (i<0xffff) { | |
| 126 | + T3CONSET=0x8000; | |
| 127 | + PR3=i; | |
| 128 | + if (i<TMR3) TMR3=0; | |
| 129 | + } else { | |
| 130 | + T3CONCLR=0x8000; | |
| 131 | + } | |
| 132 | + if ((--g_musicwait)<=0) { | |
| 133 | + g_musicstart++; | |
| 134 | + g_musicstart&=31; | |
| 135 | + g_musicwait=g_musiclen[g_musicstart]; | |
| 136 | + } | |
| 137 | + } else { | |
| 138 | + // Stop timer | |
| 139 | + T3CONCLR=0x8000; | |
| 140 | + } | |
| 141 | +} | |
| 142 | + | |
| 143 | +int musicGetNum(){ | |
| 144 | + int i, ret; | |
| 145 | + char b; | |
| 146 | + // Skip non number character | |
| 147 | + for(i=0;(b=g_mstr[g_mspos+i])<'0' && '9'<g_mstr[g_mspos+i];i++); | |
| 148 | + // Determine the number | |
| 149 | + ret=0; | |
| 150 | + while('0'<=b && b<='9'){ | |
| 151 | + ret*=10; | |
| 152 | + ret+=b-'0'; | |
| 153 | + i++; | |
| 154 | + b=g_mstr[g_mspos+i]; | |
| 155 | + } | |
| 156 | + g_mspos+=i; | |
| 157 | + return ret; | |
| 158 | +} | |
| 159 | + | |
| 160 | +void init_music(){ | |
| 161 | + // Use Timer3 and OC4 for sound. | |
| 162 | + RPB13R=5; //Use RPB13 for OC4 | |
| 163 | + OC4R=0; | |
| 164 | + OC4CON=0x000b; // Timer3, toggle mode | |
| 165 | + OC4CONSET=0x8000;// Start OC4 | |
| 166 | + T3CON=0x0050; // Prescaller: 1:32 (1.8 MHz), not yet started | |
| 167 | + | |
| 168 | + // Timer4 is used to intterupt every 1/60 sec, just after NTSC view. | |
| 169 | + T4CON=0x0040; // Prescaller: 1:16 | |
| 170 | + PR4=59473; // 3632*262/16-1 | |
| 171 | + // Timer 4 interruption, IPL3 | |
| 172 | + IPC4bits.T4IP=3; | |
| 173 | + IPC4bits.T4IS=0; | |
| 174 | + IFS0bits.T4IF=0; | |
| 175 | + IEC0bits.T4IE=1; | |
| 176 | + // Wait until end of NTSC view. | |
| 177 | + while(!drawing); | |
| 178 | + while(drawing); | |
| 179 | + T4CONSET=0x8000; // Start timer 4. | |
| 180 | + | |
| 181 | + // Initializations for music/sound. | |
| 182 | + g_qvalue=160; // Q: 1/4=90 | |
| 183 | + g_lvalue=20; // L: 1/8 | |
| 184 | + g_tones=(int*)&(g_keys[49]); // C major | |
| 185 | + g_musicstart=g_musicend=g_musicwait=g_soundstart=g_soundend=g_soundwait=g_soundrepeat=0; | |
| 186 | +} | |
| 187 | + | |
| 188 | +void musicSetL(){ | |
| 189 | + // Set length of a character. | |
| 190 | + // Syntax: L:n/m, where n and m are numbers. | |
| 191 | + int n,m; | |
| 192 | + n=musicGetNum(); | |
| 193 | + g_mspos++; | |
| 194 | + m=musicGetNum(); | |
| 195 | + g_lvalue=g_qvalue*n/m; | |
| 196 | +} | |
| 197 | + | |
| 198 | +void musicSetQ(){ | |
| 199 | + int i; | |
| 200 | + // Syntax: Q:1/4=n, where n is number. | |
| 201 | + // Skip "1/4=" | |
| 202 | + for(i=0;g_mstr[g_mspos+i]!='=';i++); | |
| 203 | + g_mspos+=i+1; | |
| 204 | + i=musicGetNum(); | |
| 205 | + if (i<48) { g_qvalue=320; /* 1/4=45 */ } | |
| 206 | + else if (i<53) { g_qvalue=288; /* 1/4=50 */ } | |
| 207 | + else if (i<60) { g_qvalue=256; /* 1/4=56 */ } | |
| 208 | + else if (i<70) { g_qvalue=224; /* 1/4=64 */ } | |
| 209 | + else if (i<83) { g_qvalue=192; /* 1/4=75 */ } | |
| 210 | + else if (i<102) { g_qvalue=160; /* 1/4=90 */ } | |
| 211 | + else if (i<132) { g_qvalue=128; /* 1/4=113 */ } | |
| 212 | + else if (i<188) { g_qvalue=96; /* 1/4=150 */ } | |
| 213 | + else { g_qvalue=64; /* 1/4=225 */ } | |
| 214 | + g_lvalue=g_qvalue>>3; | |
| 215 | +} | |
| 216 | + | |
| 217 | +void musicSetK(){ | |
| 218 | + // Syntax: K:xxx | |
| 219 | + if (!strncmp((char*)&(g_mstr[g_mspos]),"A#m",3)) { | |
| 220 | + g_mspos+=3; | |
| 221 | + g_tones=(int*)&(g_keys[0]); | |
| 222 | + return; | |
| 223 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"D#m",3)) { | |
| 224 | + g_mspos+=3; | |
| 225 | + g_tones=(int*)&(g_keys[7]); | |
| 226 | + return; | |
| 227 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"G#m",3)) { | |
| 228 | + g_mspos+=3; | |
| 229 | + g_tones=(int*)&(g_keys[14]); | |
| 230 | + return; | |
| 231 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"C#m",3)) { | |
| 232 | + g_mspos+=3; | |
| 233 | + g_tones=(int*)&(g_keys[21]); | |
| 234 | + return; | |
| 235 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"F#m",3)) { | |
| 236 | + g_mspos+=3; | |
| 237 | + g_tones=(int*)&(g_keys[28]); | |
| 238 | + return; | |
| 239 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Bbm",3)) { | |
| 240 | + g_mspos+=3; | |
| 241 | + g_tones=(int*)&(g_keys[84]); | |
| 242 | + return; | |
| 243 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Ebm",3)) { | |
| 244 | + g_mspos+=3; | |
| 245 | + g_tones=(int*)&(g_keys[91]); | |
| 246 | + return; | |
| 247 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Abm",3)) { | |
| 248 | + g_mspos+=3; | |
| 249 | + g_tones=(int*)&(g_keys[98]); | |
| 250 | + return; | |
| 251 | + } | |
| 252 | + if (!strncmp((char*)&(g_mstr[g_mspos]),"C#",2)) { | |
| 253 | + g_mspos+=2; | |
| 254 | + g_tones=(int*)&(g_keys[0]); | |
| 255 | + return; | |
| 256 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"F#",2)) { | |
| 257 | + g_mspos+=2; | |
| 258 | + g_tones=(int*)&(g_keys[7]); | |
| 259 | + return; | |
| 260 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Bm",2)) { | |
| 261 | + g_mspos+=2; | |
| 262 | + g_tones=(int*)&(g_keys[35]); | |
| 263 | + return; | |
| 264 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Em",2)) { | |
| 265 | + g_mspos+=2; | |
| 266 | + g_tones=(int*)&(g_keys[42]); | |
| 267 | + return; | |
| 268 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Am",2)) { | |
| 269 | + g_mspos+=2; | |
| 270 | + g_tones=(int*)&(g_keys[49]); | |
| 271 | + return; | |
| 272 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Dm",2)) { | |
| 273 | + g_mspos+=2; | |
| 274 | + g_tones=(int*)&(g_keys[56]); | |
| 275 | + return; | |
| 276 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Gm",2) || !strncmp((char*)&(g_mstr[g_mspos]),"Bb",2)) { | |
| 277 | + g_mspos+=2; | |
| 278 | + g_tones=(int*)&(g_keys[63]); | |
| 279 | + return; | |
| 280 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Cm",2) || !strncmp((char*)&(g_mstr[g_mspos]),"Eb",2)) { | |
| 281 | + g_mspos+=2; | |
| 282 | + g_tones=(int*)&(g_keys[70]); | |
| 283 | + return; | |
| 284 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Fm",2) || !strncmp((char*)&(g_mstr[g_mspos]),"Ab",2)) { | |
| 285 | + g_mspos+=2; | |
| 286 | + g_tones=(int*)&(g_keys[77]); | |
| 287 | + return; | |
| 288 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Db",2)) { | |
| 289 | + g_mspos+=2; | |
| 290 | + g_tones=(int*)&(g_keys[84]); | |
| 291 | + return; | |
| 292 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Gb",2)) { | |
| 293 | + g_mspos+=2; | |
| 294 | + g_tones=(int*)&(g_keys[91]); | |
| 295 | + return; | |
| 296 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Cb",2)) { | |
| 297 | + g_mspos+=2; | |
| 298 | + g_tones=(int*)&(g_keys[98]); | |
| 299 | + return; | |
| 300 | + } | |
| 301 | + switch(g_mstr[g_mspos]){ | |
| 302 | + case 'B': | |
| 303 | + g_mspos++; | |
| 304 | + g_tones=(int*)&(g_keys[14]); | |
| 305 | + return; | |
| 306 | + case 'E': | |
| 307 | + g_mspos++; | |
| 308 | + g_tones=(int*)&(g_keys[21]); | |
| 309 | + return; | |
| 310 | + case 'A': | |
| 311 | + g_mspos++; | |
| 312 | + g_tones=(int*)&(g_keys[28]); | |
| 313 | + return; | |
| 314 | + case 'D': | |
| 315 | + g_mspos++; | |
| 316 | + g_tones=(int*)&(g_keys[35]); | |
| 317 | + return; | |
| 318 | + case 'G': | |
| 319 | + g_mspos++; | |
| 320 | + g_tones=(int*)&(g_keys[42]); | |
| 321 | + return; | |
| 322 | + case 'C': | |
| 323 | + g_mspos++; | |
| 324 | + g_tones=(int*)&(g_keys[49]); | |
| 325 | + return; | |
| 326 | + case 'F': | |
| 327 | + g_mspos++; | |
| 328 | + g_tones=(int*)&(g_keys[56]); | |
| 329 | + return; | |
| 330 | + default: | |
| 331 | + err_music(g_mstr); | |
| 332 | + break; | |
| 333 | + } | |
| 334 | +} | |
| 335 | +void musicSetM(){ | |
| 336 | + // Currently do nothing | |
| 337 | + musicGetNum(); | |
| 338 | + musicGetNum(); | |
| 339 | +} | |
| 340 | + | |
| 341 | +void set_sound(unsigned long* data){ | |
| 342 | + int sound; | |
| 343 | + int len; | |
| 344 | + int pos; | |
| 345 | + int datalen; | |
| 346 | + IEC0bits.T4IE=0; // Stop interruption, first. | |
| 347 | + // Initialize | |
| 348 | + g_soundrepeat=g_soundstart=g_soundend=0; | |
| 349 | + pos=0; | |
| 350 | + do { | |
| 351 | + while(data[1]!=0x00000020) data++; // Seek DATA statement | |
| 352 | + datalen=(data[0]&0x00007FFF)-1; // Use bgezal statement containing data length. | |
| 353 | + data+=2; | |
| 354 | + while(0<datalen){ | |
| 355 | + datalen--; | |
| 356 | + len=data[0]>>16; | |
| 357 | + sound=data[0]&0x0000FFFF; | |
| 358 | + data++; | |
| 359 | + if (len) { | |
| 360 | + // Shift tone if graphic is used | |
| 361 | + if (g_use_graphic) { | |
| 362 | + // MUL_15 instead of MUL_16 for CPU clock. | |
| 363 | + // sound=sound*15/16 | |
| 364 | + sound-=(sound+7)>>4; | |
| 365 | + } | |
| 366 | + g_sound[pos]=sound-1; | |
| 367 | + g_soundlen[pos]=len; | |
| 368 | + pos++; | |
| 369 | + if (32<pos) { | |
| 370 | + err_music("Sound data too long."); | |
| 371 | + return; | |
| 372 | + } | |
| 373 | + } else { | |
| 374 | + g_soundrepeat=sound; | |
| 375 | + break; | |
| 376 | + } | |
| 377 | + } | |
| 378 | + } while(len); | |
| 379 | + g_soundend=pos; | |
| 380 | + g_soundwait=g_soundlen[0]; | |
| 381 | + IEC0bits.T4IE=1; // Restart interrupt. | |
| 382 | +} | |
| 383 | + | |
| 384 | +void set_music(char* str){ | |
| 385 | + char b; | |
| 386 | + unsigned long tone,tonenatural; | |
| 387 | + int len; | |
| 388 | + g_mstr=str; | |
| 389 | + g_mspos=0; | |
| 390 | + while(0<(b=g_mstr[g_mspos])){ | |
| 391 | + if (g_mstr[g_mspos+1]==':') { | |
| 392 | + // Set property | |
| 393 | + g_mspos+=2; | |
| 394 | + switch(b){ | |
| 395 | + case 'L': | |
| 396 | + musicSetL(); | |
| 397 | + break; | |
| 398 | + case 'Q': | |
| 399 | + musicSetQ(); | |
| 400 | + break; | |
| 401 | + case 'K': | |
| 402 | + musicSetK(); | |
| 403 | + break; | |
| 404 | + case 'M': | |
| 405 | + musicSetM(); | |
| 406 | + break; | |
| 407 | + default: | |
| 408 | + err_music(str); | |
| 409 | + break; | |
| 410 | + } | |
| 411 | + } else if ('A'<=b && b<='G' || 'a'<=b && b<='g' || b=='z') { | |
| 412 | + g_mspos++; | |
| 413 | + if (b=='z') { | |
| 414 | + tone=0; | |
| 415 | + } else if (b<='G') { | |
| 416 | + tone=g_tones[b-'A']; | |
| 417 | + tonenatural=g_keys[b-'A'+49]; | |
| 418 | + } else { | |
| 419 | + tone=g_tones[b-'a']>>1; | |
| 420 | + tonenatural=g_keys[b-'a'+49]>>1; | |
| 421 | + } | |
| 422 | + // Check "'"s | |
| 423 | + while(g_mstr[g_mspos]=='\''){ | |
| 424 | + g_mspos++; | |
| 425 | + tone>>=1; | |
| 426 | + } | |
| 427 | + // Check ","s | |
| 428 | + while(g_mstr[g_mspos]==','){ | |
| 429 | + g_mspos++; | |
| 430 | + tone<<=1; | |
| 431 | + tonenatural<<=1; | |
| 432 | + } | |
| 433 | + // Check "^","=","_" | |
| 434 | + switch(g_mstr[g_mspos]){ | |
| 435 | + case '^': | |
| 436 | + g_mspos++; | |
| 437 | + tone=toneSharp(tone); | |
| 438 | + break; | |
| 439 | + case '_': | |
| 440 | + g_mspos++; | |
| 441 | + tone=toneFlat(tone); | |
| 442 | + break; | |
| 443 | + case '=': | |
| 444 | + g_mspos++; | |
| 445 | + tone=tonenatural; | |
| 446 | + break; | |
| 447 | + default: | |
| 448 | + break; | |
| 449 | + } | |
| 450 | + // Check number for length | |
| 451 | + b=g_mstr[g_mspos]; | |
| 452 | + if ('0'<=b && b<='9') { | |
| 453 | + len=g_lvalue*musicGetNum(); | |
| 454 | + } else { | |
| 455 | + len=g_lvalue; | |
| 456 | + } | |
| 457 | + if (g_mstr[g_mspos]=='/') { | |
| 458 | + g_mspos++; | |
| 459 | + len=len/musicGetNum(); | |
| 460 | + } | |
| 461 | + // Shift tone if graphic is used | |
| 462 | + if (g_use_graphic) { | |
| 463 | + // MUL_15 instead of MUL_16 for CPU clock. | |
| 464 | + // tone=tone*15/16 | |
| 465 | + tone-=(tone+7)>>4; | |
| 466 | + } | |
| 467 | + // Update music value array | |
| 468 | + IEC0bits.T4IE=0; // Stop interruption, first. | |
| 469 | + if (g_musicstart==g_musicend) { | |
| 470 | + g_musicwait=len; | |
| 471 | + } | |
| 472 | + g_music[g_musicend]=(tone-1)&0x0000FFFF; | |
| 473 | + g_musiclen[g_musicend]=len; | |
| 474 | + g_musicend++; | |
| 475 | + g_musicend&=31; | |
| 476 | + IEC0bits.T4IE=1; // Restart interruption. | |
| 477 | + } else { | |
| 478 | + err_music(str); | |
| 479 | + } | |
| 480 | + // Go to next character | |
| 481 | + while(0<g_mstr[g_mspos] && g_mstr[g_mspos]<=0x20 || g_mstr[g_mspos]=='|') g_mspos++; | |
| 482 | + } | |
| 483 | +} | |
| \ No newline at end of file |
| @@ -0,0 +1,585 @@ | ||
| 1 | +<BASIC言語の書式> | |
| 2 | +BASICプログラムの記述は、行番号式、ラベル式、その混合、いずれの方法でも構 | |
| 3 | +いません。以下、仕様について述べます。 | |
| 4 | + | |
| 5 | +<利用可能な変数型> | |
| 6 | +利用できる変数の型は、32ビット符号付整数(-2147483648 以上 +2147483647 以 | |
| 7 | +下)と、文字列型の2種類です。文字列の末端部には0x00が付加されます。 | |
| 8 | + | |
| 9 | +A-Zの26個の整数型変数が利用可能です。文字列として扱う場合はA$のように記 | |
| 10 | +述します。ただし、A(整数型)とA$(文字列型)を同時に使用することは出来ま | |
| 11 | +せん。 | |
| 12 | + | |
| 13 | +整数型の定数は、10進法で記述します。16進法を使う場合、「$1200」のよう | |
| 14 | +に、頭に「$」を付加するか、「0x1200」の様に表記して下さい。 | |
| 15 | + | |
| 16 | +文字列型の定数は、「"」で囲って記述してください。「"」を使用する場合は、 | |
| 17 | +「CHR$($22)」のように記述することが出来ます。 | |
| 18 | + | |
| 19 | +<命令> | |
| 20 | +以下、x, y, z等は整数値を、x$, y$, z$は文字列を、x#, y#, z#は浮動 | |
| 21 | +小数点型実数値を指します。xxx, yyy, zzz, www等は任意のステートメントを | |
| 22 | +指します。[ ]は省略可能である事を示します。 | |
| 23 | + | |
| 24 | +命令同士を「:」で区切ることにより、一行で複数のコマンドを処理すること | |
| 25 | +が出来ます。 | |
| 26 | + | |
| 27 | +BGCOLOR r,g,b | |
| 28 | + 背景色指定。 | |
| 29 | +BREAK | |
| 30 | + FOR-NEXT, DO-LOOP, WHILE-WENDループから抜け出す。 | |
| 31 | +CDATA x[,y[,z[...]]] | |
| 32 | + データー列を8ビット整数値で指定する。 | |
| 33 | +CLEAR | |
| 34 | + すべての文字列型変数と整数型配列を破棄し、整数値を0とする。また、 | |
| 35 | + PCGの使用をやめ、表示キャラクターをリセットする。 | |
| 36 | +CLS | |
| 37 | + スクリーン消去。 | |
| 38 | +COLOR x | |
| 39 | + テキスト色指定。 | |
| 40 | +CURSOR x,y | |
| 41 | + カーソル位置指定。 | |
| 42 | +CDATA xxx[,yyy[,zzz[...]]] | |
| 43 | + データー列を8ビット整数値で指定する。 | |
| 44 | +DATA xxx[,yyy[,zzz[...]]] | |
| 45 | + データー列を整数値もしくは文字列で指定する。 | |
| 46 | +DIM xxx [, yyy [, zzz [, ... ]]] | |
| 47 | + 整数型もしくは浮動小数点型の配列を割り当てる。 | |
| 48 | + xxx,yyy,zzzは、例えば「A(10)」のように記述する。この場合、A(0)から | |
| 49 | + A(10)までの11個の整数型変数が確保される。浮動小数点型配列の場合は、 | |
| 50 | + 「A#(10)」の様に記述する。多次元配列も、宣言することが出来る。 | |
| 51 | +DO WHILE x | |
| 52 | +LOOP | |
| 53 | + x が0以外の場合、DO文からLOOP文までのステートメントを繰り返し実行する。 | |
| 54 | +DO UNTIL x | |
| 55 | +LOOP | |
| 56 | + x が0の場合、DO文からLOOP文までのステートメントを繰り返し実行する。 | |
| 57 | +DO | |
| 58 | +LOOP WHILE x | |
| 59 | + DO文からLOOP文までのステートメントを実行し、x が0以外の場合、繰り返す。 | |
| 60 | +DO | |
| 61 | +LOOP UNTIL x | |
| 62 | + DO文からLOOP文までのステートメントを実行し、x が0の場合、繰り返す。 | |
| 63 | +DRAWCOUNT | |
| 64 | + DRAWCOUNT値を指定する。DRAWCOUNT値に付いては、DRAWCOUNT()関数を | |
| 65 | + 参照。 | |
| 66 | +END | |
| 67 | + BASICプログラムを停止する。 | |
| 68 | +EXEC x[,y[,z[...]]] | |
| 69 | + 機械語を実行する。ただし、x,y,zは32ビット整数値。 | |
| 70 | +FOR x=yyy TO zzz [ STEP www ] | |
| 71 | +NEXT | |
| 72 | + yyyで示された計算結果をxに代入し、xの値がzzzになるまで次のNEXT文 | |
| 73 | + までのステートメントを、繰り返し実行する。繰り返しのたび、xの値は | |
| 74 | + wwwずつ増加する(省略された場合は1ずつ)。「NEXT」の次に何も記述 | |
| 75 | + しないことに注意。 | |
| 76 | +GOSUB xxx [, yyy [, zzz [, ... ]]] | |
| 77 | + 現在の実行位置を記憶し、xxx行目(もしくはラベル)に移動する。yyy, zzz | |
| 78 | + 等は、サブルーチンに引き継がれる引数(ARGS()関数を参照)。 | |
| 79 | +GOTO xxx | |
| 80 | + xxx行目(もしくはラベル)に移動する。 | |
| 81 | +IF xまたはx# THEN yyy [ ELSE zzz ] | |
| 82 | + xが0以外のとき、yyyを、0のときzzzを実行。yyyおよびzzzは、複数のステート | |
| 83 | + メントを「:」で挟んで記述可能。 | |
| 84 | +IF xまたはx# THEN | |
| 85 | +xxx | |
| 86 | +[ELSEIF yまたはy# THEN | |
| 87 | +yyy] | |
| 88 | +[ELSE | |
| 89 | +zzz] | |
| 90 | +ENDIF | |
| 91 | + xが0以外の時xxxを、それ以外で且つyが0以外の時(記述された場合)yyyを、 | |
| 92 | + それ以外の場合にzzzを実行。ELSEIFステートメントは、複数記述可。各行で、 | |
| 93 | + THENステートメントの次には何も記入しないことに注意。 | |
| 94 | +LABEL xxx | |
| 95 | + GOTO/GOSUBのジャンプ先を登録する。xxxは、英数字6文字以内の文字列。 | |
| 96 | +[LET] x=yyy | |
| 97 | + yで示された計算結果を、x(整数型変数)に代入する。「LET」は省略可。 | |
| 98 | +[LET] x#=yyy | |
| 99 | + yで示された計算結果を、x(不動州数点方型変数)に代入する。「LET」は省略可。 | |
| 100 | +[LET] x$=yyy | |
| 101 | + yyyで示された文字列(もしくは連結結果;連結演算子は「+」)を、x$に | |
| 102 | + 代入する。「LET」は省略可。 | |
| 103 | +MUSIC x$ | |
| 104 | + BGMを演奏する。詳細は、下記<MUSIC>の項を参照。 | |
| 105 | +VAR xxx [, yyy [, zzz [, ... ]]] | |
| 106 | + サブルーチン内で使う、ローカル変数を指定する。xxx, yyy等は、A-Zの | |
| 107 | + アルファベットで指定する。 | |
| 108 | +WHILE x | |
| 109 | +WEND | |
| 110 | + x が0以外の場合、WHILE文からWEND文までのステートメントを繰り返し実行する。 | |
| 111 | +PALETTE n,r,g,b | |
| 112 | + パレット指定。 | |
| 113 | +PCG x,y,z | |
| 114 | + ASCIIコードがxの文字の表示キャラクターを変更する。y,zは、キャラク | |
| 115 | + ターデーター。詳細は、下記<PCG>の項を参照。 | |
| 116 | +POKE x,y | |
| 117 | + xで示される物理的アドレスに、yで示される値(1バイト値)を書き込む。 | |
| 118 | +PRINT [ xまたはx$またはx# [ ,または; [ yまたはy$またはy# [ ... ]]]] | |
| 119 | + ディスプレイに、整数値または文字列を表示する。「;」を使用した場 | |
| 120 | + 合、次の表示が続けて行われる。「,」を使用した場合、10文字ずつ | |
| 121 | + に区切って表示される。どちらも使用しない場合、次の表示は行を変え | |
| 122 | + て行われる。 | |
| 123 | +REM xxx | |
| 124 | + 何も実行しない | |
| 125 | +RESTORE xxx | |
| 126 | + DATA読み出し開始位置を指定。xxxは行番号もしくはラベル。 | |
| 127 | +RETURN | |
| 128 | + 最後に実行されたGOSUB文の次のステートメントに移動する。戻り値を指 | |
| 129 | + 定することがができる。この場合の戻り値はGOSUB()関数にて取得が可能。 | |
| 130 | +SCROLL x,y | |
| 131 | + 画面を横方向、もしくは縦方向(斜めも可)に動かす。動かす方向と大きさ | |
| 132 | + は、x, yでそれぞれ、横方向の移動度、縦方向の移動度として指定する。 | |
| 133 | +SOUND xxx | |
| 134 | + 効果音を再生する。詳細は、下記<SOUND>の項を参照。xxxは行番号もしく | |
| 135 | + はラベル。 | |
| 136 | +SYSTEM x , y | |
| 137 | + 様々なシステム値の設定を行なう。<SYSTEM>の項を参照。 | |
| 138 | +USEGRAPHIC [x] | |
| 139 | + グラフィックディスプレイを使用、もしくは使用停止する。x=0で使用停止、 | |
| 140 | + x=1で使用、x=2で画面とパレットをクリアーして使用、x=3でグラフィック領 | |
| 141 | + 域を確保するが表示はキャラクターディスプレイのまま。ただし、グラフィッ | |
| 142 | + クディスプレイ未使用の状態でx=0の場合は、領域を確保する。xを省略した場 | |
| 143 | + 合は、x=1と同じ。 | |
| 144 | +USEPCG [x] | |
| 145 | + PCGを使用、もしくは使用停止する。x=0で使用停止、x=1で使用、x=2で | |
| 146 | + キャラクターをリセットして使用。xを省略した場合は、x=1と同じ。 | |
| 147 | + | |
| 148 | +WAIT x | |
| 149 | + xで示された時間、プログラムの実行を停止する。xが60の場合、約1秒間 | |
| 150 | + 停止。 | |
| 151 | + | |
| 152 | +<グラフィック関連命令> | |
| 153 | + | |
| 154 | +BOXFILL [x1,y1],x2,y2[,c] | |
| 155 | + 座標(x1,y1),(x2,y2)を対角線とするカラーcで塗られた長方形を描画。 | |
| 156 | +CIRCLE [x,y],r[,c] | |
| 157 | + 座標(x,y)を中心に、半径r、カラーcの円を描画。 | |
| 158 | +CIRCLEFILL [x,y],r[,c] | |
| 159 | + 座標(x,y)を中心に、半径r、カラーcで塗られた円を描画。 | |
| 160 | +GCLS | |
| 161 | + 画面クリアー。 | |
| 162 | +GCOLOR c | |
| 163 | + それぞれの命令で、cを省略した場合の色を指定。 | |
| 164 | +GPALETTE n,r,g,b | |
| 165 | + パレット指定。 | |
| 166 | +GPRINT [x,y],c,bc,s$ | |
| 167 | + 座標(x,y)にカラーcで文字列s$を表示、bc:背景色(負数の場合背景色指定なし)。 | |
| 168 | +LINE [x1,y1],x2,y2[,c] | |
| 169 | + 座標(x1,y1)から(x2,y2)にカラーcで線分を描画。 | |
| 170 | +POINT x,y | |
| 171 | + グラフィック現在位置を、設定する。 | |
| 172 | +PSET [x,y][,c] | |
| 173 | + 座標(x,y)の位置にカラーcで点を描画。 | |
| 174 | +PUTBMP [x,y],m,n,bbb | |
| 175 | + 横m*縦nドットのキャラクター(bbbで指定)を座標(x,y)に表示。 | |
| 176 | + サイズm*nの配列bmpに、単純にカラー番号を並べる。 | |
| 177 | + ただし、カラーが0の部分は透明色として扱う。ただし、bbbはラベル名もし | |
| 178 | + くは配列へのポインター。 | |
| 179 | + | |
| 180 | +<整数型関数> | |
| 181 | +以下、x, y, zは整数値を、x$, y$, z$は文字列を指します。[ ]は省略可能である事 | |
| 182 | +を示します。 | |
| 183 | + | |
| 184 | +ABS(x) | |
| 185 | + xの絶対値を返す。 | |
| 186 | +ARGS(x) | |
| 187 | + サブルーチン中で、GOSUBに渡されたx番目の引数を整数値として取り出す。 | |
| 188 | +ASC(x$) | |
| 189 | + 文字列の最初の一文字の、アスキーコードを返す。 | |
| 190 | +CREAD() | |
| 191 | + DATA文の後から、一つずつデーター(8ビット整数値)を読み出す。「READ()」 | |
| 192 | + 関数も参照。 | |
| 193 | +DRAWCOUNT() | |
| 194 | + DRAWCOUNT値を得る。DRAWCOUNTは16ビット整数値で、1/60秒ごとに1ずつ | |
| 195 | + 増える。 | |
| 196 | +GCOLOR(x,y) | |
| 197 | + グラフィック座標(x,y)の表示中パレット番号を返す。 | |
| 198 | +GOSUB(xxx [, y [, z [, ... ]]]) | |
| 199 | + GOSUB命令と同じだが、戻り値(RETURNを参照)を得ることが出来る。xxxは、 | |
| 200 | + ラベルもしくは行番号。。yyy, zzz 等は、サブルーチンに引き継がれる引数( | |
| 201 | + ARGS()関数を参照)。 | |
| 202 | +INKEY([x]) | |
| 203 | + xを指定しない場合、現在押されているキーのASCII値を返す。押されていな | |
| 204 | + い場合は、0。ASCII値でxを指定した場合、そのキーが押されているかどう | |
| 205 | + かを返す。 | |
| 206 | +INT(x#) | |
| 207 | + 実数値x#を整数値に変換して返す。 | |
| 208 | +KEYS([x]) | |
| 209 | + キー入力を得る。xの値は以下の通り。xを指定しない場合は、x=63と同じ。 | |
| 210 | + KEYUP: 1 | |
| 211 | + KEYDOWN: 2 | |
| 212 | + KEYLEFT: 4 | |
| 213 | + KEYRIGHT: 8 | |
| 214 | + KEYSTART: 16 | |
| 215 | + KEYFIRE: 32 | |
| 216 | +LEN(x$) | |
| 217 | + 文字列の長さを返す。 | |
| 218 | +MUSIC() | |
| 219 | + BGMの演奏の残り数を返す。 | |
| 220 | +NOT(x) | |
| 221 | + x=0の場合に1を、そうでない場合に0を返す。 | |
| 222 | +PEEK(x) | |
| 223 | + xで示される物理アドレスから1バイト読み取り、返す。 | |
| 224 | +READ() | |
| 225 | + DATA文の後から、一つずつデーター(32ビット整数値)を読み出す。「CREAD()」 | |
| 226 | + 関数も参照。 | |
| 227 | +RND() | |
| 228 | + 0から32767までの擬似乱数を返す。 | |
| 229 | +SGN(x) | |
| 230 | + xの符号(-1, 0, または1)を返す。 | |
| 231 | +STRNCMP(x$,y$,z) | |
| 232 | + 2つの文字列のうちz文字分を比較し、結果を返す。同じ文字列の場合は0。 | |
| 233 | +SYSTEM(x) | |
| 234 | + 様々なシステム値を、整数値で返す。「<システム変数>」の項を参照。 | |
| 235 | +TVRAM([x]) | |
| 236 | + ビデオRAMのx番目の内容を、バイト値で返す。xを省略した場合、ビデオ | |
| 237 | + RAMの開始位置の物理アドレスを返す。 | |
| 238 | +VAL(x$) | |
| 239 | + 10進数もしくは16進数文字列としてのx$の値を、整数値で返す。 | |
| 240 | + | |
| 241 | +<浮動小数点型関数> | |
| 242 | +ACOS#(x#) | |
| 243 | + x# の逆余弦を実数値で返す。 | |
| 244 | +ARGS#(x) | |
| 245 | + サブルーチン中で、GOSUBに渡されたx番目の引数を実数値として取り出す。 | |
| 246 | +ASIN#(x#) | |
| 247 | + x# の逆正弦を実数値で返す。 | |
| 248 | +ATAN#(x#) | |
| 249 | + x# の逆正接を実数値で返す。 | |
| 250 | +CEIL#(x#) | |
| 251 | + x# 以上の最小の整数を実数値で返す。 | |
| 252 | +COS#(x#) | |
| 253 | + x# の余弦を実数値で返す。 | |
| 254 | +COSH#(x#) | |
| 255 | + x# の双曲線余弦を実数値で返す。 | |
| 256 | +EXP#(x#) | |
| 257 | + eを底とする x# の指数関数値を実数値で返す。 | |
| 258 | +FABS#(x#) | |
| 259 | + x# の絶対値を実数値で返す。 | |
| 260 | +FLOAT#(x) | |
| 261 | + 整数値 x を浮動小数点型実数値に変換して返す。 | |
| 262 | +FLOOR#(x#) | |
| 263 | + x# 以下の最大の整数を実数値で返す。 | |
| 264 | +FMOD#(x#,y#) | |
| 265 | + x# を y# で割った剰余を実数値で返す。 | |
| 266 | +GOSUB#(xxx [, y [, z [, ... ]]]) | |
| 267 | + GOSUB命令と同じだが、戻り値(RETURNを参照)を得ることが出来る。xxxは、 | |
| 268 | + ラベルもしくは行番号。。yyy, zzz 等は、サブルーチンに引き継がれる引数( | |
| 269 | + ARGS()関数を参照)。 | |
| 270 | +LOG#(x#) | |
| 271 | + x# の自然対数を実数値で返す。 | |
| 272 | +LOG10#(x#) | |
| 273 | + x# の常用対数を実数値で返す。 | |
| 274 | +MODF#(x#) | |
| 275 | + x# の小数部を実数値で返す。 | |
| 276 | +PI# | |
| 277 | + 3.141593を返す。 | |
| 278 | +POW#(x#,y#) | |
| 279 | + x# の y# 乗を実数値で返す。 | |
| 280 | +SIN#(x#) | |
| 281 | + x# の正弦を実数値で返す。 | |
| 282 | +SINH#(x#) | |
| 283 | + x# の双曲線正弦を実数値で返す。 | |
| 284 | +SQRT#(x#) | |
| 285 | + x# の平方根を実数値で返す。 | |
| 286 | +TAN#(x#) | |
| 287 | + x# の正接を実数値で返す。 | |
| 288 | +TANH#(x#) | |
| 289 | + x# の双曲線正接を実数値で返す。 | |
| 290 | +VAL#(x$) | |
| 291 | + 10進数文字列としてのx$の値を、実数値で返す。 | |
| 292 | + | |
| 293 | +<文字列型関数> | |
| 294 | +A$(x [,y])など | |
| 295 | + xの値が0の場合、文字列全体を返す。 | |
| 296 | + xの値が正の場合、xで示される位置より右側の文字列を返す。 | |
| 297 | + xの値が負のとき、文字列の右側x文字を返す。 | |
| 298 | + yが指定された場合、y文字分の文字列を返す。 | |
| 299 | +ARGS$(x) | |
| 300 | + サブルーチン中で、GOSUBに渡されたx番目の引数を文字列として取り出す。 | |
| 301 | +CHR$(x) | |
| 302 | + xをアスキーコードとする文字を返す。 | |
| 303 | +DEC$(x) | |
| 304 | + xの値を、10進数の文字列として返す。 | |
| 305 | +FLOAT$(x#) | |
| 306 | + 実数値x#を、10進数の文字列として返す。 | |
| 307 | +GOSUB$(xxx [, y [, z [, ... ]]]) | |
| 308 | + GOSUB命令と同じだが、戻り値(RETURNを参照)を文字列として得ることが出来る。 | |
| 309 | + xxxは、ラベルもしくは行番号。。yyy, zzz 等は、サブルーチンに引き継がれる引数 | |
| 310 | + (ARGS()関数を参照)。 | |
| 311 | +HEX$(x [,y]) | |
| 312 | + xの値を、16進数の文字列として返す。yが指定された場合、yバイト長の | |
| 313 | + 文字列になる。 | |
| 314 | +INPUT$() | |
| 315 | + 文字列入力状態になり、入力が終了すると(Enterが押されると)文字列を返す。 | |
| 316 | +SPRINTF$(x$,y#) | |
| 317 | + x$で示される書式に従って、実数y#の内容を文字列として返す。 | |
| 318 | +SYSTEM$(x) | |
| 319 | + 様々なシステム値を、文字列で返す。「<システム変数>」の項を参照。 | |
| 320 | +READ$() | |
| 321 | + DATA文の後から、一つずつ文字列データーを読み出す。 | |
| 322 | + | |
| 323 | +<整数演算子> | |
| 324 | +-x | |
| 325 | + 符号を反転 | |
| 326 | +x + y | |
| 327 | + 整数加算 | |
| 328 | +x - y | |
| 329 | + 整数減算 | |
| 330 | +x * y | |
| 331 | + 整数乗算 | |
| 332 | +x / y | |
| 333 | + 整数除算 | |
| 334 | +x % y | |
| 335 | + 整数剰余 | |
| 336 | +x >> y | |
| 337 | + xの値をyビット右シフト | |
| 338 | +x << y | |
| 339 | + xの値をyビット左シフト | |
| 340 | +x = y | |
| 341 | + 2つの整数値が等しい場合に1、そうでないときに0 | |
| 342 | +x != y | |
| 343 | + 2つの整数値が等しい場合に0、そうでないときに1 | |
| 344 | +x < y | |
| 345 | + xがyより小さい場合に1、そうでないときに0 | |
| 346 | +x <= y | |
| 347 | + xがyより小さいか等しい場合に1、そうでないときに0 | |
| 348 | +x > y | |
| 349 | + xがyより多きい場合に1、そうでないときに0 | |
| 350 | +x >= y | |
| 351 | + xがyより多きいか等しい場合に1、そうでないときに0 | |
| 352 | +x AND y | |
| 353 | + xとyの値のビットごとの AND(論理積でないことに注意) | |
| 354 | +x OR y | |
| 355 | + xとyの値のビットごとの OR | |
| 356 | +x XOR y | |
| 357 | + xとyの値のビットごとの XOR | |
| 358 | + | |
| 359 | +なお、整数演算子の優先順位は、優先度が高いものから以下の順です。 | |
| 360 | + | |
| 361 | ++ - (単項演算子) | |
| 362 | +* / % | |
| 363 | ++ - (加算・減算) | |
| 364 | +<< >> | |
| 365 | +< <= > >= | |
| 366 | += != | |
| 367 | +XOR | |
| 368 | +AND | |
| 369 | +OR | |
| 370 | + | |
| 371 | +<文字列演算子> | |
| 372 | +x$ + y$ | |
| 373 | + 文字列の連結 | |
| 374 | + | |
| 375 | +<浮動小数点型演算子> | |
| 376 | +-x# | |
| 377 | + 符号を反転 | |
| 378 | +x# + y# | |
| 379 | + 実数加算 | |
| 380 | +x# - y# | |
| 381 | + 実数減算 | |
| 382 | +x# * y# | |
| 383 | + 実数乗算 | |
| 384 | +x# / y# | |
| 385 | + 実数除算 | |
| 386 | +x# = y# | |
| 387 | + 2つの実数値が等しい場合に1、そうでないときに0 | |
| 388 | +x# != y# | |
| 389 | + 2つの実数値が等しい場合に0、そうでないときに1 | |
| 390 | +x# < y# | |
| 391 | + xがyより小さい場合に1、そうでないときに0 | |
| 392 | +x# <= y# | |
| 393 | + xがyより小さいか等しい場合に1、そうでないときに0 | |
| 394 | +x# > y# | |
| 395 | + xがyより多きい場合に1、そうでないときに0 | |
| 396 | +x# >= y# | |
| 397 | + xがyより多きいか等しい場合に1、そうでないときに0 | |
| 398 | +x# AND y# | |
| 399 | + xとyの値の論理積(ビットごとの AND でないことに注意) | |
| 400 | +x# OR y# | |
| 401 | + xとyの値の論理和(ビットごとの OR でないことに注意) | |
| 402 | + | |
| 403 | +なお、実数演算子の優先順位は、優先度が高いものから以下の順です。 | |
| 404 | + | |
| 405 | ++ - (単項演算子) | |
| 406 | +* / | |
| 407 | ++ - (加算・減算) | |
| 408 | +< <= > >= | |
| 409 | += != | |
| 410 | +AND | |
| 411 | +OR | |
| 412 | + | |
| 413 | +<MUSIC> | |
| 414 | +MUSIC命令では、BGM用のデーターを文字列で指定します。文字列の書式は、ABC | |
| 415 | +notationに準拠しています。ただし、すべての記法が使えるわけではありません。 | |
| 416 | +なお、キーや速度などのデフォルト設定値は以下の通りです。 | |
| 417 | + | |
| 418 | +Q: 1/4=90 | |
| 419 | +L: 1/8 | |
| 420 | +K: C | |
| 421 | + | |
| 422 | +BGM演奏時に一度に設定できる音の数は、31迄です。これを超えて音楽を再生したい | |
| 423 | +場合は、MUSIC()関数の戻り値を調べ、その値が十分小さくなってから、次のMUSIC命 | |
| 424 | +令を実行するようにします。 | |
| 425 | + | |
| 426 | +添付のmusic.basに、使い方に関するサンプルがありますので、参考にして下さい。 | |
| 427 | + | |
| 428 | +<SOUND> | |
| 429 | +SOUND命令では、DATA列のデーターを、行番号もしくはラベルで指定します。SOUND命 | |
| 430 | +令による効果音再生中は、BGMは再生されません。また、前の効果音が終わる前に次 | |
| 431 | +のSOUND命令を実行すると、前の効果音の再生は停止し、新しい効果音がすぐに再生 | |
| 432 | +されます。 | |
| 433 | + | |
| 434 | +DATA列では、32ビット整数値として、交換音を表現します。この整数値の下位16 | |
| 435 | +ビットは周波数の指定です。2048が440Hz(ラの音)に対応します。値が大きくなるほ | |
| 436 | +ど、より低い音が出ます。上位16ビットは、音の長さです。1が、1/60秒に相当し | |
| 437 | +ます。最後に、65535以下の値で、効果音の繰り返し回数を指定します。これらのデー | |
| 438 | +ターの数は、32を超えないようにして下さい。 | |
| 439 | + | |
| 440 | +添付のsound.basに、使い方に関するサンプルがありますので、参考にして下さい。 | |
| 441 | + | |
| 442 | +<PCG> | |
| 443 | +PCG(Programmable Character Generator)を用いると、ASCIIコードごとにフォント | |
| 444 | +を指定して、疑似グラフィックスとして表示させることが出来ます。使用する場合 | |
| 445 | +は、まず | |
| 446 | + | |
| 447 | +USEPCG | |
| 448 | + | |
| 449 | +とします。フォントの変更は、PCGステートメントを用いて、 | |
| 450 | + | |
| 451 | +PCG 0x80,0x80402010,0x08040201 | |
| 452 | + | |
| 453 | +の様に設定します。この例では、ASCIIコード0x80の文字のフォントを設定してい | |
| 454 | +て、バックスラッシュの様な記号(左上から右下に向かう斜め線)が表示されるよう | |
| 455 | +になります。PCGの利用を停止し、オリジナルのフォントに戻す場合は、 | |
| 456 | + | |
| 457 | +USEPCG 0 | |
| 458 | + | |
| 459 | +とします。再度PCGを使用したい場合は、 | |
| 460 | + | |
| 461 | +USEPCG | |
| 462 | + | |
| 463 | +として下さい。先に設定したフォントデーターが、復活します。なお、先に設定し | |
| 464 | +たフォントデーターを破棄してPCGの使用を始めたい場合は、 | |
| 465 | + | |
| 466 | +USEPCG 2 | |
| 467 | + | |
| 468 | +として下さい。 | |
| 469 | + | |
| 470 | +<システム変数> | |
| 471 | +SYSTEM関数及びSYSTEMステートメントを用いて、各種システム情報をやりとりするこ | |
| 472 | +とが出来ます。 | |
| 473 | + | |
| 474 | +SYSTEM$(0) | |
| 475 | + MachiKania バージョン文字列、"Zoea"を返す。 | |
| 476 | +SYSTEM$(1) | |
| 477 | + MachiKania バージョン文字列、"1.0"等を返す。 | |
| 478 | +SYSTEM$(2) | |
| 479 | + BASIC バージョン文字列、"KM-1200"等を返す。 | |
| 480 | +SYSTEM$(3) | |
| 481 | + 現在実行中のHEXファイル名、"ZOEA.HEX"等を返す。 | |
| 482 | +SYSTEM(20) | |
| 483 | + キャラクターディスプレイ横幅を返す。 | |
| 484 | +SYSTEM(21) | |
| 485 | + キャラクターディスプレイ縦幅を返す。 | |
| 486 | +SYSTEM(22) | |
| 487 | + グラフィックディスプレイ横幅を返す。 | |
| 488 | +SYSTEM(23) | |
| 489 | + グラフィックディスプレイ横幅を返す。 | |
| 490 | +SYSTEM(24) | |
| 491 | + キャラクターディスプレイ用の指定色を返す。 | |
| 492 | +SYSTEM(25) | |
| 493 | + グラフィックディスプレイ用の指定色を返す。 | |
| 494 | +SYSTEM(26) | |
| 495 | + キャラクターディスプレイの、現在のX位置を返す。 | |
| 496 | +SYSTEM(27) | |
| 497 | + キャラクターディスプレイの、現在のY位置を返す。 | |
| 498 | +SYSTEM(28) | |
| 499 | + グラフィックディスプレイの、現在のX位置を返す。 | |
| 500 | +SYSTEM(29) | |
| 501 | + グラフィックディスプレイの、現在のY位置を返す。 | |
| 502 | +SYSTEM(40) | |
| 503 | + PS/2キーボードを使用中かどうかを返す。 | |
| 504 | +SYSTEM(41) | |
| 505 | + PS/2キーボード情報、vkeyを返す。 | |
| 506 | +SYSTEM(42) | |
| 507 | + PS/2キーボード情報、lockkeyを返す。 | |
| 508 | +SYSTEM(43) | |
| 509 | + PS/2キーボード情報、keytypeを返す。 | |
| 510 | +SYSTEM(100) | |
| 511 | + 変数格納領域(g_var_mem)へのポインターを返す。 | |
| 512 | +SYSTEM(101) | |
| 513 | + 乱数シードへのポインターを返す。 | |
| 514 | +SYSTEM(102) | |
| 515 | + キャラクターディスプレイ領域(TVRAM)へのポインターを返す。 | |
| 516 | +SYSTEM(103) | |
| 517 | + フォント領域へのポインターを返す。 | |
| 518 | +SYSTEM(104) | |
| 519 | + PCGフォント領域へのポインターを返す。 | |
| 520 | +SYSTEM(105) | |
| 521 | + グラフィックディスプレイ領域へのポインターを返す。 | |
| 522 | +SYSTEM 200,x | |
| 523 | + ディスプレイの表示を停止(xが0のとき)、もしくは開始(xが0以外の時)する。 | |
| 524 | + | |
| 525 | +<ヒント> | |
| 526 | +FOR-NEXTループ、WHILE-WENDループ、DO-LOOPループの途中で、GOTO文でループの | |
| 527 | +外に飛んだり、RETURN文を実行したりすると、予期せぬ結果(機器のリセット等)を | |
| 528 | +引き起こします。ただし、GOSUB文でサブルーチンを呼んだり、別のループをネスト | |
| 529 | +して使う事は可能です。 | |
| 530 | + | |
| 531 | +ON GOTO分やON GOSUB文はサポートしていません。ただし、例えば次のように記述す | |
| 532 | +ることで、同様の動作をさせることは可能です。 | |
| 533 | + GOSUB 10000+A | |
| 534 | + .... | |
| 535 | + 10000 PRINT "A=0" : RETURN | |
| 536 | + 10001 PRINT "A=1" : RETURN | |
| 537 | + 10002 PRINT "A=2" : RETURN | |
| 538 | + | |
| 539 | +一行中で連続して文字列を扱うと、"String too complexed"というエラーがでて、 | |
| 540 | +停止することがあります。この場合は、文字列を扱う命令を独立した行するか、文 | |
| 541 | +字列関連の演算を幾つかのステップに分けて、それぞれ1行ずつの記述にして試し | |
| 542 | +てみて下さい。 | |
| 543 | + | |
| 544 | +<バージョン履歴> | |
| 545 | +・KM-1200 2016年8月公開。 | |
| 546 | + 1.グラフィックディスプレイ機能および、関連のステートメント群を追加。 | |
| 547 | + 2.浮動小数点演算機能、及び、算術演算関数群を追加。 | |
| 548 | + 3.VAR, BREAK, SYSTEMステートメントを追加。 | |
| 549 | + 4.DO-LOOP, WHILE-WENDループ構造文を追加。 | |
| 550 | + 5.IF THEN - ELSEIF - ELSE - ENDIFによる、複数行での条件分岐表現を追加。 | |
| 551 | + 6.GOSUBステートメント及びGOSUB()関数に第二以降の引数を指定出来る様にし、 | |
| 552 | + サブルーチン中でARGS()関数により取り出せるようにした。 | |
| 553 | + 7.8ビット整数型を扱うCDATAステートメントとCREAD()関数を追加。 | |
| 554 | + 8.DATAステートメントで文字列を扱える様にし、READ$()で読めるようにした。 | |
| 555 | + 9.多次元配列をサポート。 | |
| 556 | + 10.例外発生時に、情報を表示するようにした。 | |
| 557 | + 11.FOR-NEXTループに於いて、TO値に一致する時だけではなく、値を超えた場合 | |
| 558 | + でもループを抜けるようにした。 | |
| 559 | + 12.MUSICステートメント用のスクリプトにエラーがある際、エラー発生行が正し | |
| 560 | + く表示されない不具合を修正。 | |
| 561 | + 13.ビットシフト演算子を、追加。 | |
| 562 | + | |
| 563 | +・KM-1120 2016年2月公開。 | |
| 564 | + 1.PCG機能を追加。 | |
| 565 | + 2.SCROLL命令を追加。 | |
| 566 | + 3.WAIT命令を追加。 | |
| 567 | + 4.「Ctrl+Break」キーによる実行停止に対応。 | |
| 568 | + 5.FOR無しでNEXTを実行した場合、GOSUB無しでRETURNを実行した場合にエラー | |
| 569 | + を表示して停止するようにした。 | |
| 570 | + | |
| 571 | +・Ver 1.1.0 (KM-1110) 2015年12月公開。 | |
| 572 | + 1.2015年11月21日に変更されたPIC32TVGSの仕様に対応。 | |
| 573 | + 2.PS/2キーボードに対応。 | |
| 574 | + 3.INKEY() INPUT$() VAL() DEC$() の4つの関数を追加。 | |
| 575 | + 4.TVRAM() ASC() PEEK()が、0x80-0xFFの値に関して負の数を返していた不具合 | |
| 576 | + を修正。 | |
| 577 | + 5.DIMステートメントにより配列を定義した際、すべての要素がゼロになるよう | |
| 578 | + にした。 | |
| 579 | + 6.単項演算子、「-」「+」を追加。 | |
| 580 | + 7.LABEL定義されていない飛び先にGOTOするとリセットされる不具合を修正。 | |
| 581 | + 8.同一のLABELを複数回使用している場合に、コンパイルエラーが出るように修 | |
| 582 | + 正。 | |
| 583 | + 9.引数を持たないPRINT文に対応。 | |
| 584 | + | |
| 585 | +・Ver 1.0.5 (KM-1100) 最初の正規公開バージョン。 |
| @@ -0,0 +1,139 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by K.Tanaka & Katsumi | |
| 4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
| 5 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include <xc.h> | |
| 9 | +#include "api.h" | |
| 10 | +#include "compiler.h" | |
| 11 | +#include "editor.h" | |
| 12 | +#include "main.h" | |
| 13 | + | |
| 14 | +char* printdec(int num){ | |
| 15 | + char str[11]; | |
| 16 | + int i; | |
| 17 | + if (num<0) { | |
| 18 | + printchar('-'); | |
| 19 | + num=0-num; | |
| 20 | + } | |
| 21 | + for(i=10;0<i;i--){ | |
| 22 | + if (num==0 && i<10) break; | |
| 23 | + str[i]='0'+rem10_32(num); | |
| 24 | + num=div10_32(num); | |
| 25 | + } | |
| 26 | + for(i++;i<11;i++) { | |
| 27 | + printchar(str[i]); | |
| 28 | + } | |
| 29 | +} | |
| 30 | + | |
| 31 | +int runbasic(char *appname,int test){ | |
| 32 | +// BASICソースのコンパイルと実行 | |
| 33 | +// appname 実行するBASICソースファイル | |
| 34 | +// test 0:コンパイルと実行、0以外:コンパイルのみで終了 | |
| 35 | +// | |
| 36 | +// 戻り値 | |
| 37 | +// 0:正常終了 | |
| 38 | +// -1:ファイルエラー | |
| 39 | +// -2:リンクエラー | |
| 40 | +// 1以上:コンパイルエラーの発生行(行番号ではなくファイル上の何行目か) | |
| 41 | + int i; | |
| 42 | + char* buff; | |
| 43 | + char* err; | |
| 44 | + | |
| 45 | + // Set grobal pointer | |
| 46 | + g_gp=get_gp(); | |
| 47 | + // Set source positions | |
| 48 | + buff=(char*)&(RAM[RAMSIZE-512]); | |
| 49 | + g_source=(char*)(&buff[0]); | |
| 50 | + g_srcpos=0; | |
| 51 | + // Set object positions | |
| 52 | + g_object=(int*)(&RAM[0]); | |
| 53 | + g_objpos=0; | |
| 54 | + g_objmax=g_object+(RAMSIZE-512)/4; // Buffer area excluded. | |
| 55 | + // Initialize SD card file system | |
| 56 | + err=init_file(buff,appname); | |
| 57 | + if (err) { | |
| 58 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 59 | + printstr("Can't Open "); | |
| 60 | + printstr(appname); | |
| 61 | + printchar('\n'); | |
| 62 | + return -1; | |
| 63 | + } | |
| 64 | + | |
| 65 | + // Initialize parameters | |
| 66 | + g_pcg_font=0; | |
| 67 | + g_use_graphic=0; | |
| 68 | + g_graphic_area=0; | |
| 69 | + clearscreen(); | |
| 70 | + setcursor(0,0,7); | |
| 71 | + | |
| 72 | + printstr("BASIC "BASVER"\n"); | |
| 73 | + wait60thsec(15); | |
| 74 | + // Initialize music | |
| 75 | + init_music(); | |
| 76 | + | |
| 77 | + printstr("Compiling..."); | |
| 78 | + | |
| 79 | + // Compile the file | |
| 80 | + err=compile_file(); | |
| 81 | + close_file(); | |
| 82 | + if (err) { | |
| 83 | + // Compile error | |
| 84 | + printstr(err); | |
| 85 | + printstr("\nAround: '"); | |
| 86 | + for(i=0;i<5;i++){ | |
| 87 | + printchar(g_source[g_srcpos-2+i]); | |
| 88 | + } | |
| 89 | + printstr("' in line "); | |
| 90 | + printdec(g_line); | |
| 91 | + printstr("\n"); | |
| 92 | + for(i=g_srcpos;0x20<=g_source[i];i++); | |
| 93 | + g_source[i]=0x00; | |
| 94 | + for(i=g_srcpos;0x20<=g_source[i];i--); | |
| 95 | + printstr(g_source+i); | |
| 96 | + return g_fileline; | |
| 97 | + } | |
| 98 | + | |
| 99 | + // Link | |
| 100 | + err=link(); | |
| 101 | + if (err) { | |
| 102 | + // Link error | |
| 103 | + printstr(err); | |
| 104 | + printstr(resolve_label(g_label)); | |
| 105 | + return -2; | |
| 106 | + } | |
| 107 | + | |
| 108 | + // All done | |
| 109 | + printstr("done\n"); | |
| 110 | + if(test) return 0; //コンパイルのみの場合 | |
| 111 | + wait60thsec(15); | |
| 112 | + | |
| 113 | + // Initialize the other parameters | |
| 114 | + // Random seed | |
| 115 | + g_rnd_seed=2463534242; | |
| 116 | + // Clear variables | |
| 117 | + for(i=0;i<ALLOC_BLOCK_NUM;i++){ | |
| 118 | + g_var_mem[i]=0; | |
| 119 | + g_var_size[i]=0; | |
| 120 | + } | |
| 121 | + // Clear key input buffer | |
| 122 | + for(i=0;i<256;i++){ | |
| 123 | + ps2keystatus[i]=0; | |
| 124 | + } | |
| 125 | + // Reset data/read. | |
| 126 | + reset_dataread(); | |
| 127 | + | |
| 128 | + // Assign memory | |
| 129 | + set_free_area((void*)(g_object+g_objpos),(void*)(&RAM[RAMSIZE])); | |
| 130 | + // Execute program | |
| 131 | + // Start program from the beginning of RAM. | |
| 132 | + // Work area (used for A-Z values) is next to the object code area. | |
| 133 | + start_program((void*)(&(RAM[0])),(void*)(&g_var_mem[0])); | |
| 134 | + printstr("\nOK\n"); | |
| 135 | + set_graphmode(0); | |
| 136 | + g_use_graphic=0; | |
| 137 | + | |
| 138 | + return 0; | |
| 139 | +} |
| @@ -0,0 +1,143 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include "compiler.h" | |
| 9 | + | |
| 10 | +void start_program(void* addr, void* memory){ | |
| 11 | + static unsigned int stored_sp; | |
| 12 | + // Store s0-s7, fp, and ra in stacks | |
| 13 | + asm volatile("#":::"s0"); | |
| 14 | + asm volatile("#":::"s1"); | |
| 15 | + asm volatile("#":::"s2"); | |
| 16 | + asm volatile("#":::"s3"); | |
| 17 | + asm volatile("#":::"s4"); | |
| 18 | + asm volatile("#":::"s5"); | |
| 19 | + asm volatile("#":::"s6"); | |
| 20 | + asm volatile("#":::"s7"); | |
| 21 | + asm volatile("#":::"fp"); | |
| 22 | + asm volatile("#":::"ra"); | |
| 23 | + // Store sp in stored_sp | |
| 24 | + asm volatile("la $v0,%0"::"i"(&stored_sp)); | |
| 25 | + asm volatile("sw $sp,0($v0)"); | |
| 26 | + // Shift sp for safety | |
| 27 | + asm volatile("addiu $sp,$sp,-8"); | |
| 28 | + // Register vector for unexpected NEXT/RETURN | |
| 29 | + asm volatile("la $v0,%0"::"i"(&err_unexp_next)); | |
| 30 | + asm volatile("sw $v0,4($sp)"); | |
| 31 | + // Store end address in g_end_addr | |
| 32 | + asm volatile("la $v0,%0"::"i"(&g_end_addr)); | |
| 33 | + asm volatile("la $v1,label"); | |
| 34 | + asm volatile("sw $v1,0($v0)"); | |
| 35 | + // Set s7 for easy calling call_library() | |
| 36 | + asm volatile("la $s7,%0"::"i"(&call_library)); | |
| 37 | + // Set fp and execute program | |
| 38 | + asm volatile("addu $fp,$zero,$a1"); | |
| 39 | + asm volatile("jr $a0"); | |
| 40 | + // Restore sp from stored_sp | |
| 41 | + asm volatile("label:"); | |
| 42 | + asm volatile("la $v0,%0"::"i"(&stored_sp)); | |
| 43 | + asm volatile("lw $sp,0($v0)"); | |
| 44 | + // Restore registers from stack and return | |
| 45 | + return; | |
| 46 | +} | |
| 47 | + | |
| 48 | +int get_gp(void){ | |
| 49 | + asm volatile("addu $v0,$gp,$zero"); | |
| 50 | +} | |
| 51 | + | |
| 52 | +int get_fp(void){ | |
| 53 | + asm volatile("addu $v0,$fp,$zero"); | |
| 54 | +} | |
| 55 | + | |
| 56 | + | |
| 57 | +void shift_obj(int* src, int* dst, int len){ | |
| 58 | + int i; | |
| 59 | + if (dst<src) { | |
| 60 | + for(i=0;i<len;i++){ | |
| 61 | + dst[i]=src[i]; | |
| 62 | + } | |
| 63 | + } else if (src<dst) { | |
| 64 | + for(i=len-1;0<=i;i--){ | |
| 65 | + dst[i]=src[i]; | |
| 66 | + } | |
| 67 | + } | |
| 68 | +} | |
| 69 | + | |
| 70 | +int strncmp(char* str1, char* str2, int len){ | |
| 71 | + int i; | |
| 72 | + for (i=0;i<len;i++) { | |
| 73 | + if (str1[i]>str2[i]) return 1; | |
| 74 | + if (str1[i]<str2[i]) return -1; | |
| 75 | + } | |
| 76 | + return 0; | |
| 77 | +} | |
| 78 | + | |
| 79 | +int nextCodeIs(char* str){ | |
| 80 | + int len; | |
| 81 | + for(len=0;str[len];len++); | |
| 82 | + if (!strncmp(g_source+g_srcpos,str,len)) { | |
| 83 | + if ('A'<=str[len-1] && str[len-1]<='Z') { | |
| 84 | + // When the last character of str is alphabet, | |
| 85 | + // the next character in source must be space, enter, or ':'. | |
| 86 | + if (0x20<g_source[g_srcpos+len] && g_source[g_srcpos+len]!=':') return 0; | |
| 87 | + } | |
| 88 | + // String matches in the current position in source. | |
| 89 | + g_srcpos+=len; | |
| 90 | + return len; | |
| 91 | + } else { | |
| 92 | + // String didn't match. | |
| 93 | + return 0; | |
| 94 | + } | |
| 95 | +} | |
| 96 | + | |
| 97 | +char* compile_line(void){ | |
| 98 | + char b1; | |
| 99 | + char* err; | |
| 100 | + g_line++; | |
| 101 | + g_fileline++; | |
| 102 | + // Check if line number exists | |
| 103 | + next_position(); | |
| 104 | + b1=g_source[g_srcpos]; | |
| 105 | + if (b1<0x20) { | |
| 106 | + // The end of line. | |
| 107 | + // Don't add $s6-setting command. | |
| 108 | + if (g_source[g_srcpos]==0x0D && g_source[g_srcpos+1]==0x0A) g_srcpos++; | |
| 109 | + g_srcpos++; | |
| 110 | + return 0; | |
| 111 | + } else if ('0'<=b1 && b1<='9') { | |
| 112 | + // Line number exists | |
| 113 | + err=get_label(); | |
| 114 | + if (err) return err; | |
| 115 | + g_line=g_label; | |
| 116 | + } | |
| 117 | + // Store line number in $s6 | |
| 118 | + if (!(g_line&0xFFFF0000)) { | |
| 119 | + // Line number must be less than 65536. | |
| 120 | + // If not, it is invalid number. | |
| 121 | + // Check existing line with the same number here. | |
| 122 | + if (search_label(g_line)) { | |
| 123 | + // Error: duplicate lines | |
| 124 | + printstr("Line "); | |
| 125 | + printstr(resolve_label(g_line)); | |
| 126 | + return ERR_MULTIPLE_LABEL; | |
| 127 | + } | |
| 128 | + check_obj_space(1); | |
| 129 | + g_object[g_objpos++]=0x34160000|g_line; //ori s6,zero,xxxx; | |
| 130 | + } | |
| 131 | + while(g_source[g_srcpos]!=0x0D && g_source[g_srcpos]!=0x0A){ | |
| 132 | + err=statement(); | |
| 133 | + if (err) return err; | |
| 134 | + next_position(); | |
| 135 | + if (g_source[g_srcpos]==':') { | |
| 136 | + g_srcpos++; | |
| 137 | + next_position(); | |
| 138 | + } | |
| 139 | + } | |
| 140 | + if (g_source[g_srcpos]==0x0D && g_source[g_srcpos+1]==0x0A) g_srcpos++; | |
| 141 | + g_srcpos++; | |
| 142 | + return 0; | |
| 143 | +} | |
| \ No newline at end of file |
| @@ -0,0 +1,99 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by K.Tanaka & Katsumi | |
| 4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
| 5 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include <xc.h> | |
| 9 | +#include "api.h" | |
| 10 | +#include "compiler.h" | |
| 11 | + | |
| 12 | +static FSFILE* g_fhandle; | |
| 13 | +static char* g_fbuff; | |
| 14 | +static int g_size; | |
| 15 | + | |
| 16 | +char* init_file(char* buff,char* appname){ | |
| 17 | + // Open file | |
| 18 | + g_fhandle=FSfopen(appname,"r"); | |
| 19 | + if (!g_fhandle) { | |
| 20 | + return ERR_UNKNOWN; | |
| 21 | + } | |
| 22 | + g_fbuff=buff; | |
| 23 | + g_line=0; | |
| 24 | + g_fileline=0; | |
| 25 | + return 0; | |
| 26 | +} | |
| 27 | + | |
| 28 | +void close_file(){ | |
| 29 | + FSfclose(g_fhandle); | |
| 30 | +} | |
| 31 | + | |
| 32 | +void read_file(int blocklen){ | |
| 33 | + int i; | |
| 34 | + static char in_string, escape; | |
| 35 | + // blocklen is either 512 or 256. | |
| 36 | + if (blocklen==512) { | |
| 37 | + // This is first read. Initialize parameter(s). | |
| 38 | + in_string=0; | |
| 39 | + escape=0; | |
| 40 | + } else if (g_size<512) { | |
| 41 | + // Already reached the end of file. | |
| 42 | + return; | |
| 43 | + } else { | |
| 44 | + // Shift buffer and source position 256 bytes. | |
| 45 | + for(i=0;i<256;i++) g_fbuff[i]=g_fbuff[i+256]; | |
| 46 | + g_srcpos-=256; | |
| 47 | + } | |
| 48 | + // Read 512 or 256 bytes from SD card. | |
| 49 | + g_size=512-blocklen+FSfread((void*)&g_fbuff[512-blocklen],1,blocklen,g_fhandle); | |
| 50 | + // Some modifications of text for easy compiling. | |
| 51 | + for(i=512-blocklen;i<512;i++){ | |
| 52 | + if (in_string) { | |
| 53 | + if (g_fbuff[i]=='\\' && !escape) { | |
| 54 | + escape=1; | |
| 55 | + } else { | |
| 56 | + escape=0; | |
| 57 | + if (g_fbuff[i]=='"') in_string=0; | |
| 58 | + } | |
| 59 | + } else { | |
| 60 | + // If not in string, all upper cases. | |
| 61 | + if (g_fbuff[i]=='"') in_string=1; | |
| 62 | + else if ('a'<=g_fbuff[i] && g_fbuff[i]<='z') g_fbuff[i]+='A'-'a'; | |
| 63 | + // If not in string, tabs will be spaces. | |
| 64 | + else if ('\t'==g_fbuff[i]) g_fbuff[i]=' '; | |
| 65 | + } | |
| 66 | + if (g_fbuff[i]==0x0a || g_fbuff[i]==0x0d) in_string=escape=0; | |
| 67 | + } | |
| 68 | + return; | |
| 69 | +} | |
| 70 | + | |
| 71 | +char* compile_file(){ | |
| 72 | + int i; | |
| 73 | + char* err; | |
| 74 | + // Read first 512 bytes | |
| 75 | + read_file(512); | |
| 76 | + // Compile line by line | |
| 77 | + while (g_size==512) { | |
| 78 | + err=compile_line(); | |
| 79 | + if (err) return err; | |
| 80 | + // Maintain at least 256 characters in cache. | |
| 81 | + if (256<=g_srcpos) read_file(256); | |
| 82 | + } | |
| 83 | + // Return code at the end | |
| 84 | + g_source[g_size]=0x0d; | |
| 85 | + // Compile last few lines. | |
| 86 | + while(g_srcpos<g_size-1){ | |
| 87 | + err=compile_line(); | |
| 88 | + if (err) return err; | |
| 89 | + } | |
| 90 | + // Add "DATA 0" and "END" statements. | |
| 91 | + g_source="DATA 0:END\n"; | |
| 92 | + g_srcpos=0; | |
| 93 | + err=compile_line(); | |
| 94 | + if (err) return err; | |
| 95 | + g_srcpos=-1; | |
| 96 | + // No error occured | |
| 97 | + return 0; | |
| 98 | +} | |
| 99 | + |
| @@ -0,0 +1,303 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +/* Definitions */ | |
| 9 | +// Number of variables (including temporary ones) | |
| 10 | +#define ALLOC_VAR_NUM 36 | |
| 11 | +// Number of blocks that can be assigned for memory allocation (including ALLOC_VAR_NUM) | |
| 12 | +#define ALLOC_BLOCK_NUM 48 | |
| 13 | +// Block # dedicated for PCG | |
| 14 | +#define ALLOC_PCG_BLOCK 36 | |
| 15 | +// Block # dedicated for GRAPHIC | |
| 16 | +#define ALLOC_GRAPHIC_BLOCK 37 | |
| 17 | +// Start # of permanent blocks | |
| 18 | +#define ALLOC_PERM_BLOCK 38 | |
| 19 | + | |
| 20 | +// Persistent RAM bytes used for object, heap and exception data | |
| 21 | +#define PERSISTENT_RAM_SIZE (1024*56) | |
| 22 | +// Exception data area bytes | |
| 23 | +#define EXCEPTION_DATA_SIZE (64) | |
| 24 | +// RAM size used for object and heap | |
| 25 | +#define RAMSIZE (PERSISTENT_RAM_SIZE-EXCEPTION_DATA_SIZE) | |
| 26 | + | |
| 27 | +/* Enums */ | |
| 28 | +enum variable{ | |
| 29 | + VAR_INTEGER, | |
| 30 | + VAR_FLOAT, | |
| 31 | + VAR_STRING | |
| 32 | +}; | |
| 33 | + | |
| 34 | +enum operator{ | |
| 35 | + OP_VOID=0, | |
| 36 | + OP_OR =1, | |
| 37 | + OP_AND =2, | |
| 38 | + OP_XOR =3, | |
| 39 | + OP_EQ =4, | |
| 40 | + OP_NEQ =5, | |
| 41 | + OP_LT =6, | |
| 42 | + OP_LTE =7, | |
| 43 | + OP_MT =8, | |
| 44 | + OP_MTE =9, | |
| 45 | + OP_SHL =10, | |
| 46 | + OP_SHR =11, | |
| 47 | + OP_ADD =12, | |
| 48 | + OP_SUB =13, | |
| 49 | + OP_MUL =14, | |
| 50 | + OP_DIV =15, | |
| 51 | + OP_REM =16 | |
| 52 | +}; | |
| 53 | +enum libs{ | |
| 54 | + LIB_SOUND, | |
| 55 | + LIB_MUSICFUNC, | |
| 56 | + LIB_MUSIC, | |
| 57 | + LIB_SETDRAWCOUNT, | |
| 58 | + LIB_DRAWCOUNT, | |
| 59 | + LIB_PALETTE, | |
| 60 | + LIB_GPALETTE, | |
| 61 | + LIB_BGCOLOR, | |
| 62 | + LIB_CURSOR, | |
| 63 | + LIB_CLS, | |
| 64 | + LIB_GCLS, | |
| 65 | + LIB_COLOR, | |
| 66 | + LIB_GCOLOR, | |
| 67 | + LIB_KEYS, | |
| 68 | + LIB_RESTORE, | |
| 69 | + LIB_RESTORE2, | |
| 70 | + LIB_READ, | |
| 71 | + LIB_MIDSTR, | |
| 72 | + LIB_CLEAR, | |
| 73 | + LIB_DIV0, | |
| 74 | + LIB_LETSTR, | |
| 75 | + LIB_STRNCMP, | |
| 76 | + LIB_RND, | |
| 77 | + LIB_DEC, | |
| 78 | + LIB_HEX, | |
| 79 | + LIB_CHR, | |
| 80 | + LIB_CONNECT_STRING, | |
| 81 | + LIB_STRING, | |
| 82 | + LIB_PRINTSTR, | |
| 83 | + LIB_LABEL, | |
| 84 | + LIB_DIM, | |
| 85 | + LIB_VAL, | |
| 86 | + LIB_INPUT, | |
| 87 | + LIB_INKEY, | |
| 88 | + LIB_USEPCG, | |
| 89 | + LIB_PCG, | |
| 90 | + LIB_SCROLL, | |
| 91 | + LIB_WAIT, | |
| 92 | + LIB_VAR_PUSH, | |
| 93 | + LIB_VAR_POP, | |
| 94 | + LIB_SYSTEM, | |
| 95 | + LIB_SPRINTF, | |
| 96 | + LIB_FLOAT, | |
| 97 | + LIB_FLOATFUNCS, | |
| 98 | + LIB_CREAD, | |
| 99 | + LIB_USEGRAPHIC, | |
| 100 | + LIB_GRAPHIC, | |
| 101 | + LIB_DEBUG | |
| 102 | +}; | |
| 103 | +enum functions{ | |
| 104 | + FUNC_FLOAT, | |
| 105 | + FUNC_INT, | |
| 106 | + FUNC_VALSHARP, | |
| 107 | + FUNC_SIN, | |
| 108 | + FUNC_COS, | |
| 109 | + FUNC_TAN, | |
| 110 | + FUNC_ASIN, | |
| 111 | + FUNC_ACOS, | |
| 112 | + FUNC_ATAN, | |
| 113 | + FUNC_SINH, | |
| 114 | + FUNC_COSH, | |
| 115 | + FUNC_TANH, | |
| 116 | + FUNC_EXP, | |
| 117 | + FUNC_LOG, | |
| 118 | + FUNC_LOG10, | |
| 119 | + FUNC_POW, | |
| 120 | + FUNC_SQRT, | |
| 121 | + FUNC_CEIL, | |
| 122 | + FUNC_FLOOR, | |
| 123 | + FUNC_FABS, | |
| 124 | + FUNC_MODF, | |
| 125 | + FUNC_FMOD, | |
| 126 | + FUNC_PSET, | |
| 127 | + FUNC_LINE, | |
| 128 | + FUNC_BOXFILL, | |
| 129 | + FUNC_CIRCLE, | |
| 130 | + FUNC_CIRCLEFILL, | |
| 131 | + FUNC_GPRINT, | |
| 132 | + FUNC_PUTBMP, | |
| 133 | + FUNC_PUTBMP2, | |
| 134 | + FUNC_GCOLOR, | |
| 135 | + FUNC_POINT, | |
| 136 | +}; | |
| 137 | + | |
| 138 | +/* Global vars (see globalvers.c) */ | |
| 139 | +extern int g_intconst; | |
| 140 | +extern char g_valueisconst; | |
| 141 | +extern int g_rnd_seed; | |
| 142 | +extern unsigned int g_label; | |
| 143 | +extern int g_sdepth; | |
| 144 | +extern int g_maxsdepth; | |
| 145 | +extern enum variable g_lastvar; | |
| 146 | +extern char* g_source; | |
| 147 | +extern int g_srcpos; | |
| 148 | +extern int g_line; | |
| 149 | +extern int g_fileline; | |
| 150 | +extern int* g_object; | |
| 151 | +extern int g_objpos; | |
| 152 | +extern int* g_objmax; | |
| 153 | +extern const char* g_err_str[]; | |
| 154 | +extern const unsigned char g_priority[]; | |
| 155 | +extern enum operator g_last_op; | |
| 156 | +extern int g_end_addr; | |
| 157 | +extern int g_gp; | |
| 158 | +extern int g_s6; | |
| 159 | +extern char RAM[RAMSIZE]; | |
| 160 | +extern unsigned int g_ex_data[EXCEPTION_DATA_SIZE/4]; | |
| 161 | +extern int g_var_mem[ALLOC_BLOCK_NUM]; | |
| 162 | +extern unsigned short g_var_pointer[ALLOC_BLOCK_NUM]; | |
| 163 | +extern unsigned short g_var_size[ALLOC_BLOCK_NUM]; | |
| 164 | +extern char g_temp_area_used; | |
| 165 | +extern int* g_heap_mem; | |
| 166 | +extern int g_max_mem; | |
| 167 | +extern char g_disable_break; | |
| 168 | +extern unsigned char* g_pcg_font; | |
| 169 | +extern char g_use_graphic; | |
| 170 | +extern unsigned short* g_graphic_area; | |
| 171 | + | |
| 172 | +/* Prototypes */ | |
| 173 | +int get_gp(void); | |
| 174 | +int get_fp(void); | |
| 175 | +void start_program(void* addr, void* memory); | |
| 176 | +void shift_obj(int* src, int* dst, int len); | |
| 177 | +char* compile_line(void); | |
| 178 | +int nextCodeIs(char* str); | |
| 179 | + | |
| 180 | +char* init_file(char* buff,char* appname); | |
| 181 | +void close_file(); | |
| 182 | +void read_file(int blocklen); | |
| 183 | +char* compile_file(); | |
| 184 | + | |
| 185 | +void err_break(void); | |
| 186 | +void err_music(char* str); | |
| 187 | +void err_data_not_found(void); | |
| 188 | +void err_str_complex(void); | |
| 189 | +void err_label_not_found(void); | |
| 190 | +void err_no_mem(void); | |
| 191 | +void err_div_zero(void); | |
| 192 | +void err_unkonwn(void); | |
| 193 | +void err_unexp_next(void); | |
| 194 | +void err_no_block(void); | |
| 195 | +char* resolve_label(int s6); | |
| 196 | + | |
| 197 | +void set_sound(unsigned long* data); | |
| 198 | +int musicRemaining(void); | |
| 199 | +void set_music(char* str); | |
| 200 | +void init_music(void); | |
| 201 | + | |
| 202 | +char* statement(void); | |
| 203 | +char* gosub_statement(); | |
| 204 | +char* graphic_statement(enum functions func); | |
| 205 | + | |
| 206 | +char* function(void); | |
| 207 | +char* str_function(void); | |
| 208 | +char* float_function(void); | |
| 209 | + | |
| 210 | +void call_library(void); | |
| 211 | +void reset_dataread(); | |
| 212 | + | |
| 213 | +void free_temp_str(char* str); | |
| 214 | +void* alloc_memory(int size, int var_num); | |
| 215 | +void* calloc_memory(int size, int var_num); | |
| 216 | +void move_to_perm_block(int var_num); | |
| 217 | +void move_from_perm_block(int var_num); | |
| 218 | + | |
| 219 | +char* link(void); | |
| 220 | +char* get_label(void); | |
| 221 | +void* search_label(unsigned int label); | |
| 222 | + | |
| 223 | +char* get_string(); | |
| 224 | +char* simple_string(void); | |
| 225 | + | |
| 226 | +char* get_operator(void); | |
| 227 | +char* get_floatOperator(void); | |
| 228 | +char* calculation(enum operator op); | |
| 229 | +char* calculation_float(enum operator op); | |
| 230 | +int lib_float(int ia0,int iv0, enum operator a1); | |
| 231 | + | |
| 232 | +char* get_dim_value(char b1); | |
| 233 | +char* get_simple_value(void); | |
| 234 | +char* get_value(); | |
| 235 | +char* get_floatOrValue(); | |
| 236 | +char* get_stringFloatOrValue(); | |
| 237 | + | |
| 238 | +void blue_screen(void); | |
| 239 | + | |
| 240 | +char* get_float(); | |
| 241 | + | |
| 242 | +/* Error messages */ | |
| 243 | +#define ERR_SYNTAX (char*)(g_err_str[0]) | |
| 244 | +#define ERR_NE_BINARY (char*)(g_err_str[1]) | |
| 245 | +#define ERR_NE_MEMORY (char*)(g_err_str[2]) | |
| 246 | +#define ERR_DIV_0 (char*)(g_err_str[3]) | |
| 247 | +#define ERR_NY_I (char*)(g_err_str[4]) | |
| 248 | +#define ERR_LABEL_NF (char*)(g_err_str[5]) | |
| 249 | +#define ERR_LABEL_LONG (char*)(g_err_str[6]) | |
| 250 | +#define ERR_STR_COMPLEX (char*)(g_err_str[7]) | |
| 251 | +#define ERR_DATA_NF (char*)(g_err_str[8]) | |
| 252 | +#define ERR_UNKNOWN (char*)(g_err_str[9]) | |
| 253 | +#define ERR_MUSIC (char*)(g_err_str[10]) | |
| 254 | +#define ERR_MULTIPLE_LABEL (char*)(g_err_str[11]) | |
| 255 | +#define ERR_BREAK (char*)(g_err_str[12]) | |
| 256 | +#define ERR_UNEXP_NEXT (char*)(g_err_str[13]) | |
| 257 | +#define ERR_NO_BLOCK (char*)(g_err_str[14]) | |
| 258 | +#define ERR_GOSUB_ASH (char*)(g_err_str[15]) | |
| 259 | +#define ERR_INVALID_BREAK (char*)(g_err_str[16]) | |
| 260 | +#define ERR_INVALID_ELSEIF (char*)(g_err_str[17]) | |
| 261 | + | |
| 262 | +/* Macros */ | |
| 263 | + | |
| 264 | +// Skip blanc(s) in source code | |
| 265 | +#define next_position() while(g_source[g_srcpos]==' ') {g_srcpos++;} | |
| 266 | + | |
| 267 | +// Check if object area is not full. | |
| 268 | +#define check_obj_space(x) if (g_objmax<g_object+g_objpos+(x)) return ERR_NE_BINARY | |
| 269 | + | |
| 270 | +// Returns priority of operator | |
| 271 | +#define priority(x) (int)g_priority[(int)(x)] | |
| 272 | + | |
| 273 | +// Insert code for calling library | |
| 274 | +//02E0F809 jalr ra,s7 | |
| 275 | +//24070000 addiu a3,zero,0000 | |
| 276 | +#define call_lib_code(x) \ | |
| 277 | + check_obj_space(2);\ | |
| 278 | + g_object[g_objpos++]=0x02E0F809;\ | |
| 279 | + g_object[g_objpos++]=0x24070000|((x)&0x0000FFFF) | |
| 280 | + | |
| 281 | +// Division macro for unsigned long | |
| 282 | +// Valid for 31 bits for all cases and 32 bits for some cases | |
| 283 | +#define div32(x,y,z) ((((unsigned long long)((unsigned long)(x)))*((unsigned long long)((unsigned long)(y))))>>(z)) | |
| 284 | + | |
| 285 | +// Divide by 10 (valid for 32 bits) | |
| 286 | +#define div10_32(x) div32(x,0xcccccccd,35) | |
| 287 | +#define rem10_32(x) ((x)-10*div10_32(x)) | |
| 288 | + | |
| 289 | +// Divide by 36 (valid for 32 bits) | |
| 290 | +#define div36_32(x) div32(x,0xe38e38e4,37) | |
| 291 | +#define rem36_32(x) (x-36*div36_32(x)) | |
| 292 | + | |
| 293 | +// Check break key or buttons when executing BASIC code. | |
| 294 | +// In PS/2 mode, detect ctrl-break. | |
| 295 | +// In button mode, detect pushing four buttons are pushed simultaneously. | |
| 296 | +#define check_break() \ | |
| 297 | + if (g_disable_break==0) {\ | |
| 298 | + if (inPS2MODE()) {\ | |
| 299 | + if (ps2keystatus[0x03]) err_break();\ | |
| 300 | + } else {\ | |
| 301 | + if ((PORTB&0x4c80)==0) err_break();\ | |
| 302 | + }\ | |
| 303 | + } |
| @@ -0,0 +1,517 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include "compiler.h" | |
| 9 | +#include "api.h" | |
| 10 | + | |
| 11 | +char* music_function(){ | |
| 12 | + call_lib_code(LIB_MUSICFUNC); | |
| 13 | + return 0; | |
| 14 | +} | |
| 15 | + | |
| 16 | +char* read_function(){ | |
| 17 | + call_lib_code(LIB_READ); | |
| 18 | + return 0; | |
| 19 | +} | |
| 20 | + | |
| 21 | +char* cread_function(){ | |
| 22 | + call_lib_code(LIB_CREAD); | |
| 23 | + return 0; | |
| 24 | +} | |
| 25 | + | |
| 26 | +char* gosub_function(){ | |
| 27 | + // Check if garbage collection has been done. | |
| 28 | + // This check is required because the used temporary area would be changed | |
| 29 | + // in sub routine. | |
| 30 | + if (g_temp_area_used) return ERR_GOSUB_ASH; | |
| 31 | + return gosub_statement(); | |
| 32 | +} | |
| 33 | +char* strncmp_function(){ | |
| 34 | + char* err; | |
| 35 | + err=get_string(); | |
| 36 | + if (err) return err; | |
| 37 | + check_obj_space(2); | |
| 38 | + g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
| 39 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
| 40 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 41 | + g_srcpos++; | |
| 42 | + err=get_string(); | |
| 43 | + if (err) return err; | |
| 44 | + check_obj_space(1); | |
| 45 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
| 46 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 47 | + g_srcpos++; | |
| 48 | + err=get_value(); | |
| 49 | + if (err) return err; | |
| 50 | + check_obj_space(3); | |
| 51 | + g_object[g_objpos++]=0x8FA40008; // lw a0,8(sp) | |
| 52 | + g_object[g_objpos++]=0x8FA50004; // lw a1,4(sp) | |
| 53 | + g_object[g_objpos++]=0x27BD0008; // addiu sp,sp,8 | |
| 54 | + call_lib_code(LIB_STRNCMP); | |
| 55 | + return 0; | |
| 56 | +} | |
| 57 | +char* len_function(){ | |
| 58 | + char* err; | |
| 59 | + err=get_string(); | |
| 60 | + if (err) return err; | |
| 61 | + check_obj_space(5); | |
| 62 | + g_object[g_objpos++]=0x2443FFFF; // addiu v1,v0,-1 | |
| 63 | + // loop: | |
| 64 | + g_object[g_objpos++]=0x80640001; // lb a0,1(v1) | |
| 65 | + g_object[g_objpos++]=0x1480FFFE; // bne a0,zero,loop | |
| 66 | + g_object[g_objpos++]=0x24630001; // addiu v1,v1,1 | |
| 67 | + g_object[g_objpos++]=0x00621023; // subu v0,v1,v0 | |
| 68 | + return 0; | |
| 69 | +} | |
| 70 | + | |
| 71 | +char* asc_function(){ | |
| 72 | + char* err; | |
| 73 | + err=get_string(); | |
| 74 | + if (err) return err; | |
| 75 | + check_obj_space(1); | |
| 76 | + g_object[g_objpos++]=0x90420000; // lbu v0,0(v0) | |
| 77 | + return 0; | |
| 78 | +} | |
| 79 | + | |
| 80 | +char* val_function(){ | |
| 81 | + char* err; | |
| 82 | + err=get_string(); | |
| 83 | + if (err) return err; | |
| 84 | + call_lib_code(LIB_VAL); | |
| 85 | + return 0; | |
| 86 | +} | |
| 87 | + | |
| 88 | +char* peek_function(){ | |
| 89 | + char* err; | |
| 90 | + err=get_value(); | |
| 91 | + if (err) return err; | |
| 92 | + check_obj_space(1); | |
| 93 | + g_object[g_objpos++]=0x90420000; // lbu v0,0(v0) | |
| 94 | + return 0; | |
| 95 | +} | |
| 96 | + | |
| 97 | +char* sgn_function(){ | |
| 98 | + char* err; | |
| 99 | + err=get_value(); | |
| 100 | + if (err) return err; | |
| 101 | + check_obj_space(5); | |
| 102 | + g_object[g_objpos++]=0x10400004; // beq v0,zero,end | |
| 103 | + g_object[g_objpos++]=0x24030001; // addiu v1,zero,1 | |
| 104 | + g_object[g_objpos++]=0x1C400002; // bgtz v0,end | |
| 105 | + g_object[g_objpos++]=0x00601021; // addu v0,v1,zero | |
| 106 | + g_object[g_objpos++]=0x00031023; // subu v0,zero,v1 | |
| 107 | + // end: | |
| 108 | + return 0; | |
| 109 | +} | |
| 110 | + | |
| 111 | +char* abs_function(){ | |
| 112 | + char* err; | |
| 113 | + err=get_value(); | |
| 114 | + if (err) return err; | |
| 115 | + check_obj_space(3); | |
| 116 | + g_object[g_objpos++]=0x00021FC3; //sra v1,v0,0x1f | |
| 117 | + g_object[g_objpos++]=0x00621026; //xor v0,v1,v0 | |
| 118 | + g_object[g_objpos++]=0x00431023; //subu v0,v0,v1 | |
| 119 | + return 0; | |
| 120 | +} | |
| 121 | + | |
| 122 | +char* not_function(){ | |
| 123 | + char* err; | |
| 124 | + err=get_value(); | |
| 125 | + if (err) return err; | |
| 126 | + check_obj_space(1); | |
| 127 | + g_object[g_objpos++]=0x2C420001; //sltiu v0,v0,1 | |
| 128 | + return 0; | |
| 129 | +} | |
| 130 | + | |
| 131 | +char* rnd_function(){ | |
| 132 | + call_lib_code(LIB_RND); | |
| 133 | + return 0; | |
| 134 | +} | |
| 135 | + | |
| 136 | + | |
| 137 | +char* chr_function(void){ | |
| 138 | + char* err; | |
| 139 | + err=get_value(); | |
| 140 | + if (err) return err; | |
| 141 | + call_lib_code(LIB_CHR); | |
| 142 | + return 0; | |
| 143 | +} | |
| 144 | +char* hex_function(void){ | |
| 145 | + char* err; | |
| 146 | + err=get_value(); | |
| 147 | + if (err) return err; | |
| 148 | + if (g_source[g_srcpos]==',') { | |
| 149 | + // Second argument found. | |
| 150 | + // Get is as $a0. | |
| 151 | + g_srcpos++; | |
| 152 | + check_obj_space(2); | |
| 153 | + g_object[g_objpos++]=0x27BDFFFC; //addiu sp,sp,-4 | |
| 154 | + g_object[g_objpos++]=0xAFA20004; //sw v0,4(sp) | |
| 155 | + err=get_value(); | |
| 156 | + if (err) return err; | |
| 157 | + check_obj_space(3); | |
| 158 | + g_object[g_objpos++]=0x00022021; //a0,zero,v0 | |
| 159 | + g_object[g_objpos++]=0x8FA20004; //lw v0,4(sp) | |
| 160 | + g_object[g_objpos++]=0x27BD0004; //addiu sp,sp,4 | |
| 161 | + } else { | |
| 162 | + // Second argument not found. | |
| 163 | + // Set $a0 to 0. | |
| 164 | + check_obj_space(1); | |
| 165 | + g_object[g_objpos++]=0x24040000; //addiu a0,zero,0 | |
| 166 | + } | |
| 167 | + call_lib_code(LIB_HEX); | |
| 168 | + return 0; | |
| 169 | +} | |
| 170 | + | |
| 171 | +char* dec_function(void){ | |
| 172 | + char* err; | |
| 173 | + err=get_value(); | |
| 174 | + if (err) return err; | |
| 175 | + call_lib_code(LIB_DEC); | |
| 176 | + return 0; | |
| 177 | +} | |
| 178 | + | |
| 179 | +char* keys_function(void){ | |
| 180 | + char* err; | |
| 181 | + next_position(); | |
| 182 | + if (g_source[g_srcpos]==')') { | |
| 183 | + check_obj_space(1); | |
| 184 | + g_object[g_objpos++]=0x3402003F; //ori v0,zero,0x3f | |
| 185 | + } else { | |
| 186 | + err=get_value(); | |
| 187 | + if (err) return err; | |
| 188 | + } | |
| 189 | + call_lib_code(LIB_KEYS); | |
| 190 | + return 0; | |
| 191 | +} | |
| 192 | + | |
| 193 | +char* tvram_function(void){ | |
| 194 | + char* err; | |
| 195 | + int i; | |
| 196 | + next_position(); | |
| 197 | + if (g_source[g_srcpos]==')') { | |
| 198 | + i=(int)(&TVRAM[0]); | |
| 199 | + i-=g_gp; | |
| 200 | + check_obj_space(1); | |
| 201 | + g_object[g_objpos++]=0x27820000|(i&0x0000FFFF); // addiu v0,gp,xxxx | |
| 202 | + } else { | |
| 203 | + err=get_value(); | |
| 204 | + if (err) return err; | |
| 205 | + i=(int)(&TVRAM[0]); | |
| 206 | + i-=g_gp; | |
| 207 | + check_obj_space(3); | |
| 208 | + g_object[g_objpos++]=0x27830000|(i&0x0000FFFF); // addiu v1,gp,xxxx | |
| 209 | + g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
| 210 | + g_object[g_objpos++]=0x90620000; // lbu v0,0(v1) | |
| 211 | + } | |
| 212 | + return 0; | |
| 213 | +} | |
| 214 | + | |
| 215 | +char* drawcount_function(void){ | |
| 216 | + call_lib_code(LIB_DRAWCOUNT); | |
| 217 | + return 0; | |
| 218 | +} | |
| 219 | + | |
| 220 | +char* input_function(void){ | |
| 221 | + call_lib_code(LIB_INPUT); | |
| 222 | + return 0; | |
| 223 | +} | |
| 224 | + | |
| 225 | +char* inkey_function(void){ | |
| 226 | + char* err; | |
| 227 | + next_position(); | |
| 228 | + if (g_source[g_srcpos]==')') { | |
| 229 | + check_obj_space(1); | |
| 230 | + g_object[g_objpos++]=0x34020000; //ori v0,zero,0x00 | |
| 231 | + } else { | |
| 232 | + err=get_value(); | |
| 233 | + if (err) return err; | |
| 234 | + } | |
| 235 | + call_lib_code(LIB_INKEY); | |
| 236 | + return 0; | |
| 237 | +} | |
| 238 | + | |
| 239 | +char* args_function(void){ | |
| 240 | + char* err; | |
| 241 | + int i; | |
| 242 | + err=get_value(); | |
| 243 | + if (err) return err; | |
| 244 | + i=g_object[g_objpos-1]; | |
| 245 | + if ((i>>16)==0x3402) { | |
| 246 | + // Previous object is "ori v0,zero,xxxx". | |
| 247 | + i&=0xffff; | |
| 248 | + i=(i+1)<<2; | |
| 249 | + g_object[g_objpos-1]=0x8EA20000|i; // lw v0,xx(s5) | |
| 250 | + } else { | |
| 251 | + check_obj_space(3); | |
| 252 | + g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
| 253 | + g_object[g_objpos++]=0x02A21021; // addu v0,s5,v0 | |
| 254 | + g_object[g_objpos++]=0x8C420004; // lw v0,4(v0) | |
| 255 | + } | |
| 256 | + return 0; | |
| 257 | +} | |
| 258 | + | |
| 259 | +char* system_function(void){ | |
| 260 | + char* err; | |
| 261 | + err=get_value(); | |
| 262 | + if (err) return err; | |
| 263 | + g_object[g_objpos++]=0x00402021; // addu a0,v0,zero | |
| 264 | + call_lib_code(LIB_SYSTEM); | |
| 265 | + return 0; | |
| 266 | +} | |
| 267 | + | |
| 268 | +char* sprintf_function(void){ | |
| 269 | + char* err; | |
| 270 | + err=get_string(); | |
| 271 | + if (err) return err; | |
| 272 | + next_position(); | |
| 273 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 274 | + g_srcpos++; | |
| 275 | + check_obj_space(2); | |
| 276 | + g_object[g_objpos++]=0x27BDFFFC; //addiu sp,sp,-4 | |
| 277 | + g_object[g_objpos++]=0xAFA20004; //sw v0,4(sp) | |
| 278 | + err=get_float(); | |
| 279 | + if (err) return err; | |
| 280 | + check_obj_space(3); | |
| 281 | + g_object[g_objpos++]=0x00022021; //addu a0,zero,v0 | |
| 282 | + g_object[g_objpos++]=0x8FA20004; //lw v0,4(sp) | |
| 283 | + g_object[g_objpos++]=0x27BD0004; //addiu sp,sp,4 | |
| 284 | + call_lib_code(LIB_SPRINTF); | |
| 285 | + return 0; | |
| 286 | +} | |
| 287 | + | |
| 288 | +char* floatstr_function(void){ | |
| 289 | + char* err; | |
| 290 | + err=get_float(); | |
| 291 | + if (err) return err; | |
| 292 | + check_obj_space(2); | |
| 293 | + g_object[g_objpos++]=0x00022021; //addu a0,zero,v0 | |
| 294 | + g_object[g_objpos++]=0x34020000; //ori v0,zero,0x0000 | |
| 295 | + call_lib_code(LIB_SPRINTF); | |
| 296 | + return 0; | |
| 297 | +} | |
| 298 | + | |
| 299 | +char* floatsharp_function(void){ | |
| 300 | + char* err; | |
| 301 | + err=get_value(); | |
| 302 | + if (err) return err; | |
| 303 | + check_obj_space(1); | |
| 304 | + g_object[g_objpos++]=0x34050000|(FUNC_FLOAT&0x0000ffff);// ori a1,zero,xxxx | |
| 305 | + call_lib_code(LIB_FLOATFUNCS); | |
| 306 | + return 0; | |
| 307 | +} | |
| 308 | + | |
| 309 | +char* valsharp_function(void){ | |
| 310 | + char* err; | |
| 311 | + err=get_string(); | |
| 312 | + if (err) return err; | |
| 313 | + check_obj_space(1); | |
| 314 | + g_object[g_objpos++]=0x34050000|(FUNC_VALSHARP&0x0000ffff);// ori a1,zero,xxxx | |
| 315 | + call_lib_code(LIB_FLOATFUNCS); | |
| 316 | + return 0; | |
| 317 | +} | |
| 318 | + | |
| 319 | +char* int_function(void){ | |
| 320 | + char* err; | |
| 321 | + err=get_float(); | |
| 322 | + if (err) return err; | |
| 323 | + check_obj_space(1); | |
| 324 | + g_object[g_objpos++]=0x34050000|(FUNC_INT&0x0000ffff);// ori a1,zero,xxxx | |
| 325 | + call_lib_code(LIB_FLOATFUNCS); | |
| 326 | + return 0; | |
| 327 | +} | |
| 328 | + | |
| 329 | +char* float_constant(float val){ | |
| 330 | + volatile int i; | |
| 331 | + ((float*)(&i))[0]=val; | |
| 332 | + if (i&0xFFFF0000) { | |
| 333 | + // 32 bit | |
| 334 | + check_obj_space(2); | |
| 335 | + g_object[g_objpos++]=0x3C020000|((i>>16)&0x0000FFFF); // lui v0,xxxx | |
| 336 | + g_object[g_objpos++]=0x34420000|(i&0x0000FFFF); // ori v0,v0,xxxx | |
| 337 | + } else { | |
| 338 | + // 16 bit | |
| 339 | + check_obj_space(1); | |
| 340 | + g_object[g_objpos++]=0x34020000|(i&0x0000FFFF); // ori v0,zero,xxxx | |
| 341 | + } | |
| 342 | + return 0; | |
| 343 | +} | |
| 344 | + | |
| 345 | +char* float_1param_function(enum functions func){ | |
| 346 | + char* err; | |
| 347 | + err=get_float(); | |
| 348 | + if (err) return err; | |
| 349 | + check_obj_space(1); | |
| 350 | + g_object[g_objpos++]=0x34050000|(func&0x0000ffff);// ori a1,zero,xxxx | |
| 351 | + call_lib_code(LIB_FLOATFUNCS); | |
| 352 | + return 0; | |
| 353 | +} | |
| 354 | + | |
| 355 | +char* float_2param_function(enum functions func){ | |
| 356 | + char* err; | |
| 357 | + err=get_float(); | |
| 358 | + if (err) return err; | |
| 359 | + next_position(); | |
| 360 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 361 | + g_srcpos++; | |
| 362 | + check_obj_space(2); | |
| 363 | + g_object[g_objpos++]=0x27BDFFFC; //addiu sp,sp,-4 | |
| 364 | + g_object[g_objpos++]=0xAFA20004; //sw v0,4(sp) | |
| 365 | + err=get_float(); | |
| 366 | + if (err) return err; | |
| 367 | + check_obj_space(4); | |
| 368 | + g_object[g_objpos++]=0x00022021; //addu a0,zero,v0 | |
| 369 | + g_object[g_objpos++]=0x8FA20004; //lw v0,4(sp) | |
| 370 | + g_object[g_objpos++]=0x27BD0004; //addiu sp,sp,4 | |
| 371 | + g_object[g_objpos++]=0x34050000|(func&0x0000ffff);// ori a1,zero,xxxx | |
| 372 | + call_lib_code(LIB_FLOATFUNCS); | |
| 373 | + return 0; | |
| 374 | +} | |
| 375 | + | |
| 376 | +char* float_function(void){ | |
| 377 | + char* err; | |
| 378 | + if (nextCodeIs("FLOAT#(")) { | |
| 379 | + err=floatsharp_function(); | |
| 380 | + } else if (nextCodeIs("VAL#(")) { | |
| 381 | + err=valsharp_function(); | |
| 382 | + } else if (nextCodeIs("SIN#(")) { | |
| 383 | + err=float_1param_function(FUNC_SIN); | |
| 384 | + } else if (nextCodeIs("COS#(")) { | |
| 385 | + err=float_1param_function(FUNC_COS); | |
| 386 | + } else if (nextCodeIs("TAN#(")) { | |
| 387 | + err=float_1param_function(FUNC_TAN); | |
| 388 | + } else if (nextCodeIs("ASIN#(")) { | |
| 389 | + err=float_1param_function(FUNC_ASIN); | |
| 390 | + } else if (nextCodeIs("ACOS#(")) { | |
| 391 | + err=float_1param_function(FUNC_ACOS); | |
| 392 | + } else if (nextCodeIs("ATAN#(")) { | |
| 393 | + err=float_1param_function(FUNC_ATAN); | |
| 394 | + } else if (nextCodeIs("SINH#(")) { | |
| 395 | + err=float_1param_function(FUNC_SINH); | |
| 396 | + } else if (nextCodeIs("COSH#(")) { | |
| 397 | + err=float_1param_function(FUNC_COSH); | |
| 398 | + } else if (nextCodeIs("TANH#(")) { | |
| 399 | + err=float_1param_function(FUNC_TANH); | |
| 400 | + } else if (nextCodeIs("EXP#(")) { | |
| 401 | + err=float_1param_function(FUNC_EXP); | |
| 402 | + } else if (nextCodeIs("LOG#(")) { | |
| 403 | + err=float_1param_function(FUNC_LOG); | |
| 404 | + } else if (nextCodeIs("LOG10#(")) { | |
| 405 | + err=float_1param_function(FUNC_LOG10); | |
| 406 | + } else if (nextCodeIs("POW#(")) { | |
| 407 | + err=float_2param_function(FUNC_POW); | |
| 408 | + } else if (nextCodeIs("SQRT#(")) { | |
| 409 | + err=float_1param_function(FUNC_SQRT); | |
| 410 | + } else if (nextCodeIs("CEIL#(")) { | |
| 411 | + err=float_1param_function(FUNC_CEIL); | |
| 412 | + } else if (nextCodeIs("FLOOR#(")) { | |
| 413 | + err=float_1param_function(FUNC_FLOOR); | |
| 414 | + } else if (nextCodeIs("FABS#(")) { | |
| 415 | + err=float_1param_function(FUNC_FABS); | |
| 416 | + } else if (nextCodeIs("MODF#(")) { | |
| 417 | + err=float_1param_function(FUNC_MODF); | |
| 418 | + } else if (nextCodeIs("FMOD#(")) { | |
| 419 | + err=float_2param_function(FUNC_FMOD); | |
| 420 | + } else if (nextCodeIs("GOSUB#(")) { | |
| 421 | + err=gosub_function(); | |
| 422 | + } else if (nextCodeIs("ARGS#(")) { | |
| 423 | + err=args_function(); | |
| 424 | + } else if (nextCodeIs("PI#")) { | |
| 425 | + return float_constant(3.141593); | |
| 426 | + } else { | |
| 427 | + return ERR_SYNTAX; | |
| 428 | + } | |
| 429 | + if (err) return err; | |
| 430 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
| 431 | + g_srcpos++; | |
| 432 | + return 0; | |
| 433 | +} | |
| 434 | + | |
| 435 | +char* str_function(void){ | |
| 436 | + char* err; | |
| 437 | + if (nextCodeIs("CHR$(")) { | |
| 438 | + err=chr_function(); | |
| 439 | + } else if (nextCodeIs("HEX$(")) { | |
| 440 | + err=hex_function(); | |
| 441 | + } else if (nextCodeIs("DEC$(")) { | |
| 442 | + err=dec_function(); | |
| 443 | + } else if (nextCodeIs("INPUT$(")) { | |
| 444 | + err=input_function(); | |
| 445 | + } else if (nextCodeIs("GOSUB$(")) { | |
| 446 | + err=gosub_function(); | |
| 447 | + } else if (nextCodeIs("ARGS$(")) { | |
| 448 | + err=args_function(); | |
| 449 | + } else if (nextCodeIs("READ$(")) { | |
| 450 | + err=read_function(); | |
| 451 | + } else if (nextCodeIs("SPRINTF$(")) { | |
| 452 | + err=sprintf_function(); | |
| 453 | + } else if (nextCodeIs("FLOAT$(")) { | |
| 454 | + err=floatstr_function(); | |
| 455 | + } else if (nextCodeIs("SYSTEM$(")) { | |
| 456 | + err=system_function(); | |
| 457 | + } else { | |
| 458 | + return ERR_SYNTAX; | |
| 459 | + } | |
| 460 | + if (err) return err; | |
| 461 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
| 462 | + g_srcpos++; | |
| 463 | + return 0; | |
| 464 | +} | |
| 465 | + | |
| 466 | +char* function(void){ | |
| 467 | + char* err; | |
| 468 | + if (nextCodeIs("NOT(")) { | |
| 469 | + err=not_function(); | |
| 470 | + } else if (nextCodeIs("DRAWCOUNT(")) { | |
| 471 | + err=drawcount_function(); | |
| 472 | + } else if (nextCodeIs("MUSIC(")) { | |
| 473 | + err=music_function(); | |
| 474 | + } else if (nextCodeIs("TVRAM(")) { | |
| 475 | + err=tvram_function(); | |
| 476 | + } else if (nextCodeIs("KEYS(")) { | |
| 477 | + err=keys_function(); | |
| 478 | + } else if (nextCodeIs("READ(")) { | |
| 479 | + err=read_function(); | |
| 480 | + } else if (nextCodeIs("CREAD(")) { | |
| 481 | + err=cread_function(); | |
| 482 | + } else if (nextCodeIs("GOSUB(")) { | |
| 483 | + err=gosub_function(); | |
| 484 | + } else if (nextCodeIs("STRNCMP(")) { | |
| 485 | + err=strncmp_function(); | |
| 486 | + } else if (nextCodeIs("PEEK(")) { | |
| 487 | + err=peek_function(); | |
| 488 | + } else if (nextCodeIs("LEN(")) { | |
| 489 | + err=len_function(); | |
| 490 | + } else if (nextCodeIs("ASC(")) { | |
| 491 | + err=asc_function(); | |
| 492 | + } else if (nextCodeIs("SGN(")) { | |
| 493 | + err=sgn_function(); | |
| 494 | + } else if (nextCodeIs("ABS(")) { | |
| 495 | + err=abs_function(); | |
| 496 | + } else if (nextCodeIs("RND(")) { | |
| 497 | + err=rnd_function(); | |
| 498 | + } else if (nextCodeIs("VAL(")) { | |
| 499 | + err=val_function(); | |
| 500 | + } else if (nextCodeIs("INKEY(")) { | |
| 501 | + err=inkey_function(); | |
| 502 | + } else if (nextCodeIs("ARGS(")) { | |
| 503 | + err=args_function(); | |
| 504 | + } else if (nextCodeIs("SYSTEM(")) { | |
| 505 | + err=system_function(); | |
| 506 | + } else if (nextCodeIs("INT(")) { | |
| 507 | + err=int_function(); | |
| 508 | + } else if (nextCodeIs("GCOLOR(")) { | |
| 509 | + err=graphic_statement(FUNC_GCOLOR); | |
| 510 | + } else { | |
| 511 | + return ERR_SYNTAX; | |
| 512 | + } | |
| 513 | + if (err) return err; | |
| 514 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
| 515 | + g_srcpos++; | |
| 516 | + return err; | |
| 517 | +} |
| @@ -0,0 +1,213 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +/* | |
| 9 | + Public functions: | |
| 10 | + char* get_string(void); | |
| 11 | + char* simple_string(void); | |
| 12 | +*/ | |
| 13 | + | |
| 14 | +#include "api.h" | |
| 15 | +#include "compiler.h" | |
| 16 | + | |
| 17 | +char* simple_string(void){ | |
| 18 | + char* err; | |
| 19 | + unsigned char b1,b2; | |
| 20 | + int i,j; | |
| 21 | + next_position(); | |
| 22 | + b1=g_source[g_srcpos]; | |
| 23 | + b2=g_source[g_srcpos+1]; | |
| 24 | + if (b1=='"') { | |
| 25 | + // Constant string | |
| 26 | + // Count character number (+1 for \0) | |
| 27 | + // This may be more than actual character number due to escape sequence. | |
| 28 | + i=0; | |
| 29 | + while(1){ | |
| 30 | + i++; | |
| 31 | + b1=g_source[g_srcpos+i]; | |
| 32 | + if (b1=='"') { | |
| 33 | + break; | |
| 34 | + } else if (b1=='\\') { | |
| 35 | + i++; | |
| 36 | + } else if (b1<0x20) { | |
| 37 | + // This is an error, that will be detected later again. | |
| 38 | + break; | |
| 39 | + } | |
| 40 | + }; | |
| 41 | + g_srcpos++; | |
| 42 | + // Determine required word number | |
| 43 | + i=(i+3)/4; | |
| 44 | + // Determine address containing the string | |
| 45 | + j=(int)(&(g_object[g_objpos+3])); | |
| 46 | + // Note that using "bgezal zero," must be used to skip some region. | |
| 47 | + // This is to find embed string in the code. | |
| 48 | + check_obj_space(2+i); | |
| 49 | + g_object[g_objpos++]=0x04110000|((i+1)&0x0000FFFF); // bgezal zero,xxxx | |
| 50 | + g_object[g_objpos++]=0x03E01021; // addu v0,ra,zero | |
| 51 | + for(j=0;(b1=g_source[g_srcpos++])!='"';j++) { | |
| 52 | + if (b1=='\\') { | |
| 53 | + b1=g_source[g_srcpos++]; | |
| 54 | + if (b1=='x' || b1=='X') { | |
| 55 | + // Hexadecimal | |
| 56 | + b1=g_source[g_srcpos++]; | |
| 57 | + if ('0'<=b1 && b1<='9') b1=b1-'0'; | |
| 58 | + else if ('A'<=b1 && b1<='F') b1=b1-'A'+10; | |
| 59 | + else if ('a'<=b1 && b1<='f') b1=b1-'a'+10; | |
| 60 | + else return ERR_SYNTAX; | |
| 61 | + b2=g_source[g_srcpos++]; | |
| 62 | + if ('0'<=b2 && b2<='9') b2=b2-'0'; | |
| 63 | + else if ('A'<=b2 && b2<='F') b2=b2-'A'+10; | |
| 64 | + else if ('a'<=b2 && b2<='f') b2=b2-'a'+10; | |
| 65 | + else return ERR_SYNTAX; | |
| 66 | + b1=(b1<<4)|b2; | |
| 67 | + } else if (b1<0x20) { | |
| 68 | + return ERR_SYNTAX; | |
| 69 | + } else { | |
| 70 | + // \\ or \" | |
| 71 | + } | |
| 72 | + } else if (b1<0x20) { | |
| 73 | + return ERR_SYNTAX; | |
| 74 | + } | |
| 75 | + ((char*)(&g_object[g_objpos]))[j]=b1; | |
| 76 | + } | |
| 77 | + ((char*)(&g_object[g_objpos]))[j]=0x00; | |
| 78 | + g_objpos+=i; | |
| 79 | + } else if ('A'<=b1 && b1<='Z' && b2=='$') { | |
| 80 | + // String variable | |
| 81 | + g_srcpos+=2; | |
| 82 | + next_position(); | |
| 83 | + if (g_source[g_srcpos]=='(') { | |
| 84 | + // A part of string | |
| 85 | + g_srcpos++; | |
| 86 | + err=get_value(); | |
| 87 | + if (err) return err; | |
| 88 | + if (g_source[g_srcpos]==')') { | |
| 89 | + g_srcpos++; | |
| 90 | + // Put -1 to $a0 | |
| 91 | + check_obj_space(1); | |
| 92 | + g_object[g_objpos++]=0x2404FFFF; // addiu a0,zero,-1 | |
| 93 | + } else if (g_source[g_srcpos]==',') { | |
| 94 | + g_srcpos++; | |
| 95 | + // Store $v0 in stack | |
| 96 | + g_sdepth+=4; | |
| 97 | + if (g_maxsdepth<g_sdepth) g_maxsdepth=g_sdepth; | |
| 98 | + check_obj_space(1); | |
| 99 | + g_object[g_objpos++]=0xAFA20000|g_sdepth; // sw v0,xx(sp) | |
| 100 | + // Get next value | |
| 101 | + err=get_value(); | |
| 102 | + if (err) return err; | |
| 103 | + // Copy $v0 to $a0 and get value from stack to $a0. | |
| 104 | + check_obj_space(2); | |
| 105 | + g_object[g_objpos++]=0x00402021; // addu a0,v0,zero | |
| 106 | + g_object[g_objpos++]=0x8FA20000|g_sdepth; // lw v0,xx(sp) | |
| 107 | + g_sdepth-=4; | |
| 108 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
| 109 | + g_srcpos++; | |
| 110 | + // Temp area will be used when executing. | |
| 111 | + g_temp_area_used=1; | |
| 112 | + } else { | |
| 113 | + return ERR_SYNTAX; | |
| 114 | + } | |
| 115 | + // $a1 is var number, $v0 is position, $a0 is length | |
| 116 | + check_obj_space(1); | |
| 117 | + g_object[g_objpos++]=0x24050000|(b1-'A'); // addiu a1,zero,xx | |
| 118 | + call_lib_code(LIB_MIDSTR); | |
| 119 | + } else { | |
| 120 | + // Simple string | |
| 121 | + check_obj_space(1); | |
| 122 | + g_object[g_objpos++]=0x8FC20000|((b1-'A')*4); // lw v0,xx(s8) | |
| 123 | + // String is pointed by $v0 | |
| 124 | + } | |
| 125 | + } else if ('A'<=b1 && b1<='Z') { | |
| 126 | + // Function | |
| 127 | + // String would be pointed by $v0 | |
| 128 | + // Otherwise, it will be assinged in xxx_function() function. | |
| 129 | + err=str_function(); | |
| 130 | + if (err) return err; | |
| 131 | + // Temp area would be used when executing. | |
| 132 | + g_temp_area_used=1; | |
| 133 | + return 0; | |
| 134 | + } else { | |
| 135 | + return ERR_SYNTAX; | |
| 136 | + } | |
| 137 | + return 0; | |
| 138 | +} | |
| 139 | + | |
| 140 | +char* get_string_sub(){ | |
| 141 | + char* err; | |
| 142 | + char b1; | |
| 143 | + // Obtain initial string | |
| 144 | + err=simple_string(); | |
| 145 | + if (err) return err; | |
| 146 | + // Check if connection operator exists | |
| 147 | + next_position(); | |
| 148 | + b1=g_source[g_srcpos]; | |
| 149 | + if (b1!='+' && b1!='&') return 0; // Exit if connection operator does not exist. | |
| 150 | + g_srcpos++; | |
| 151 | + // Connection required. | |
| 152 | + // Prepare one level of stack for handling | |
| 153 | + g_sdepth+=4; | |
| 154 | + if (g_maxsdepth<g_sdepth) g_maxsdepth=g_sdepth; | |
| 155 | + while(1) { | |
| 156 | + // Store current pointer in stack | |
| 157 | + check_obj_space(1); | |
| 158 | + g_object[g_objpos++]=0xAFA20000|g_sdepth; // sw v0,xx(sp) | |
| 159 | + // Obtain next string (pointer will be in $v0) | |
| 160 | + err=simple_string(); | |
| 161 | + if (err) return err; | |
| 162 | + // Restore previous pointer from stack in $a0 and copy $v0 to $a1 | |
| 163 | + // Call library | |
| 164 | + check_obj_space(2); | |
| 165 | + g_object[g_objpos++]=0x8FA40000|g_sdepth; // lw a0,xx(sp) | |
| 166 | + call_lib_code(LIB_CONNECT_STRING); | |
| 167 | + // Temp area will be used when executing. | |
| 168 | + g_temp_area_used=1; | |
| 169 | + // Check if further connection operator exists | |
| 170 | + next_position(); | |
| 171 | + b1=g_source[g_srcpos]; | |
| 172 | + if (b1!='+' && b1!='&') break; | |
| 173 | + g_srcpos++; | |
| 174 | + } | |
| 175 | + g_sdepth-=4; | |
| 176 | + return 0; | |
| 177 | +} | |
| 178 | + | |
| 179 | +char* get_string(){ | |
| 180 | + // This is only the public function. | |
| 181 | + // Note that this can be called recursively. | |
| 182 | + // String may contain a function with a parameter of value | |
| 183 | + // that is a function with a parameter of string. | |
| 184 | + // Result will be in $v0 as a pointer. | |
| 185 | + char* err; | |
| 186 | + char b1; | |
| 187 | + int i,prevpos; | |
| 188 | + if (g_sdepth==0) { | |
| 189 | + // Initialize stack handler | |
| 190 | + g_maxsdepth=0; | |
| 191 | + prevpos=g_objpos; | |
| 192 | + // Stack decrement command will be filled later | |
| 193 | + check_obj_space(1); | |
| 194 | + g_objpos++; | |
| 195 | + } | |
| 196 | + err=get_string_sub(); | |
| 197 | + if (err) return err; | |
| 198 | + if (g_sdepth==0) { | |
| 199 | + if (g_maxsdepth==0) { | |
| 200 | + // Stack was not used. | |
| 201 | + shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1); | |
| 202 | + g_objpos--; | |
| 203 | + } else { | |
| 204 | + // Stack was used. | |
| 205 | + check_obj_space(1); | |
| 206 | + g_object[prevpos]=0x27BD0000 | (0-g_maxsdepth) & 0x0000FFFF; // addiu sp,sp,-xx | |
| 207 | + g_object[g_objpos++]=0x27BD0000 | g_maxsdepth & 0x0000FFFF; // addiu sp,sp,xx | |
| 208 | + } | |
| 209 | + } | |
| 210 | + g_lastvar=VAR_STRING; | |
| 211 | + return 0; | |
| 212 | +} | |
| 213 | + |
| @@ -0,0 +1,1387 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include "api.h" | |
| 9 | +#include "compiler.h" | |
| 10 | + | |
| 11 | +char* rem_statement(){ | |
| 12 | + if (g_source[g_srcpos-4]<0x20) { | |
| 13 | + // This line contains only "REM" statement | |
| 14 | + // Delete $s6-setting command if exists. | |
| 15 | + if ((g_object[g_objpos-1]&0xffff0000)==0x34160000) g_objpos--; | |
| 16 | + } | |
| 17 | + while(0x20<=g_source[g_srcpos]){ | |
| 18 | + g_srcpos++; | |
| 19 | + } | |
| 20 | + return 0; | |
| 21 | +} | |
| 22 | + | |
| 23 | +char* sound_statement(){ | |
| 24 | + char *err; | |
| 25 | + err=get_label(); | |
| 26 | + if (err) return err; | |
| 27 | + if (g_label) { | |
| 28 | + // Label/number is constant. | |
| 29 | + // Linker will change following codes later. | |
| 30 | + // Note that 0x0814xxxx and 0x0815xxxx are specific codes for these. | |
| 31 | + check_obj_space(2); | |
| 32 | + g_object[g_objpos++]=0x08140000|((g_label>>16)&0x0000FFFF); // lui v0,xxxx | |
| 33 | + g_object[g_objpos++]=0x08150000|(g_label&0x0000FFFF); // ori v0,v0,xxxx | |
| 34 | + } else { | |
| 35 | + // Label/number will be dynamically set when executing code. | |
| 36 | + err=get_value(); | |
| 37 | + if (err) return err; | |
| 38 | + call_lib_code(LIB_LABEL); | |
| 39 | + } | |
| 40 | + call_lib_code(LIB_SOUND); | |
| 41 | + return 0; | |
| 42 | +} | |
| 43 | +char* music_statement(){ | |
| 44 | + char *err; | |
| 45 | + err=get_string(); | |
| 46 | + call_lib_code(LIB_MUSIC); | |
| 47 | + return 0; | |
| 48 | +} | |
| 49 | + | |
| 50 | +char* exec_statement(){ | |
| 51 | + char *err; | |
| 52 | + char b1; | |
| 53 | + int i,prevpos; | |
| 54 | + b1=g_source[g_srcpos]; | |
| 55 | + while('0'<=b1 && b1<='9' || b1=='-' || b1=='$'){ | |
| 56 | + prevpos=g_objpos; | |
| 57 | + g_valueisconst=1; | |
| 58 | + err=get_simple_value(); | |
| 59 | + if (!g_valueisconst) err=ERR_SYNTAX; | |
| 60 | + if (err) return err; | |
| 61 | + check_obj_space(1); | |
| 62 | + g_objpos=prevpos; | |
| 63 | + g_object[g_objpos++]=g_intconst; | |
| 64 | + next_position(); | |
| 65 | + b1=g_source[g_srcpos]; | |
| 66 | + if (b1!=',') break; | |
| 67 | + g_srcpos++; | |
| 68 | + next_position(); | |
| 69 | + b1=g_source[g_srcpos]; | |
| 70 | + if (b1==0x0d || b1==0x0a) { | |
| 71 | + // Multiline DATA/EXEC statement | |
| 72 | + g_line++; | |
| 73 | + g_fileline++; | |
| 74 | + if (b1==0x0D && g_source[g_srcpos+1]==0x0A) g_srcpos++; | |
| 75 | + g_srcpos++; | |
| 76 | + // Maintain at least 256 characters in cache. | |
| 77 | + if (256<=g_srcpos) read_file(256); | |
| 78 | + next_position(); | |
| 79 | + b1=g_source[g_srcpos]; | |
| 80 | + } | |
| 81 | + } | |
| 82 | + return 0; | |
| 83 | +} | |
| 84 | + | |
| 85 | +char* cdata_statement(){ | |
| 86 | + // 0x00000020, 0x00000021, 0x00000022, and 0x00000023 (add/addu/sub/subu zero,zero,zero) | |
| 87 | + // are the sign of data region | |
| 88 | + int beginpos,prevpos; | |
| 89 | + char* err; | |
| 90 | + char b1; | |
| 91 | + char* cpy; | |
| 92 | + int shift=0; | |
| 93 | + int i=0; | |
| 94 | + beginpos=g_objpos; | |
| 95 | + check_obj_space(2); | |
| 96 | + g_object[g_objpos++]=0x04110000; // bgezal zero,xxxx | |
| 97 | + g_object[g_objpos++]=0x00000020; // add zero,zero,zero | |
| 98 | + next_position(); | |
| 99 | + b1=g_source[g_srcpos]; | |
| 100 | + while('0'<=b1 && b1<='9' || b1=='-' || b1=='$'){ | |
| 101 | + prevpos=g_objpos; | |
| 102 | + g_valueisconst=1; | |
| 103 | + err=get_simple_value(); | |
| 104 | + if (!g_valueisconst) err=ERR_SYNTAX; | |
| 105 | + if (g_intconst<0x00 || 0xff<g_intconst) err=ERR_SYNTAX; | |
| 106 | + if (err) return err; | |
| 107 | + g_objpos=prevpos; | |
| 108 | + i|=g_intconst<<shift; | |
| 109 | + shift+=8; | |
| 110 | + if (32<=shift) { | |
| 111 | + check_obj_space(1); | |
| 112 | + g_object[g_objpos++]=i; | |
| 113 | + shift=0; | |
| 114 | + i=0; | |
| 115 | + } | |
| 116 | + next_position(); | |
| 117 | + b1=g_source[g_srcpos]; | |
| 118 | + if (b1!=',') break; | |
| 119 | + g_srcpos++; | |
| 120 | + next_position(); | |
| 121 | + b1=g_source[g_srcpos]; | |
| 122 | + if (b1==0x0d || b1==0x0a) { | |
| 123 | + // Multiline CDATA statement | |
| 124 | + g_line++; | |
| 125 | + g_fileline++; | |
| 126 | + if (b1==0x0D && g_source[g_srcpos+1]==0x0A) g_srcpos++; | |
| 127 | + g_srcpos++; | |
| 128 | + // Maintain at least 256 characters in cache. | |
| 129 | + if (256<=g_srcpos) read_file(256); | |
| 130 | + next_position(); | |
| 131 | + b1=g_source[g_srcpos]; | |
| 132 | + } | |
| 133 | + } | |
| 134 | + // Write the last 1-3 bytes and shift data if total # is not multipes of 4. | |
| 135 | + if (0<shift) { | |
| 136 | + // Convert shift value from bit-shift to data byte-shift. | |
| 137 | + shift=4-shift/8; | |
| 138 | + check_obj_space(1); | |
| 139 | + g_object[g_objpos++]=i; | |
| 140 | + for(cpy=(char*)&g_object[g_objpos]-1;(char*)&g_object[beginpos+2]<cpy;cpy--){ | |
| 141 | + cpy[0]=cpy[0-shift]; | |
| 142 | + } | |
| 143 | + } | |
| 144 | + // Determine the size of data | |
| 145 | + i=g_objpos-beginpos-1; | |
| 146 | + g_object[beginpos] =0x04110000|i; // bgezal zero,xxxx | |
| 147 | + g_object[beginpos+1]=0x00000020|shift; // add zero,zero,zero | |
| 148 | + return 0; | |
| 149 | +} | |
| 150 | + | |
| 151 | +char* data_statement(){ | |
| 152 | + // 0x00000020, 0x00000021, 0x00000022, and 0x00000023 (add/addu/sub/subu zero,zero,zero) | |
| 153 | + // are the sign of data region | |
| 154 | + int i,prevpos; | |
| 155 | + char* err; | |
| 156 | + while(1){ | |
| 157 | + prevpos=g_objpos; | |
| 158 | + check_obj_space(2); | |
| 159 | + g_object[g_objpos++]=0x04110000; // bgezal zero,xxxx | |
| 160 | + g_object[g_objpos++]=0x00000020; // add zero,zero,zero | |
| 161 | + next_position(); | |
| 162 | + if (g_source[g_srcpos]=='"') { | |
| 163 | + // Constant string | |
| 164 | + // Store pointer to string. This is 3 words bellow of current position | |
| 165 | + g_object[g_objpos]=(int)(&g_object[g_objpos+3]); | |
| 166 | + g_objpos++; | |
| 167 | + g_object[prevpos]=0x04110002; // bgezal zero,xxxx | |
| 168 | + err=simple_string(); | |
| 169 | + if (err) return err; | |
| 170 | + next_position(); | |
| 171 | + if (g_source[g_srcpos]==',') continue; | |
| 172 | + return 0; | |
| 173 | + } | |
| 174 | + err=exec_statement(); | |
| 175 | + if (err) return err; | |
| 176 | + // Determine the size of data | |
| 177 | + i=g_objpos-prevpos-1; | |
| 178 | + g_object[prevpos]=0x04110000|i; // bgezal zero,xxxx | |
| 179 | + if (g_source[g_srcpos]=='"') { | |
| 180 | + // Constant string | |
| 181 | + continue; | |
| 182 | + } | |
| 183 | + return 0; | |
| 184 | + } | |
| 185 | +} | |
| 186 | + | |
| 187 | +char* clear_statement(){ | |
| 188 | + call_lib_code(LIB_CLEAR); | |
| 189 | + return 0; | |
| 190 | +} | |
| 191 | + | |
| 192 | +char* poke_statement(){ | |
| 193 | + char* err; | |
| 194 | + err=get_value(); | |
| 195 | + if (err) return err; | |
| 196 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 197 | + g_srcpos++; | |
| 198 | + check_obj_space(2); | |
| 199 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
| 200 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
| 201 | + err=get_value(); | |
| 202 | + if (err) return err; | |
| 203 | + check_obj_space(3); | |
| 204 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
| 205 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
| 206 | + g_object[g_objpos++]=0xA0620000; // sb v0,0(v1) | |
| 207 | + return 0; | |
| 208 | +} | |
| 209 | + | |
| 210 | +char* dim_statement(){ | |
| 211 | + char* err; | |
| 212 | + char b1; | |
| 213 | + int spos; | |
| 214 | + int stack; | |
| 215 | + while(1){ | |
| 216 | + stack=0; | |
| 217 | + next_position(); | |
| 218 | + b1=g_source[g_srcpos]; | |
| 219 | + if (b1<'A' || 'Z'<b1) return ERR_SYNTAX; | |
| 220 | + g_srcpos++; | |
| 221 | + if (g_source[g_srcpos]=='#') g_srcpos++; | |
| 222 | + next_position(); | |
| 223 | + if (g_source[g_srcpos]!='(') return ERR_SYNTAX; | |
| 224 | + check_obj_space(1); | |
| 225 | + spos=g_objpos++; // addiu sp,sp,xxxx | |
| 226 | + do { | |
| 227 | + g_srcpos++; | |
| 228 | + err=get_value(); | |
| 229 | + if (err) return err; | |
| 230 | + stack+=4; | |
| 231 | + check_obj_space(1); | |
| 232 | + g_object[g_objpos++]=0xAFA20000|stack; // sw v0,8(sp) | |
| 233 | + } while (g_source[g_srcpos]==','); | |
| 234 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
| 235 | + g_srcpos++; | |
| 236 | + check_obj_space(3); | |
| 237 | + g_object[g_objpos++]=0x24040000|(b1-'A'); // addiu a0,zero,xx | |
| 238 | + g_object[g_objpos++]=0x24050000|(stack/4); // addiu a1,zero,xxxx | |
| 239 | + g_object[g_objpos++]=0x03A01025; // or v0,sp,zero | |
| 240 | + call_lib_code(LIB_DIM); | |
| 241 | + // Stack -/+ | |
| 242 | + check_obj_space(1); | |
| 243 | + g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xxxx | |
| 244 | + stack=(0-stack)&0x0000FFFF; | |
| 245 | + g_object[spos]=0x27BD0000|stack; // addiu sp,sp,xxxx | |
| 246 | + next_position(); | |
| 247 | + if (g_source[g_srcpos]!=',') break; | |
| 248 | + g_srcpos++; | |
| 249 | + } | |
| 250 | + return 0; | |
| 251 | +} | |
| 252 | + | |
| 253 | +char* label_statement(){ | |
| 254 | + char* err; | |
| 255 | + char b1; | |
| 256 | + b1=g_source[g_srcpos]; | |
| 257 | + if (b1<'A' || 'Z'<b1) return ERR_SYNTAX; // Number is not allowed here. | |
| 258 | + err=get_label(); | |
| 259 | + if (err) return err; | |
| 260 | + // Check existing label with the same name here. | |
| 261 | + if (search_label(g_label)) { | |
| 262 | + // Error: duplicate labels | |
| 263 | + printstr("Label "); | |
| 264 | + printstr(resolve_label(g_label)); | |
| 265 | + return ERR_MULTIPLE_LABEL; | |
| 266 | + } | |
| 267 | + check_obj_space(2); | |
| 268 | + g_object[g_objpos++]=0x3C160000|((g_label>>16)&0x0000FFFF); //lui s6,yyyy; | |
| 269 | + g_object[g_objpos++]=0x36D60000|(g_label&0x0000FFFF); //ori s6,s6,zzzz; | |
| 270 | + return 0; | |
| 271 | +} | |
| 272 | + | |
| 273 | +char* restore_statement(){ | |
| 274 | + char* err; | |
| 275 | + err=get_label(); | |
| 276 | + if (err) return err; | |
| 277 | + if (g_label) { | |
| 278 | + // Constant label/number | |
| 279 | + // Use 32 bit mode also for values<65536 | |
| 280 | + // This code will be replaced to code for v0 for pointer in linker. | |
| 281 | + check_obj_space(2); | |
| 282 | + g_object[g_objpos++]=0x3C020000|(g_label>>16); // lui v0,xxxx | |
| 283 | + g_object[g_objpos++]=0x34420000|(g_label&0x0000FFFF); // ori v0,v0,xxxx | |
| 284 | + } else { | |
| 285 | + // Dynamic number | |
| 286 | + err=get_value(); | |
| 287 | + if (err) return err; | |
| 288 | + } | |
| 289 | + call_lib_code(LIB_RESTORE); | |
| 290 | + return 0; | |
| 291 | +} | |
| 292 | + | |
| 293 | +char* gosub_statement_sub(){ | |
| 294 | + char* err; | |
| 295 | + err=get_label(); | |
| 296 | + if (err) return err; | |
| 297 | + if (g_label) { | |
| 298 | + // Label/number is constant. | |
| 299 | + // Linker will change following codes later. | |
| 300 | + // Note that 0x0812xxxx and 0x0813xxxx are specific codes for these. | |
| 301 | + check_obj_space(6); | |
| 302 | + g_object[g_objpos++]=0x04110003; // bgezal zero,label1 | |
| 303 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
| 304 | + g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
| 305 | + g_object[g_objpos++]=0x08120000|((g_label>>16)&0x0000FFFF); // nop | |
| 306 | + // label1: | |
| 307 | + g_object[g_objpos++]=0x08130000|(g_label&0x0000FFFF); // j xxxx | |
| 308 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
| 309 | + // label2: | |
| 310 | + } else { | |
| 311 | + // Label/number will be dynamically set when executing code. | |
| 312 | + err=get_value(); | |
| 313 | + if (err) return err; | |
| 314 | + call_lib_code(LIB_LABEL); | |
| 315 | + check_obj_space(6); | |
| 316 | + g_object[g_objpos++]=0x04110003; // bgezal zero,label1 | |
| 317 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
| 318 | + g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
| 319 | + g_object[g_objpos++]=0x00000000; // nop | |
| 320 | + // label1: | |
| 321 | + g_object[g_objpos++]=0x00400008; // jr v0 | |
| 322 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
| 323 | + // label2: | |
| 324 | + } | |
| 325 | + return 0; | |
| 326 | +} | |
| 327 | + | |
| 328 | +char* gosub_statement(){ | |
| 329 | + char* err; | |
| 330 | + int opos,spos,stack; | |
| 331 | + opos=g_objpos; | |
| 332 | + spos=g_srcpos; | |
| 333 | + err=gosub_statement_sub(); | |
| 334 | + if (err) return err; | |
| 335 | + next_position(); | |
| 336 | + // If there is no 2nd argument, return. | |
| 337 | + if (g_source[g_srcpos]!=',') return 0; | |
| 338 | + | |
| 339 | + // There is (at least) 2nd argument. | |
| 340 | + // Rewind object and construct argument-creating routine. | |
| 341 | + g_objpos=opos; | |
| 342 | + stack=4; | |
| 343 | + g_object[g_objpos++]=0x27BD0000; // addiu sp,sp,-xx | |
| 344 | + do { | |
| 345 | + g_srcpos++; | |
| 346 | + stack+=4; | |
| 347 | + err=get_stringFloatOrValue(); | |
| 348 | + if (err) return err; | |
| 349 | + check_obj_space(1); | |
| 350 | + g_object[g_objpos++]=0xAFA20000|stack; // sw v0,xx(sp) | |
| 351 | + next_position(); | |
| 352 | + } while(g_source[g_srcpos]==','); | |
| 353 | + check_obj_space(2); | |
| 354 | + g_object[g_objpos++]=0xAFB50004; // sw s5,4(sp) | |
| 355 | + g_object[g_objpos++]=0x03A0A821; // addu s5,sp,zero | |
| 356 | + g_object[opos]|=((0-stack)&0xFFFF); // addiu sp,sp,-xx (See above) | |
| 357 | + // Rewind source and construct GOSUB routine again. | |
| 358 | + opos=spos; | |
| 359 | + spos=g_srcpos; | |
| 360 | + g_srcpos=opos; | |
| 361 | + err=gosub_statement_sub(); | |
| 362 | + if (err) return err; | |
| 363 | + // Remove stack | |
| 364 | + check_obj_space(2); | |
| 365 | + g_object[g_objpos++]=0x8FB50004; // lw s5,4(sp) | |
| 366 | + g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xx | |
| 367 | + // All done, go back to wright source position | |
| 368 | + g_srcpos=spos; | |
| 369 | + return 0; | |
| 370 | +} | |
| 371 | + | |
| 372 | +char* return_statement(){ | |
| 373 | + char* err; | |
| 374 | + char b1; | |
| 375 | + next_position(); | |
| 376 | + b1=g_source[g_srcpos]; | |
| 377 | + if (0x20<b1 && b1!=':') { | |
| 378 | + // There is a return value. | |
| 379 | + err=get_stringFloatOrValue(); | |
| 380 | + if (err) return err; | |
| 381 | + } | |
| 382 | + check_obj_space(3); | |
| 383 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
| 384 | + g_object[g_objpos++]=0x00600008; // jr v1 | |
| 385 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
| 386 | + return 0; | |
| 387 | +} | |
| 388 | + | |
| 389 | +char* goto_statement(){ | |
| 390 | + char* err; | |
| 391 | + err=get_label(); | |
| 392 | + if (err) return err; | |
| 393 | + if (g_label) { | |
| 394 | + // Label/number is constant. | |
| 395 | + // Linker will change following codes later. | |
| 396 | + // Note that 0x0810xxxx and 0x0811xxxx are specific codes for these. | |
| 397 | + check_obj_space(2); | |
| 398 | + g_object[g_objpos++]=0x08100000|((g_label>>16)&0x0000FFFF); // j xxxx | |
| 399 | + g_object[g_objpos++]=0x08110000|(g_label&0x0000FFFF); // nop | |
| 400 | + } else { | |
| 401 | + // Label/number will be dynamically set when executing code. | |
| 402 | + err=get_value(); | |
| 403 | + if (err) return err; | |
| 404 | + call_lib_code(LIB_LABEL); | |
| 405 | + check_obj_space(2); | |
| 406 | + g_object[g_objpos++]=0x00400008; // jr v0 | |
| 407 | + g_object[g_objpos++]=0x00000000; // nop | |
| 408 | + } | |
| 409 | + return 0; | |
| 410 | +} | |
| 411 | + | |
| 412 | +char* if_statement(){ | |
| 413 | + char* err; | |
| 414 | + int prevpos,bpos; | |
| 415 | + // Get value. | |
| 416 | + err=get_floatOrValue(); | |
| 417 | + if (err) return err; | |
| 418 | + // Check "THEN" | |
| 419 | + if (!nextCodeIs("THEN")) return ERR_SYNTAX; | |
| 420 | + // Check if statement follows after THEN statement | |
| 421 | + next_position(); | |
| 422 | + if (nextCodeIs("REM")) { | |
| 423 | + // If REM statement follows, skip comment words. | |
| 424 | + rem_statement(); | |
| 425 | + } | |
| 426 | + if (g_source[g_srcpos]<0x20) { | |
| 427 | + // End of line. | |
| 428 | + // Use IF-THEN-ENDIF mode (multiple line mode) | |
| 429 | + check_obj_space(3); | |
| 430 | + g_object[g_objpos++]=0x30000000; // nop (see linker) | |
| 431 | + g_object[g_objpos++]=0x10400000; // beq v0,zero,xxxx | |
| 432 | + g_object[g_objpos++]=0x30000000; // nop (see linker) | |
| 433 | + return 0; | |
| 434 | + } | |
| 435 | + // One line mode | |
| 436 | + // If $v0=0 then skip. | |
| 437 | + bpos=g_objpos; | |
| 438 | + check_obj_space(2); | |
| 439 | + g_object[g_objpos++]=0x10400000; // beq v0,zero,xxxx | |
| 440 | + g_object[g_objpos++]=0x00000000; // nop | |
| 441 | + prevpos=g_srcpos; | |
| 442 | + if (statement()) { | |
| 443 | + // May be label | |
| 444 | + g_srcpos=prevpos; | |
| 445 | + err=goto_statement(); | |
| 446 | + if (err) return err; | |
| 447 | + } else { | |
| 448 | + // Must be statement(s) | |
| 449 | + while(1) { | |
| 450 | + if (g_source[g_srcpos]!=':') break; | |
| 451 | + g_srcpos++; | |
| 452 | + err=statement(); | |
| 453 | + if (err) return err; | |
| 454 | + } | |
| 455 | + } | |
| 456 | + // Check if "ELSE" exists. | |
| 457 | + if (!nextCodeIs("ELSE ")) { | |
| 458 | + // "ELSE" not found. This is the end of "IF" statement. | |
| 459 | + // Previous branch command must jump to this position. | |
| 460 | + g_object[bpos]=0x10400000|(g_objpos-bpos-1); // beq v0,zero,xxxx | |
| 461 | + return 0; | |
| 462 | + } | |
| 463 | + // Skip after ELSE if required. | |
| 464 | + check_obj_space(2); | |
| 465 | + g_object[g_objpos++]=0x10000000; // beq zero,zero,xxxx | |
| 466 | + g_object[g_objpos++]=0x00000000; // nop | |
| 467 | + // Previous branch command must jump to this position. | |
| 468 | + g_object[bpos]=0x10400000|(g_objpos-bpos-1); // beq v0,zero,xxxx | |
| 469 | + bpos=g_objpos-2; | |
| 470 | + // Next statement is either label or general statement | |
| 471 | + prevpos=g_srcpos; | |
| 472 | + if (statement()) { | |
| 473 | + // May be label | |
| 474 | + g_srcpos=prevpos; | |
| 475 | + err=goto_statement(); | |
| 476 | + if (err) return err; | |
| 477 | + } else { | |
| 478 | + // Must be statement(s) | |
| 479 | + while(1) { | |
| 480 | + if (g_source[g_srcpos]!=':') break; | |
| 481 | + g_srcpos++; | |
| 482 | + err=statement(); | |
| 483 | + if (err) return err; | |
| 484 | + } | |
| 485 | + } | |
| 486 | + // Previous branch command must jump to this position. | |
| 487 | + g_object[bpos]=0x10000000|(g_objpos-bpos-1); // beq zero,zero,xxxx | |
| 488 | + return 0; | |
| 489 | +} | |
| 490 | + | |
| 491 | +char* elseif_statement(void){ | |
| 492 | + // Multiple line mode | |
| 493 | + char* err; | |
| 494 | + g_object[g_objpos++]=0x08160100; // breakif (see linker) | |
| 495 | + g_object[g_objpos++]=0x30008000; // nop (see linker) | |
| 496 | + // Get value. | |
| 497 | + err=get_floatOrValue(); | |
| 498 | + if (err) return err; | |
| 499 | + // Check "THEN" | |
| 500 | + if (!nextCodeIs("THEN")) return ERR_SYNTAX; | |
| 501 | + // Check if statement follows after THEN statement | |
| 502 | + next_position(); | |
| 503 | + if (nextCodeIs("REM")) { | |
| 504 | + // If REM statement follows, skip comment words. | |
| 505 | + rem_statement(); | |
| 506 | + } | |
| 507 | + if (0x20<=g_source[g_srcpos]) return ERR_SYNTAX; | |
| 508 | + // Statement didn't follow after THEM statement (that is correct). | |
| 509 | + g_object[g_objpos++]=0x10400000; // beq v0,zero,xxxx | |
| 510 | + g_object[g_objpos++]=0x30000000; // nop (see linker) | |
| 511 | + return 0; | |
| 512 | + | |
| 513 | +} | |
| 514 | + | |
| 515 | +char* else_statement(void){ | |
| 516 | + // Multiple line mode | |
| 517 | + g_object[g_objpos++]=0x08160100; // breakif (see linker) | |
| 518 | + g_object[g_objpos++]=0x30008000; // nop (see linker) | |
| 519 | + g_object[g_objpos++]=0x30000000; // nop (see linker) | |
| 520 | + // Check if statement follows after THEN statement | |
| 521 | + next_position(); | |
| 522 | + if (nextCodeIs("REM")) { | |
| 523 | + // If REM statement follows, skip comment words. | |
| 524 | + rem_statement(); | |
| 525 | + } | |
| 526 | + if (0x20<=g_source[g_srcpos]) return ERR_SYNTAX; | |
| 527 | + // Statement didn't follow after THEM statement (that is correct). | |
| 528 | + return 0; | |
| 529 | +} | |
| 530 | + | |
| 531 | +char* endif_statement(void){ | |
| 532 | + // Multiple line mode | |
| 533 | + g_object[g_objpos++]=0x30008000; // nop (see linker) | |
| 534 | + g_object[g_objpos++]=0x30008000; // nop (see linker) | |
| 535 | + // Check if statement follows after THEN statement | |
| 536 | + next_position(); | |
| 537 | + if (nextCodeIs("REM")) { | |
| 538 | + // If REM statement follows, skip comment words. | |
| 539 | + rem_statement(); | |
| 540 | + } | |
| 541 | + if (0x20<=g_source[g_srcpos]) return ERR_SYNTAX; | |
| 542 | + // Statement didn't follow after THEM statement (that is correct). | |
| 543 | + return 0; | |
| 544 | +} | |
| 545 | + | |
| 546 | +char* end_statement(void){ | |
| 547 | + int i; | |
| 548 | + i=(int)&g_end_addr; | |
| 549 | + i-=g_gp; | |
| 550 | + check_obj_space(3); | |
| 551 | + g_object[g_objpos++]=0x8F820000|(i&0x0000FFFF); // lw v0,xxxx(gp) | |
| 552 | + g_object[g_objpos++]=0x00400008; // jr v0 | |
| 553 | + g_object[g_objpos++]=0x00000000; // nop | |
| 554 | + return 0; | |
| 555 | +} | |
| 556 | + | |
| 557 | +char* let_dim_sub(char b1){ | |
| 558 | + char* err; | |
| 559 | + g_srcpos++; | |
| 560 | + err=get_value(); | |
| 561 | + if (err) return err; | |
| 562 | + check_obj_space(4); | |
| 563 | + g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
| 564 | + g_object[g_objpos++]=0x8FC30000|((b1-'A')*4); // lw v1,xx(s8) | |
| 565 | + g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
| 566 | + g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp) | |
| 567 | + while(g_source[g_srcpos]==','){ | |
| 568 | + g_srcpos++; | |
| 569 | + err=get_value(); | |
| 570 | + if (err) return err; | |
| 571 | + check_obj_space(4); | |
| 572 | + g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
| 573 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
| 574 | + g_object[g_objpos++]=0x8C630000; // lw v1,0(v1) | |
| 575 | + g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
| 576 | + g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp) | |
| 577 | + } | |
| 578 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
| 579 | + g_srcpos++; | |
| 580 | + return 0; | |
| 581 | +}; | |
| 582 | + | |
| 583 | +char* let_statement(){ | |
| 584 | + char* err; | |
| 585 | + char b1,b2,b3; | |
| 586 | + int i; | |
| 587 | + next_position(); | |
| 588 | + b1=g_source[g_srcpos]; | |
| 589 | + b2=g_source[g_srcpos+1]; | |
| 590 | + b3=g_source[g_srcpos+2]; | |
| 591 | + if (b1<'A' || 'Z'<b1) return ERR_SYNTAX; | |
| 592 | + g_srcpos++; | |
| 593 | + if (b2=='#' && b3=='(') { | |
| 594 | + // Float dimension | |
| 595 | + g_srcpos++; | |
| 596 | + check_obj_space(1); | |
| 597 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
| 598 | + let_dim_sub(b1); | |
| 599 | + next_position(); | |
| 600 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
| 601 | + g_srcpos++; | |
| 602 | + err=get_float(); | |
| 603 | + if (err) return err; | |
| 604 | + check_obj_space(3); | |
| 605 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
| 606 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
| 607 | + g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
| 608 | + return 0; | |
| 609 | + } else if (b2=='#') { | |
| 610 | + // Float A-Z | |
| 611 | + g_srcpos++; | |
| 612 | + next_position(); | |
| 613 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
| 614 | + g_srcpos++; | |
| 615 | + err=get_float(); | |
| 616 | + if (err) return err; | |
| 617 | + check_obj_space(1); | |
| 618 | + g_object[g_objpos++]=0xAFC20000|((b1-'A')*4); // sw v0,xxx(s8) | |
| 619 | + return 0; | |
| 620 | + } else if (b2=='$') { | |
| 621 | + // String | |
| 622 | + g_srcpos++; | |
| 623 | + next_position(); | |
| 624 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
| 625 | + g_srcpos++; | |
| 626 | + err=get_string(); | |
| 627 | + if (err) return err; | |
| 628 | + check_obj_space(1); | |
| 629 | + g_object[g_objpos++]=0x24040000|(b1-'A'); //addiu a0,zero,xx | |
| 630 | + call_lib_code(LIB_LETSTR); | |
| 631 | + return 0; | |
| 632 | + } else if (b2=='(') { | |
| 633 | + // Dimension | |
| 634 | + check_obj_space(1); | |
| 635 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
| 636 | + let_dim_sub(b1); | |
| 637 | + next_position(); | |
| 638 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
| 639 | + g_srcpos++; | |
| 640 | + err=get_value(); | |
| 641 | + if (err) return err; | |
| 642 | + check_obj_space(3); | |
| 643 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
| 644 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
| 645 | + g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
| 646 | + return 0; | |
| 647 | + } else { | |
| 648 | + // Integer A-Z | |
| 649 | + next_position(); | |
| 650 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
| 651 | + g_srcpos++; | |
| 652 | + err=get_value(); | |
| 653 | + if (err) return err; | |
| 654 | + check_obj_space(1); | |
| 655 | + g_object[g_objpos++]=0xAFC20000|((b1-'A')*4); // sw v0,xxx(s8) | |
| 656 | + } | |
| 657 | + return 0; | |
| 658 | +} | |
| 659 | + | |
| 660 | +char* print_statement(){ | |
| 661 | + char* err; | |
| 662 | + char b1; | |
| 663 | + int i; | |
| 664 | + int status=0;// 1:',' 2:';' 0:none | |
| 665 | + while(1){ | |
| 666 | + next_position(); | |
| 667 | + b1=g_source[g_srcpos]; | |
| 668 | + if (b1<0x20 || b1==':') break; | |
| 669 | + if (!strncmp(g_source+g_srcpos,"ELSE " ,5)) break; | |
| 670 | + err=get_stringFloatOrValue(); | |
| 671 | + if (err) return err; | |
| 672 | + switch(g_lastvar){ | |
| 673 | + case VAR_INTEGER: | |
| 674 | + // Use DEC$() function. | |
| 675 | + call_lib_code(LIB_DEC); | |
| 676 | + break; | |
| 677 | + case VAR_FLOAT: | |
| 678 | + // Use FLOAT$() function. | |
| 679 | + check_obj_space(2); | |
| 680 | + g_object[g_objpos++]=0x00022021; //addu a0,zero,v0 | |
| 681 | + g_object[g_objpos++]=0x34020000; //ori v0,zero,0x0000 | |
| 682 | + call_lib_code(LIB_SPRINTF); | |
| 683 | + break; | |
| 684 | + case VAR_STRING: | |
| 685 | + default: | |
| 686 | + break; | |
| 687 | + } | |
| 688 | + // Call printstr() function | |
| 689 | + // First argument is the pointer to string | |
| 690 | + call_lib_code(LIB_PRINTSTR); | |
| 691 | + next_position(); | |
| 692 | + b1=g_source[g_srcpos]; | |
| 693 | + if (b1==',') { | |
| 694 | + status=1; | |
| 695 | + g_srcpos++; | |
| 696 | + // Call lib_string() function for comma (,) | |
| 697 | + check_obj_space(1); | |
| 698 | + g_object[g_objpos++]=0x34040001; // ori a0,zero,1 | |
| 699 | + call_lib_code(LIB_STRING); | |
| 700 | + } else if (b1==';') { | |
| 701 | + status=2; | |
| 702 | + g_srcpos++; | |
| 703 | + } else { | |
| 704 | + status=0; | |
| 705 | + } | |
| 706 | + } | |
| 707 | + if (status==0) { | |
| 708 | + // Call lib_string() function for CR (\n) | |
| 709 | + check_obj_space(1); | |
| 710 | + g_object[g_objpos++]=0x34040000; // ori a0,zero,0 | |
| 711 | + call_lib_code(LIB_STRING); | |
| 712 | + } | |
| 713 | + return 0; | |
| 714 | +} | |
| 715 | + | |
| 716 | +char* break_statement(){ | |
| 717 | + check_obj_space(2); | |
| 718 | + g_object[g_objpos++]=0x08160000; // j xxxx (See link() function) | |
| 719 | + g_object[g_objpos++]=0x00000000; // nop | |
| 720 | + return 0; | |
| 721 | +} | |
| 722 | + | |
| 723 | +char* for_statement(){ | |
| 724 | + char* err; | |
| 725 | + char b1; | |
| 726 | + // Initialization of variable | |
| 727 | + next_position(); | |
| 728 | + b1=g_source[g_srcpos]; | |
| 729 | + if (b1<'A' || 'Z'<b1) return ERR_SYNTAX; | |
| 730 | + err=let_statement(); | |
| 731 | + if (err) return err; | |
| 732 | + // Check if "TO" exists | |
| 733 | + next_position(); | |
| 734 | + if (!nextCodeIs("TO ")) return ERR_SYNTAX; | |
| 735 | + err=get_value(); | |
| 736 | + if (err) return err; | |
| 737 | + // Usage of stack: | |
| 738 | + // 12(sp): "TO" value | |
| 739 | + // 8(sp): "STEP" value | |
| 740 | + // 4(sp): Address to return to in "NEXT" statement. | |
| 741 | + // Store "TO" value in stack | |
| 742 | + check_obj_space(2); | |
| 743 | + g_object[g_objpos++]=0x0820FFF4; // addiu sp,sp,-12 (see linker) | |
| 744 | + g_object[g_objpos++]=0xAFA2000C; // sw v0,12(sp) | |
| 745 | + // Check if "STEP" exists | |
| 746 | + next_position(); | |
| 747 | + g_valueisconst=1; | |
| 748 | + if (nextCodeIs("STEP ")) { | |
| 749 | + // "STEP" exists. Get value | |
| 750 | + err=get_value(); | |
| 751 | + if (err) return err; | |
| 752 | + } else { | |
| 753 | + // "STEP" not exist. Use "1". | |
| 754 | + check_obj_space(1); | |
| 755 | + g_object[g_objpos++]=0x24020001; // addiu v0,zero,1 | |
| 756 | + g_intconst=1; | |
| 757 | + } | |
| 758 | + check_obj_space(14); | |
| 759 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) (STEP value) | |
| 760 | + g_object[g_objpos++]=0x04110004; // bgezal zero,check | |
| 761 | + g_object[g_objpos++]=0x8FC40000|((b1-'A')*4); // lw a0,xx(s8) (current var value) | |
| 762 | + // After executing "NEXT" statement, process reaches following line. | |
| 763 | + // Update variable value by adding STEP value | |
| 764 | + // Note that STEP value is loaded onto $v0 in NEXT statement | |
| 765 | + g_object[g_objpos++]=0x8FC40000|((b1-'A')*4); // lw a0,xx(s8) (current var value) | |
| 766 | + g_object[g_objpos++]=0x00822021; // addu a0,a0,v0 | |
| 767 | + g_object[g_objpos++]=0xAFC40000|((b1-'A')*4); // sw a0,xx(s8) (new var value) | |
| 768 | + // Value-checking routine and storing ra in stack | |
| 769 | + // check: | |
| 770 | + g_object[g_objpos++]=0x8FA3000C; // lw v1,12(sp) (TO value) | |
| 771 | + g_object[g_objpos++]=0x00641823; // subu v1,v1,a0 | |
| 772 | + g_object[g_objpos++]=0x04420001; // bltzl v0,negative | |
| 773 | + g_object[g_objpos++]=0x00031823; // subu v1,zero,v1 | |
| 774 | + // negative: | |
| 775 | + g_object[g_objpos++]=0x04610003; // bgez v1,continue | |
| 776 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
| 777 | + break_statement(); // (2 words) | |
| 778 | + // continue: | |
| 779 | + return 0; | |
| 780 | +} | |
| 781 | + | |
| 782 | +char* next_statement(){ | |
| 783 | + // Return to address stored in 4($sp) | |
| 784 | + // while set $v0 to 8($sp) (see for_statement) | |
| 785 | + check_obj_space(4); | |
| 786 | + g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
| 787 | + g_object[g_objpos++]=0x03E00008; // jr ra | |
| 788 | + g_object[g_objpos++]=0x8FA20008; // lw v0,8(sp) (STEP value) | |
| 789 | + g_object[g_objpos++]=0x0830000C; // addiu sp,sp,12 (see linker) | |
| 790 | + return 0; | |
| 791 | +} | |
| 792 | + | |
| 793 | +char* do_statement(){ | |
| 794 | + char* err; | |
| 795 | + // Usage of stack: | |
| 796 | + // 4(sp): Address to return to in "DO" statement. | |
| 797 | + check_obj_space(3); | |
| 798 | + g_object[g_objpos++]=0x04110001;// bgezal zero,label1: | |
| 799 | + g_object[g_objpos++]=0x0822FFFC;// addiu sp,sp,-4 (see linker) | |
| 800 | + // label1: | |
| 801 | + g_object[g_objpos++]=0xAFBF0004;// sw ra,4(sp) | |
| 802 | + next_position(); | |
| 803 | + if (nextCodeIs("WHILE ")) { | |
| 804 | + // DO WHILE | |
| 805 | + err=get_floatOrValue(); | |
| 806 | + if (err) return err; | |
| 807 | + check_obj_space(2); | |
| 808 | + g_object[g_objpos++]=0x14400003; // bne v0,zero,labe2 | |
| 809 | + g_object[g_objpos++]=0x00000000; // nop | |
| 810 | + return break_statement(); // (2 words) | |
| 811 | + // label2: | |
| 812 | + | |
| 813 | + } else if (nextCodeIs("UNTIL ")) { | |
| 814 | + // DO UNTIL | |
| 815 | + err=get_floatOrValue(); | |
| 816 | + if (err) return err; | |
| 817 | + check_obj_space(2); | |
| 818 | + g_object[g_objpos++]=0x10400003; // beq v0,zero,label2 | |
| 819 | + g_object[g_objpos++]=0x00000000; // nop | |
| 820 | + return break_statement(); // (2 words) | |
| 821 | + // label2: | |
| 822 | + } else { | |
| 823 | + // DO statement without WHILE/UNTIL | |
| 824 | + return 0; | |
| 825 | + } | |
| 826 | +} | |
| 827 | + | |
| 828 | +char* loop_statement(){ | |
| 829 | + char* err; | |
| 830 | + next_position(); | |
| 831 | + if (nextCodeIs("WHILE ")) { | |
| 832 | + // LOOP WHILE | |
| 833 | + err=get_floatOrValue(); | |
| 834 | + if (err) return err; | |
| 835 | + check_obj_space(1); | |
| 836 | + g_object[g_objpos++]=0x10400003; // beq v0,zero,label1 | |
| 837 | + } else if (nextCodeIs("UNTIL ")) { | |
| 838 | + // LOOP UNTIL | |
| 839 | + err=get_floatOrValue(); | |
| 840 | + if (err) return err; | |
| 841 | + check_obj_space(1); | |
| 842 | + g_object[g_objpos++]=0x14400003; // bne v0,zero,label | |
| 843 | + } else { | |
| 844 | + // LOOP statement without WHILE/UNTIL | |
| 845 | + } | |
| 846 | + check_obj_space(4); | |
| 847 | + g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
| 848 | + g_object[g_objpos++]=0x03E00008; // jr ra | |
| 849 | + g_object[g_objpos++]=0x00000000; // nop | |
| 850 | + // label1: | |
| 851 | + g_object[g_objpos++]=0x08320004; // addiu sp,sp,4 (See link() function) | |
| 852 | + return 0; | |
| 853 | +} | |
| 854 | + | |
| 855 | +char* while_statement(){ | |
| 856 | + char* err; | |
| 857 | + check_obj_space(3); | |
| 858 | + g_object[g_objpos++]=0x04110001; // bgezal zero,label1: | |
| 859 | + g_object[g_objpos++]=0x0821FFFC; // addiu sp,sp,-4 (see linker) | |
| 860 | + // label1: | |
| 861 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
| 862 | + err=get_floatOrValue(); | |
| 863 | + if (err) return err; | |
| 864 | + check_obj_space(2); | |
| 865 | + g_object[g_objpos++]=0x14400003; // bne v0,zero,label2 | |
| 866 | + g_object[g_objpos++]=0x00000000; // nop | |
| 867 | + return break_statement(); // (2 words) | |
| 868 | + // label2: | |
| 869 | +} | |
| 870 | + | |
| 871 | +char* wend_statement(){ | |
| 872 | + check_obj_space(4); | |
| 873 | + g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
| 874 | + g_object[g_objpos++]=0x03E00008; // jr ra | |
| 875 | + g_object[g_objpos++]=0x00000000; // nop | |
| 876 | + // label1: | |
| 877 | + g_object[g_objpos++]=0x08310004; // addiu sp,sp,4 (See link() function) | |
| 878 | + return 0; | |
| 879 | +} | |
| 880 | + | |
| 881 | +char* palette_statement(enum libs lib){ | |
| 882 | + // lib is either LIB_PALETTE or LIB_GPALETTE | |
| 883 | + // PALETTE N,R,G,B | |
| 884 | + char* err; | |
| 885 | + // Get N | |
| 886 | + err=get_value(); | |
| 887 | + if (err) return err; | |
| 888 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 889 | + g_srcpos++; | |
| 890 | + check_obj_space(2); | |
| 891 | + g_object[g_objpos++]=0x27BDFFF4; // addiu sp,sp,-12 | |
| 892 | + g_object[g_objpos++]=0xAFA2000C; // sw v0,12(sp) | |
| 893 | + // Get R | |
| 894 | + err=get_value(); | |
| 895 | + if (err) return err; | |
| 896 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 897 | + g_srcpos++; | |
| 898 | + check_obj_space(1); | |
| 899 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
| 900 | + // Get G | |
| 901 | + err=get_value(); | |
| 902 | + if (err) return err; | |
| 903 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 904 | + g_srcpos++; | |
| 905 | + check_obj_space(1); | |
| 906 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
| 907 | + // Get B | |
| 908 | + err=get_value(); | |
| 909 | + if (err) return err; | |
| 910 | + check_obj_space(6); | |
| 911 | + g_object[g_objpos++]=0x8FA40008; // lw a0,8(sp) | |
| 912 | + g_object[g_objpos++]=0x00042400; // sll a0,a0,0x10 | |
| 913 | + g_object[g_objpos++]=0x8FA50004; // lw a1,4(sp) | |
| 914 | + g_object[g_objpos++]=0x00A42825; // or a1,a1,a0 | |
| 915 | + g_object[g_objpos++]=0x8FA4000C; // lw a0,12(sp) | |
| 916 | + g_object[g_objpos++]=0x27BD000C; // addiu sp,sp,12 | |
| 917 | + // a0=N, a1=(R<<16)|G, v0=B | |
| 918 | + call_lib_code(lib); | |
| 919 | + return 0; | |
| 920 | +} | |
| 921 | + | |
| 922 | +char* param3_statement(enum libs lib){ | |
| 923 | + char* err; | |
| 924 | + // Get 1st parameter | |
| 925 | + err=get_value(); | |
| 926 | + if (err) return err; | |
| 927 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 928 | + g_srcpos++; | |
| 929 | + check_obj_space(2); | |
| 930 | + g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
| 931 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
| 932 | + // Get 2nd parameter | |
| 933 | + err=get_value(); | |
| 934 | + if (err) return err; | |
| 935 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 936 | + g_srcpos++; | |
| 937 | + check_obj_space(1); | |
| 938 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
| 939 | + // Get 3rd parameter | |
| 940 | + err=get_value(); | |
| 941 | + if (err) return err; | |
| 942 | + check_obj_space(3); | |
| 943 | + g_object[g_objpos++]=0x8FA40008; // lw a0,8(sp) | |
| 944 | + g_object[g_objpos++]=0x8FA50004; // lw a1,4(sp) | |
| 945 | + g_object[g_objpos++]=0x27BD0008; // addiu sp,sp,8 | |
| 946 | + // a0=1st, a1=2nd, v0=3rd | |
| 947 | + call_lib_code(lib); | |
| 948 | + return 0; | |
| 949 | +} | |
| 950 | + | |
| 951 | +char* bgcolor_statement(){ | |
| 952 | + // BGCOLOR R,G,B | |
| 953 | + return param3_statement(LIB_BGCOLOR); | |
| 954 | +} | |
| 955 | + | |
| 956 | +char* pcg_statement(){ | |
| 957 | + // PCG ASCII,D1,D2 | |
| 958 | + return param3_statement(LIB_PCG); | |
| 959 | +} | |
| 960 | + | |
| 961 | +char* usepcg_statement(){ | |
| 962 | + int objpos=g_objpos; | |
| 963 | + if (get_value()) { | |
| 964 | + // Getting integer failed. | |
| 965 | + // It supporsed to be not parameter | |
| 966 | + // and same as parameter=1. | |
| 967 | + g_objpos=objpos; | |
| 968 | + check_obj_space(1); | |
| 969 | + g_object[g_objpos++]=0x34020001; //ori v0,zero,0x01 | |
| 970 | + } | |
| 971 | + call_lib_code(LIB_USEPCG); | |
| 972 | + return 0; | |
| 973 | +} | |
| 974 | + | |
| 975 | +char* usegraphic_statement(){ | |
| 976 | + int objpos=g_objpos; | |
| 977 | + if (get_value()) { | |
| 978 | + // Getting integer failed. | |
| 979 | + // It supporsed to be not parameter | |
| 980 | + // and same as parameter=1. | |
| 981 | + g_objpos=objpos; | |
| 982 | + check_obj_space(1); | |
| 983 | + g_object[g_objpos++]=0x34020001; //ori v0,zero,0x01 | |
| 984 | + } | |
| 985 | + call_lib_code(LIB_USEGRAPHIC); | |
| 986 | + return 0; | |
| 987 | +} | |
| 988 | + | |
| 989 | +char* cls_statement(){ | |
| 990 | + call_lib_code(LIB_CLS); | |
| 991 | + return 0; | |
| 992 | +} | |
| 993 | + | |
| 994 | +char* gcls_statement(){ | |
| 995 | + call_lib_code(LIB_GCLS); | |
| 996 | + return 0; | |
| 997 | +} | |
| 998 | + | |
| 999 | +char* color_statement(){ | |
| 1000 | + char* err; | |
| 1001 | + err=get_value(); | |
| 1002 | + if (err) return err; | |
| 1003 | + call_lib_code(LIB_COLOR); | |
| 1004 | + return 0; | |
| 1005 | +} | |
| 1006 | + | |
| 1007 | +char* gcolor_statement(){ | |
| 1008 | + char* err; | |
| 1009 | + err=get_value(); | |
| 1010 | + if (err) return err; | |
| 1011 | + call_lib_code(LIB_GCOLOR); | |
| 1012 | + return 0; | |
| 1013 | +} | |
| 1014 | + | |
| 1015 | +char* param2_statement(enum libs lib){ | |
| 1016 | + char* err; | |
| 1017 | + // Get 1st | |
| 1018 | + err=get_value(); | |
| 1019 | + if (err) return err; | |
| 1020 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 1021 | + g_srcpos++; | |
| 1022 | + check_obj_space(2); | |
| 1023 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
| 1024 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
| 1025 | + // Get 2nd | |
| 1026 | + err=get_value(); | |
| 1027 | + if (err) return err; | |
| 1028 | + check_obj_space(2); | |
| 1029 | + g_object[g_objpos++]=0x8FA40004; // lw a0,4(sp) | |
| 1030 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
| 1031 | + call_lib_code(lib); | |
| 1032 | + return 0; | |
| 1033 | +} | |
| 1034 | + | |
| 1035 | +char* system_statement(){ | |
| 1036 | + // SYSTEM X,Y | |
| 1037 | + return param2_statement(LIB_SYSTEM); | |
| 1038 | +} | |
| 1039 | + | |
| 1040 | +char* cursor_statement(){ | |
| 1041 | + // CURSOR X,Y | |
| 1042 | + return param2_statement(LIB_CURSOR); | |
| 1043 | +} | |
| 1044 | + | |
| 1045 | +char* scroll_statement(){ | |
| 1046 | + // SCROLL X,Y | |
| 1047 | + return param2_statement(LIB_SCROLL); | |
| 1048 | +} | |
| 1049 | + | |
| 1050 | +char* drawcount_statement(){ | |
| 1051 | + char* err; | |
| 1052 | + err=get_value(); | |
| 1053 | + if (err) return err; | |
| 1054 | + call_lib_code(LIB_SETDRAWCOUNT); | |
| 1055 | + return 0; | |
| 1056 | +} | |
| 1057 | + | |
| 1058 | +char* wait_statement(){ | |
| 1059 | + char* err; | |
| 1060 | + err=get_value(); | |
| 1061 | + if (err) return err; | |
| 1062 | + call_lib_code(LIB_WAIT); | |
| 1063 | + return 0; | |
| 1064 | +} | |
| 1065 | +char* var_statement(){ | |
| 1066 | + // Clear flags | |
| 1067 | + unsigned int flags=0; | |
| 1068 | + // Prepare stack | |
| 1069 | + // Note that 12 bytes is used in lib_var() | |
| 1070 | + // Another 4 bytes is used for return address | |
| 1071 | + short stack=12; | |
| 1072 | + char b; | |
| 1073 | + do { | |
| 1074 | + // Seek variable | |
| 1075 | + next_position(); | |
| 1076 | + b=g_source[g_srcpos++]; | |
| 1077 | + if (b<'A' || 'Z'<b) return ERR_SYNTAX; | |
| 1078 | + flags|=1<<(b-'A'); | |
| 1079 | + stack+=4; | |
| 1080 | + // Support float and string variables | |
| 1081 | + b=g_source[g_srcpos]; | |
| 1082 | + if (b=='#' || b=='$') g_srcpos++; | |
| 1083 | + // Seek ',' or end of statement | |
| 1084 | + next_position(); | |
| 1085 | + b=g_source[g_srcpos++]; | |
| 1086 | + } while(b==','); | |
| 1087 | + g_srcpos--; | |
| 1088 | + // Jump to push routine, first | |
| 1089 | + check_obj_space(2); | |
| 1090 | + g_object[g_objpos++]=0x04110007; // bgezal zero,label1 | |
| 1091 | + g_object[g_objpos++]=0x27BD0000|((0-stack)&0xffff); // addiu sp,sp,-xx | |
| 1092 | + // Process will be here after RETURN statement | |
| 1093 | + // Pop routine | |
| 1094 | + check_obj_space(1); | |
| 1095 | + g_object[g_objpos++]=0x03A02821; // addu a1,sp,zero | |
| 1096 | + call_lib_code(LIB_VAR_POP); | |
| 1097 | + // Restore stack and return | |
| 1098 | + check_obj_space(4); | |
| 1099 | + g_object[g_objpos++]=0x8FA30000|stack; // lw v1,xx(sp) | |
| 1100 | + g_object[g_objpos++]=0x00600008; // jr v1 | |
| 1101 | + g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xx | |
| 1102 | + // Push rotine | |
| 1103 | + check_obj_space(4); // label1: | |
| 1104 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
| 1105 | + g_object[g_objpos++]=0x03A02821; // addu a1,sp,zero | |
| 1106 | + g_object[g_objpos++]=0x3C040000|(flags>>16); // lui a0,XXXX | |
| 1107 | + g_object[g_objpos++]=0x34840000|(flags&0xffff); // ori a0,a0,XXXX | |
| 1108 | + call_lib_code(LIB_VAR_PUSH); | |
| 1109 | + return 0; | |
| 1110 | +} | |
| 1111 | + | |
| 1112 | +char* graphic_statement(enum functions func){ | |
| 1113 | + /* | |
| 1114 | + PSET X1,Y1[,C] | |
| 1115 | + LINE X1,Y1,X2,Y2[,C] | |
| 1116 | + BOXFILL X1,Y1,X2,Y2[,C] | |
| 1117 | + CIRCLE X1,Y1,R[,C] | |
| 1118 | + CIRCLEFILL X1,Y1,R[,C] | |
| 1119 | + GPRINT X1,Y1,C,BC,S$ | |
| 1120 | + PUTBMP X1,Y1,M,N,BMP | |
| 1121 | + $a0 cotains func (8 bits), X1 (12 bits) and Y1 (12 bits) | |
| 1122 | + $a1 contains X2/R (12 bits) and Y2 (12 bits) | |
| 1123 | + $v0 contains C/S$/BMP (32 bits) | |
| 1124 | + */ | |
| 1125 | + char* err; | |
| 1126 | + int paramnum; | |
| 1127 | + switch(func){ | |
| 1128 | + case FUNC_PSET:// X1,Y1[,C] | |
| 1129 | + case FUNC_GCOLOR:// X1,Y1 | |
| 1130 | + case FUNC_POINT:// X1,Y1 | |
| 1131 | + paramnum=2; | |
| 1132 | + break; | |
| 1133 | + case FUNC_CIRCLE:// X1,Y1,R[,C] | |
| 1134 | + case FUNC_CIRCLEFILL:// X1,Y1,R[,C] | |
| 1135 | + paramnum=3; | |
| 1136 | + break; | |
| 1137 | + case FUNC_LINE:// X1,Y1,X2,Y2[,C] | |
| 1138 | + case FUNC_BOXFILL:// X1,Y1,X2,Y2[,C] | |
| 1139 | + paramnum=4; | |
| 1140 | + break; | |
| 1141 | + case FUNC_GPRINT:// X1,Y1,C,BC,S$ | |
| 1142 | + case FUNC_PUTBMP:// X1,Y1,M,N,BMP | |
| 1143 | + paramnum=5; | |
| 1144 | + break; | |
| 1145 | + default: | |
| 1146 | + return ERR_UNKNOWN; | |
| 1147 | + } | |
| 1148 | + | |
| 1149 | + next_position(); | |
| 1150 | + if (g_source[g_srcpos]==',') { | |
| 1151 | + // X1 and Y1 is omitted. Set 0x800 for both. | |
| 1152 | + check_obj_space(4); | |
| 1153 | + g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
| 1154 | + g_object[g_objpos++]=0x3C020080; // lui v0,0x0080 | |
| 1155 | + g_object[g_objpos++]=0x34420800; // ori v0,v0,0x0800 | |
| 1156 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
| 1157 | + } else { | |
| 1158 | + // X1 | |
| 1159 | + err=get_value(); | |
| 1160 | + if (err) return err; | |
| 1161 | + check_obj_space(4); | |
| 1162 | + g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
| 1163 | + g_object[g_objpos++]=0x30420FFF; // andi v0,v0,0xfff | |
| 1164 | + g_object[g_objpos++]=0x00021300; // sll v0,v0,0xc | |
| 1165 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
| 1166 | + // Y1 | |
| 1167 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 1168 | + g_srcpos++; | |
| 1169 | + err=get_value(); | |
| 1170 | + if (err) return err; | |
| 1171 | + check_obj_space(4); | |
| 1172 | + g_object[g_objpos++]=0x30420FFF; // andi v0,v0,0xfff | |
| 1173 | + g_object[g_objpos++]=0x8FA40004; // lw a0,4(sp) | |
| 1174 | + g_object[g_objpos++]=0x00441025; // or v0,v0,a0 | |
| 1175 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
| 1176 | + } | |
| 1177 | + if (2<paramnum) { | |
| 1178 | + // X2, R, or M | |
| 1179 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 1180 | + g_srcpos++; | |
| 1181 | + err=get_value(); | |
| 1182 | + if (err) return err; | |
| 1183 | + check_obj_space(3); | |
| 1184 | + g_object[g_objpos++]=0x30420FFF; // andi v0,v0,0xfff | |
| 1185 | + g_object[g_objpos++]=0x00021300; // sll v0,v0,0xc | |
| 1186 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
| 1187 | + if (3<paramnum) { | |
| 1188 | + // X2, BC, or N | |
| 1189 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 1190 | + g_srcpos++; | |
| 1191 | + err=get_value(); | |
| 1192 | + if (err) return err; | |
| 1193 | + check_obj_space(4); | |
| 1194 | + g_object[g_objpos++]=0x30420FFF; // andi v0,v0,0xfff | |
| 1195 | + g_object[g_objpos++]=0x8FA40008; // lw a0,8(sp) | |
| 1196 | + g_object[g_objpos++]=0x00441025; // or v0,v0,a0 | |
| 1197 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
| 1198 | + } | |
| 1199 | + } | |
| 1200 | + if (func==FUNC_GPRINT) { | |
| 1201 | + // S$ | |
| 1202 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 1203 | + g_srcpos++; | |
| 1204 | + err=get_string(); | |
| 1205 | + if (err) return err; | |
| 1206 | + } else if (func==FUNC_PUTBMP) { | |
| 1207 | + // BMP | |
| 1208 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
| 1209 | + g_srcpos++; | |
| 1210 | + err=get_label(); | |
| 1211 | + if (g_label && !err) { | |
| 1212 | + // Label/number is constant. | |
| 1213 | + // Linker will change following codes later. | |
| 1214 | + // Note that 0x0814xxxx and 0x0815xxxx are specific codes for these. | |
| 1215 | + check_obj_space(2); | |
| 1216 | + g_object[g_objpos++]=0x08140000|((g_label>>16)&0x0000FFFF); // lui v0,xxxx | |
| 1217 | + g_object[g_objpos++]=0x08150000|(g_label&0x0000FFFF); // ori v0,v0,xxxx | |
| 1218 | + // Change func to FUNC_PUTBMP2 (label mode). | |
| 1219 | + func=FUNC_PUTBMP2; | |
| 1220 | + } else { | |
| 1221 | + err=get_value(); | |
| 1222 | + if (err) return err; | |
| 1223 | + } | |
| 1224 | + } else { | |
| 1225 | + // [,C] | |
| 1226 | + if (g_source[g_srcpos]==',') { | |
| 1227 | + g_srcpos++; | |
| 1228 | + err=get_value(); | |
| 1229 | + if (err) return err; | |
| 1230 | + } else { | |
| 1231 | + // If C is omitted, use -1. | |
| 1232 | + check_obj_space(1); | |
| 1233 | + g_object[g_objpos++]=0x2402FFFF; // addiu v0,zero,-1 | |
| 1234 | + } | |
| 1235 | + } | |
| 1236 | + // Prepare $a0 | |
| 1237 | + check_obj_space(1); | |
| 1238 | + g_object[g_objpos++]=0x34040000|(func&0x0ff); // ori a0,zero,xxxx | |
| 1239 | + g_object[g_objpos++]=0x00042600; // sll a0,a0,0x18 | |
| 1240 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
| 1241 | + g_object[g_objpos++]=0x00832025; // or a0,a0,v1 | |
| 1242 | + // Prepare $a1 | |
| 1243 | + g_object[g_objpos++]=0x8FA50008; // lw a1,8(sp) | |
| 1244 | + // Restore stack pointer | |
| 1245 | + g_object[g_objpos++]=0x27BD0008; // addiu sp,sp,8 | |
| 1246 | + // Call library | |
| 1247 | + call_lib_code(LIB_GRAPHIC); | |
| 1248 | + return 0; | |
| 1249 | +} | |
| 1250 | +#ifdef __DEBUG | |
| 1251 | + char* debug_statement(){ | |
| 1252 | + call_lib_code(LIB_DEBUG); | |
| 1253 | + return 0; | |
| 1254 | + } | |
| 1255 | +#endif | |
| 1256 | + | |
| 1257 | + | |
| 1258 | +char* statement(void){ | |
| 1259 | + char* err; | |
| 1260 | + int prevpos; | |
| 1261 | + next_position(); | |
| 1262 | + // Clear flag for temp area usage. | |
| 1263 | + g_temp_area_used=0; | |
| 1264 | + // Initialize stack handler used for value | |
| 1265 | + g_sdepth=g_maxsdepth=0; | |
| 1266 | + if (nextCodeIs("REM")) { | |
| 1267 | + err=rem_statement(); | |
| 1268 | + } else if (nextCodeIs("SOUND ")) { | |
| 1269 | + err=sound_statement(); | |
| 1270 | + } else if (nextCodeIs("MUSIC ")) { | |
| 1271 | + err=music_statement(); | |
| 1272 | + } else if (nextCodeIs("DRAWCOUNT ")) { | |
| 1273 | + err=drawcount_statement(); | |
| 1274 | + } else if (nextCodeIs("CURSOR ")) { | |
| 1275 | + err=cursor_statement(); | |
| 1276 | + } else if (nextCodeIs("PALETTE ")) { | |
| 1277 | + err=palette_statement(LIB_PALETTE); | |
| 1278 | + } else if (nextCodeIs("GPALETTE ")) { | |
| 1279 | + err=palette_statement(LIB_GPALETTE); | |
| 1280 | + } else if (nextCodeIs("BGCOLOR ")) { | |
| 1281 | + err=bgcolor_statement(); | |
| 1282 | + } else if (nextCodeIs("CLS")) { | |
| 1283 | + err=cls_statement(); | |
| 1284 | + } else if (nextCodeIs("GCLS")) { | |
| 1285 | + err=gcls_statement(); | |
| 1286 | + } else if (nextCodeIs("COLOR ")) { | |
| 1287 | + err=color_statement(); | |
| 1288 | + } else if (nextCodeIs("GCOLOR ")) { | |
| 1289 | + err=gcolor_statement(); | |
| 1290 | + } else if (nextCodeIs("RESTORE ")) { | |
| 1291 | + err=restore_statement(); | |
| 1292 | + } else if (nextCodeIs("DATA ")) { | |
| 1293 | + err=data_statement(); | |
| 1294 | + } else if (nextCodeIs("CDATA ")) { | |
| 1295 | + err=cdata_statement(); | |
| 1296 | + } else if (nextCodeIs("LABEL ")) { | |
| 1297 | + err=label_statement(); | |
| 1298 | + } else if (nextCodeIs("DIM ")) { | |
| 1299 | + err=dim_statement(); | |
| 1300 | + } else if (nextCodeIs("CLEAR")) { | |
| 1301 | + err=clear_statement(); | |
| 1302 | + } else if (nextCodeIs("PRINT")) { | |
| 1303 | + err=print_statement(); | |
| 1304 | + } else if (nextCodeIs("IF ")) { | |
| 1305 | + err=if_statement(); | |
| 1306 | + } else if (nextCodeIs("ELSEIF ")) { | |
| 1307 | + err=elseif_statement(); | |
| 1308 | + } else if (nextCodeIs("ELSE")) { | |
| 1309 | + err=else_statement(); | |
| 1310 | + } else if (nextCodeIs("ENDIF")) { | |
| 1311 | + err=endif_statement(); | |
| 1312 | + } else if (nextCodeIs("END")) { | |
| 1313 | + err=end_statement(); | |
| 1314 | + } else if (nextCodeIs("EXEC ")) { | |
| 1315 | + err=exec_statement(); | |
| 1316 | + } else if (nextCodeIs("GOTO ")) { | |
| 1317 | + err=goto_statement(); | |
| 1318 | + } else if (nextCodeIs("GOSUB ")) { | |
| 1319 | + err=gosub_statement(); | |
| 1320 | + } else if (nextCodeIs("RETURN")) { | |
| 1321 | + err=return_statement(); | |
| 1322 | + } else if (nextCodeIs("POKE ")) { | |
| 1323 | + err=poke_statement(); | |
| 1324 | + } else if (nextCodeIs("FOR ")) { | |
| 1325 | + err=for_statement(); | |
| 1326 | + } else if (nextCodeIs("NEXT")) { | |
| 1327 | + err=next_statement(); | |
| 1328 | + } else if (nextCodeIs("LET ")) { | |
| 1329 | + err=let_statement(); | |
| 1330 | + } else if (nextCodeIs("PCG ")) { | |
| 1331 | + err=pcg_statement(); | |
| 1332 | + } else if (nextCodeIs("USEPCG")) { | |
| 1333 | + err=usepcg_statement(); | |
| 1334 | + } else if (nextCodeIs("SCROLL ")) { | |
| 1335 | + err=scroll_statement(); | |
| 1336 | + } else if (nextCodeIs("WAIT ")) { | |
| 1337 | + err=wait_statement(); | |
| 1338 | + } else if (nextCodeIs("USEGRAPHIC")) { | |
| 1339 | + err=usegraphic_statement(); | |
| 1340 | + } else if (nextCodeIs("PSET ")) { | |
| 1341 | + err=graphic_statement(FUNC_PSET); | |
| 1342 | + } else if (nextCodeIs("LINE ")) { | |
| 1343 | + err=graphic_statement(FUNC_LINE); | |
| 1344 | + } else if (nextCodeIs("BOXFILL ")) { | |
| 1345 | + err=graphic_statement(FUNC_BOXFILL); | |
| 1346 | + } else if (nextCodeIs("CIRCLE ")) { | |
| 1347 | + err=graphic_statement(FUNC_CIRCLE); | |
| 1348 | + } else if (nextCodeIs("CIRCLEFILL ")) { | |
| 1349 | + err=graphic_statement(FUNC_CIRCLEFILL); | |
| 1350 | + } else if (nextCodeIs("GPRINT ")) { | |
| 1351 | + err=graphic_statement(FUNC_GPRINT); | |
| 1352 | + } else if (nextCodeIs("PUTBMP ")) { | |
| 1353 | + err=graphic_statement(FUNC_PUTBMP); | |
| 1354 | + } else if (nextCodeIs("POINT ")) { | |
| 1355 | + err=graphic_statement(FUNC_POINT); | |
| 1356 | + } else if (nextCodeIs("VAR ")) { | |
| 1357 | + err=var_statement(); | |
| 1358 | + } else if (nextCodeIs("DO")) { | |
| 1359 | + err=do_statement(); | |
| 1360 | + } else if (nextCodeIs("LOOP")) { | |
| 1361 | + err=loop_statement(); | |
| 1362 | + } else if (nextCodeIs("WHILE ")) { | |
| 1363 | + err=while_statement(); | |
| 1364 | + } else if (nextCodeIs("WEND")) { | |
| 1365 | + err=wend_statement(); | |
| 1366 | + } else if (nextCodeIs("BREAK")) { | |
| 1367 | + err=break_statement(); | |
| 1368 | + } else if (nextCodeIs("SYSTEM")) { | |
| 1369 | + err=system_statement(); | |
| 1370 | +#ifdef __DEBUG | |
| 1371 | + } else if (nextCodeIs("DEBUG")) { | |
| 1372 | + err=debug_statement(); | |
| 1373 | +#endif | |
| 1374 | + } else { | |
| 1375 | + err=let_statement(); | |
| 1376 | + } | |
| 1377 | + if (err) return err; | |
| 1378 | + // Stack handler must be zero here. | |
| 1379 | + if (g_sdepth!=0) return ERR_UNKNOWN; | |
| 1380 | + // Check if temp area is used | |
| 1381 | + if (g_temp_area_used) { | |
| 1382 | + // Temp area is used. Insert a garbage collection flag setting routine. | |
| 1383 | + check_obj_space(1); | |
| 1384 | + g_object[g_objpos++]=0x7ED6F000;// ext s6,s6,0,31 | |
| 1385 | + } | |
| 1386 | + return 0; | |
| 1387 | +} |
| @@ -0,0 +1,368 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include "compiler.h" | |
| 9 | + | |
| 10 | +unsigned int g_label; | |
| 11 | + | |
| 12 | +char* get_label(void){ | |
| 13 | + unsigned int i; | |
| 14 | + char b1; | |
| 15 | + int prevpos; | |
| 16 | + next_position(); | |
| 17 | + prevpos=g_srcpos; | |
| 18 | + i=0; | |
| 19 | + b1=g_source[g_srcpos]; | |
| 20 | + if ('0'<= b1 && b1<='9') { | |
| 21 | + // May be line number | |
| 22 | + do { | |
| 23 | + i*=10; | |
| 24 | + i+=b1-'0'; | |
| 25 | + g_srcpos++; | |
| 26 | + b1=g_source[g_srcpos]; | |
| 27 | + } while ('0'<= b1 && b1<='9'); | |
| 28 | + // Check if end of the statement. | |
| 29 | + if (i==0 || 65535<i) { | |
| 30 | + // Line number 0 or more than 65535 is not available | |
| 31 | + g_srcpos=prevpos; | |
| 32 | + return ERR_SYNTAX; | |
| 33 | + } else if (get_operator()) { | |
| 34 | + // Oparator not found. | |
| 35 | + g_label=i; | |
| 36 | + return 0; | |
| 37 | + } else { | |
| 38 | + // This is not constant line number. | |
| 39 | + g_srcpos=prevpos; | |
| 40 | + g_label=0; | |
| 41 | + return 0; | |
| 42 | + } | |
| 43 | + } else if ('A'<=b1 && b1<='Z') { | |
| 44 | + // May be label | |
| 45 | + do { | |
| 46 | + // First character must be A-Z | |
| 47 | + // From second, A-Z and 0-9 can be used. | |
| 48 | + i*=36; | |
| 49 | + if ('0'<=b1 && b1<='9') { | |
| 50 | + i+=b1-'0'; | |
| 51 | + } else if (g_srcpos==prevpos) { | |
| 52 | + // First character must be A-Z. | |
| 53 | + // Subtract 9, resulting 1-26 but not 10-35. | |
| 54 | + // This subtraction is required to maintain | |
| 55 | + // final number being <0x80000000. | |
| 56 | + i+=b1-'A'+1; | |
| 57 | + } else { | |
| 58 | + i+=b1-'A'+10; | |
| 59 | + } | |
| 60 | + g_srcpos++; | |
| 61 | + b1=g_source[g_srcpos]; | |
| 62 | + } while ('0'<= b1 && b1<='9' || 'A'<=b1 && b1<='Z'); | |
| 63 | + // Length of the label must be between 2 and 6. | |
| 64 | + if (g_srcpos-prevpos<2 || 6<g_srcpos-prevpos) { | |
| 65 | + g_srcpos=prevpos; | |
| 66 | + return ERR_LABEL_LONG; | |
| 67 | + } | |
| 68 | + // Must not be a function | |
| 69 | + next_position(); | |
| 70 | + if (g_source[g_srcpos]=='(') { | |
| 71 | + g_srcpos=prevpos; | |
| 72 | + g_label=0; | |
| 73 | + return 0; | |
| 74 | + } | |
| 75 | + g_label=i+65536; | |
| 76 | + return 0; | |
| 77 | + } else { | |
| 78 | + g_label=0; | |
| 79 | + return 0; | |
| 80 | + } | |
| 81 | +} | |
| 82 | + | |
| 83 | +void* search_label(unsigned int label){ | |
| 84 | + unsigned int i,code,search1,search2; | |
| 85 | + if (label&0xFFFF0000) { | |
| 86 | + // Label | |
| 87 | + search1=0x3C160000|((label>>16)&0x0000FFFF); //lui s6,yyyy; | |
| 88 | + search2=0x36D60000|(label&0x0000FFFF); //ori s6,s6,zzzz; | |
| 89 | + for(i=0;i<g_objpos;i++){ | |
| 90 | + code=g_object[i]; | |
| 91 | + if (code==search1) { | |
| 92 | + if (g_object[i+1]==search2) { | |
| 93 | + // Label number found | |
| 94 | + return &(g_object[i]); | |
| 95 | + } | |
| 96 | + } | |
| 97 | + if (code&0xFFFF0000==0x04110000) { | |
| 98 | + // "bgezal zero," assembly found. Skip following block (strig). | |
| 99 | + i+=code&0x0000FFFF; | |
| 100 | + i--; | |
| 101 | + } | |
| 102 | + } | |
| 103 | + // Line number not found. | |
| 104 | + return 0; | |
| 105 | + } else { | |
| 106 | + // Line number | |
| 107 | + search1=0x34160000|label; //ori s6,zero,xxxx; | |
| 108 | + for(i=0;i<g_objpos;i++){ | |
| 109 | + code=g_object[i]; | |
| 110 | + if (code==search1) { | |
| 111 | + // Line number found | |
| 112 | + return &(g_object[i]); | |
| 113 | + } | |
| 114 | + if (code&0xFFFF0000==0x04110000) { | |
| 115 | + // "bgezal zero," assembly found. Skip following block (strig). | |
| 116 | + i+=code&0x0000FFFF; | |
| 117 | + i--; | |
| 118 | + } | |
| 119 | + } | |
| 120 | + // Line number not found. | |
| 121 | + return 0; | |
| 122 | + } | |
| 123 | +} | |
| 124 | + | |
| 125 | +void* search_breakout(unsigned int start){ | |
| 126 | + unsigned int pos,code1,depth; | |
| 127 | + // Start search from start point where BREAK statement is used. | |
| 128 | + depth=0; | |
| 129 | + for(pos=start;pos<g_objpos;pos++){ | |
| 130 | + code1=g_object[pos]; | |
| 131 | + switch(code1>>16){ | |
| 132 | + case 0x0411: | |
| 133 | + // "bgezal zero," assembly found. Skip following block (strig). | |
| 134 | + pos+=code1&0x0000FFFF; | |
| 135 | + pos--; | |
| 136 | + break; | |
| 137 | + case 0x0820: // FOR | |
| 138 | + case 0x0821: // WHILE | |
| 139 | + case 0x0822: // DO | |
| 140 | + depth++; | |
| 141 | + break; | |
| 142 | + case 0x0830: // NEXT | |
| 143 | + case 0x0831: // WEND | |
| 144 | + case 0x0832: // LOOP | |
| 145 | + if (0<depth) { | |
| 146 | + depth--; | |
| 147 | + break; | |
| 148 | + } | |
| 149 | + // Destination found. | |
| 150 | + return (void*)&g_object[pos]; | |
| 151 | + default: | |
| 152 | + break; | |
| 153 | + } | |
| 154 | + } | |
| 155 | + return 0; | |
| 156 | +} | |
| 157 | + | |
| 158 | +void* search_ifout(unsigned int start){ | |
| 159 | + unsigned int pos,code1,depth; | |
| 160 | + // Start search from start point where BREAK statement is used. | |
| 161 | + depth=0; | |
| 162 | + for(pos=start;pos<g_objpos;pos++){ | |
| 163 | + code1=g_object[pos]; | |
| 164 | + switch(code1>>16){ | |
| 165 | + case 0x0411: | |
| 166 | + // "bgezal zero," assembly found. Skip following block (strig). | |
| 167 | + pos+=code1&0x0000FFFF; | |
| 168 | + pos--; | |
| 169 | + break; | |
| 170 | + case 0x3000: // Block marker | |
| 171 | + if (code1&0x00008000) { | |
| 172 | + // end block | |
| 173 | + if (0<depth) { | |
| 174 | + depth--; | |
| 175 | + break; | |
| 176 | + } | |
| 177 | + // Destination found. | |
| 178 | + return (void*)&g_object[pos]; | |
| 179 | + } else { | |
| 180 | + // begin block | |
| 181 | + depth++; | |
| 182 | + } | |
| 183 | + default: | |
| 184 | + break; | |
| 185 | + } | |
| 186 | + } | |
| 187 | + return 0; | |
| 188 | +} | |
| 189 | + | |
| 190 | +/* | |
| 191 | + Following codes are dedicated to specific use: | |
| 192 | + 0x0810xxxx, 0x0811xxxx: GOTO statement | |
| 193 | + 0x0812xxxx, 0x0813xxxx: GOSUB statement | |
| 194 | + 0x0814xxxx, 0x0815xxxx: SOUND etc, for setting v0 as pointer to DATA array. | |
| 195 | + 0x0816xxxx: BREAK statemant and relatives | |
| 196 | + 0x08160000: BREAK | |
| 197 | + 0x08160100: Jump to next ELSE, ELSEIF or ENDIF | |
| 198 | + 0x082xyyyy: Begin block (FOR/DO/WHILE) | |
| 199 | + 0x083xyyyy: End block (NEXT/LOOP/WEND) | |
| 200 | + 0x00000020, 0x00000021, | |
| 201 | + 0x00000022, 0x00000023: Marker for begining the DATA region. | |
| 202 | + MLB 2 bits show skip byte length in DATA. | |
| 203 | + 0x30000000: Begin block (IF-THEN-ELSEIF-ELSE-ENDIF) | |
| 204 | + 0x30008000: End block (IF-THEN-ELSEIF-ELSE-ENDIF) | |
| 205 | + | |
| 206 | + IF-THEN-ELSEIF-ELSE-ENDIF is written as follows: | |
| 207 | + IF-THEN: 0x30000000 0x10400000 0x30000000 | |
| 208 | + ELSEIF-THEN: 0x08160100 0x30008000 (conditional expression) 0x10400000 0x30000000 | |
| 209 | + ELSE: 0x08160100 0x30008000 0x30000000 | |
| 210 | + ENDIF: 0x30008000 0x30008000 | |
| 211 | + , where "0x10400000 0x30000000" and "0x08160100 0x30008000" will be replaced by | |
| 212 | + codes jumping to next 0x30008000. The 0x30000000 - 0x30008000 blocks will be skipped. | |
| 213 | +*/ | |
| 214 | + | |
| 215 | +char* link(void){ | |
| 216 | + int pos; | |
| 217 | + unsigned int code1,code2,label; | |
| 218 | + g_fileline=0; | |
| 219 | + for(pos=0;pos<g_objpos;pos++){ | |
| 220 | + code1=g_object[pos]; | |
| 221 | + switch(code1>>16){ | |
| 222 | + case 0x0411: | |
| 223 | + // "bgezal zero," assembly found. Skip following block (strig). | |
| 224 | + pos+=code1&0x0000FFFF; | |
| 225 | + pos--; | |
| 226 | + break; | |
| 227 | + case 0x3416: | |
| 228 | + // "ori s6,zero,xxxx" found this is the first word in a line. | |
| 229 | + g_fileline++; | |
| 230 | + g_line=code1&0x0000FFFF; | |
| 231 | + break; | |
| 232 | + case 0x0810: | |
| 233 | + // GOTO | |
| 234 | + code2=g_object[pos+1]; | |
| 235 | + if ((code2&0xFFFF0000)!=0x08110000) continue; | |
| 236 | + code1&=0x0000FFFF; | |
| 237 | + code2&=0x0000FFFF; | |
| 238 | + label=(code1<<16)|code2; | |
| 239 | + code1=(int)search_label(label); | |
| 240 | + g_label=label; | |
| 241 | + if (!code1) return ERR_LABEL_NF; | |
| 242 | + code1&=0x0FFFFFFF; | |
| 243 | + code1>>=2; | |
| 244 | + code1|=0x08000000; // j xxxx | |
| 245 | + g_object[pos++]=code1; | |
| 246 | + g_object[pos]=0x00000000; // nop | |
| 247 | + break; | |
| 248 | + case 0x0812: | |
| 249 | + // GOSUB | |
| 250 | + code2=g_object[pos+1]; | |
| 251 | + if ((code2&0xFFFF0000)!=0x08130000) continue; | |
| 252 | + code1&=0x0000FFFF; | |
| 253 | + code2&=0x0000FFFF; | |
| 254 | + label=(code1<<16)|code2; | |
| 255 | + code2=(int)search_label(label); | |
| 256 | + g_label=label; | |
| 257 | + if (!code2) return ERR_LABEL_NF; | |
| 258 | + code2&=0x0FFFFFFF; | |
| 259 | + code2>>=2; | |
| 260 | + code2|=0x08000000; // j xxxx | |
| 261 | + g_object[pos++]=0x00000000; // nop | |
| 262 | + g_object[pos]=code2; | |
| 263 | + break; | |
| 264 | + case 0x0814: | |
| 265 | + // SOUND etc, for setting v0 as pointer to label/line | |
| 266 | + code2=g_object[pos+1]; | |
| 267 | + if ((code2&0xFFFF0000)!=0x08150000) continue; | |
| 268 | + code1&=0x0000FFFF; | |
| 269 | + code2&=0x0000FFFF; | |
| 270 | + label=(code1<<16)|code2; | |
| 271 | + code1=(int)search_label(label); | |
| 272 | + g_label=label; | |
| 273 | + if (!code1) return ERR_LABEL_NF; | |
| 274 | + g_object[pos++]=0x3C020000|((code1>>16)&0x0000FFFF); // lui v0,xxxx | |
| 275 | + g_object[pos] =0x34420000|(code1&0x0000FFFF); // ori v0,v0,xxxx | |
| 276 | + break; | |
| 277 | + case 0x0816: | |
| 278 | + switch(code1&0xFFFF) { | |
| 279 | + case 0x0000: | |
| 280 | + // BREAK statement | |
| 281 | + // Find next the NEXT or WHILE statement and insert jump code after this. | |
| 282 | + g_label=g_line; | |
| 283 | + code1=(int)search_breakout(pos); | |
| 284 | + if (!code1) return ERR_INVALID_BREAK; | |
| 285 | + code1&=0x0FFFFFFF; | |
| 286 | + code1>>=2; | |
| 287 | + code1|=0x08000000; // j xxxx | |
| 288 | + g_object[pos]=code1; | |
| 289 | + break; | |
| 290 | + case 0x0100: | |
| 291 | + // Jump to next ENDIF | |
| 292 | + g_label=g_line; | |
| 293 | + // "pos+2" is for skipping next code (must be 0x30008000) | |
| 294 | + code1=(int)search_ifout(pos+2); | |
| 295 | + if (!code1) return ERR_INVALID_ELSEIF; | |
| 296 | + code1&=0x0FFFFFFF; | |
| 297 | + code1>>=2; | |
| 298 | + code1|=0x08000000; // j xxxx | |
| 299 | + g_object[pos]=code1; | |
| 300 | + break; | |
| 301 | + default: | |
| 302 | + break; | |
| 303 | + } | |
| 304 | + break; | |
| 305 | + case 0x3000: | |
| 306 | + // Block marker | |
| 307 | + switch(code1&0xFFFF) { | |
| 308 | + case 0x0000: | |
| 309 | + // Begin if block | |
| 310 | + if (g_object[pos-1]==0x10400000) { // beq v0,zero,xxxx | |
| 311 | + // IF-THEN or ELSEIF-THEN | |
| 312 | + // Jump to next ELSE, ELSEIF or ENDIF | |
| 313 | + g_label=g_line; | |
| 314 | + // "pos+1" is for skipping current code (0x30000000) | |
| 315 | + code1=(int)search_ifout(pos+1); | |
| 316 | + if (!code1) return ERR_INVALID_ELSEIF; | |
| 317 | + code1-=(int)(&g_object[pos]); | |
| 318 | + code1>>=2; | |
| 319 | + code1&=0x0000FFFF; | |
| 320 | + code1|=0x10400000; // beq v0,zero,xxxx | |
| 321 | + g_object[pos-1]=code1; | |
| 322 | + break; | |
| 323 | + } | |
| 324 | + break; | |
| 325 | + default: | |
| 326 | + break; | |
| 327 | + } | |
| 328 | + break; | |
| 329 | + case 0x0820: // FOR | |
| 330 | + case 0x0830: // NEXT | |
| 331 | + case 0x0821: // WHILE | |
| 332 | + case 0x0831: // WEND | |
| 333 | + case 0x0822: // DO | |
| 334 | + case 0x0832: // WHILE | |
| 335 | + // These are used for detecing the depth of structures. | |
| 336 | + // Change them to stack increase/decrease commands. | |
| 337 | + g_object[pos]=0x27BD0000|(code1&0x0000FFFF); //// addiu sp,sp,xx | |
| 338 | + break; | |
| 339 | + case 0x2407: // addiu a3,zero,xxxx | |
| 340 | + if (g_object[pos-1]!=0x02E0F809) break; // jalr ra,s7 | |
| 341 | + // call_lib_code(x) | |
| 342 | + switch(code1&0x0000FFFF){ | |
| 343 | + case LIB_RESTORE: | |
| 344 | + // Convert label data to pointer if not dynamic | |
| 345 | + code1=g_object[pos-3]; | |
| 346 | + code2=g_object[pos-2]; | |
| 347 | + if ((code1>>16)!=0x3C02) break; // lui v0,xxxx | |
| 348 | + if ((code2>>16)!=0x3442) break; // ori v0,v0,xxxx | |
| 349 | + label=(code1<<16)|(code2&0x0000FFFF); | |
| 350 | + code1=(int)search_label(label); | |
| 351 | + g_label=label; | |
| 352 | + if (!code1) return ERR_LABEL_NF; | |
| 353 | + code2=code1&0x0000FFFF; | |
| 354 | + code1=code1>>16; | |
| 355 | + g_object[pos-3]=0x3C020000|code1; // lui v0,xxxx | |
| 356 | + g_object[pos-2]=0x34420000|code2; // ori v0,v0,xxxx | |
| 357 | + g_object[pos]=0x24070000|LIB_RESTORE2; // addiu a3,zero,xxxx | |
| 358 | + break; | |
| 359 | + default: | |
| 360 | + break; | |
| 361 | + } | |
| 362 | + break; | |
| 363 | + default: | |
| 364 | + break; | |
| 365 | + } | |
| 366 | + } | |
| 367 | + return 0; | |
| 368 | +} | |
| \ No newline at end of file |
| @@ -0,0 +1,150 @@ | ||
| 1 | +#include "./compiler.h" | |
| 2 | +#include "stdlib.h" | |
| 3 | + | |
| 4 | +char* get_float_sub(int pr); | |
| 5 | + | |
| 6 | +char* get_simple_float(void){ | |
| 7 | + int i; | |
| 8 | + float f; | |
| 9 | + char* err; | |
| 10 | + char b1,b2,b3; | |
| 11 | + next_position(); | |
| 12 | + b1=g_source[g_srcpos]; | |
| 13 | + if (b1=='(') { | |
| 14 | + // (...) | |
| 15 | + // Parenthesis | |
| 16 | + g_srcpos++; | |
| 17 | + next_position(); | |
| 18 | + err=get_float_sub(priority(OP_VOID)); | |
| 19 | + if (err) return err; | |
| 20 | + next_position(); | |
| 21 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
| 22 | + g_srcpos++; | |
| 23 | + } else if (b1=='-') { | |
| 24 | + // Unary '-' operator | |
| 25 | + // Note that unary operators ( + and - ) have higher priority than the other operators | |
| 26 | + g_srcpos++; | |
| 27 | + err=get_simple_float(); | |
| 28 | + if (err) return err; | |
| 29 | + check_obj_space(2); | |
| 30 | + g_object[g_objpos++]=0x3404; // ori a0,zero,0x123 | |
| 31 | + g_object[g_objpos++]=0x34050000|(OP_SUB&0x0000FFFF); // ori a1,zero,xxxx | |
| 32 | + call_lib_code(LIB_FLOAT); | |
| 33 | + } else { | |
| 34 | + // Main routine of getting float value here | |
| 35 | + if (b1=='+') g_srcpos++; // Ignore unary '+' operator | |
| 36 | + next_position(); | |
| 37 | + b1=g_source[g_srcpos]; | |
| 38 | + b2=g_source[g_srcpos+1]; | |
| 39 | + b3=g_source[g_srcpos+2]; | |
| 40 | + if ('0'<=b1 && b1<='9') { | |
| 41 | + f=strtof((const char*)&g_source[g_srcpos],&err); | |
| 42 | + if (&g_source[g_srcpos]==err) return ERR_SYNTAX; | |
| 43 | + g_srcpos=err-g_source; | |
| 44 | + i=((int*)(&f))[0]; | |
| 45 | + if (i&0xFFFF0000) { | |
| 46 | + // 32 bit | |
| 47 | + check_obj_space(2); | |
| 48 | + g_object[g_objpos++]=0x3C020000|((i>>16)&0x0000FFFF); // lui v0,xxxx | |
| 49 | + g_object[g_objpos++]=0x34420000|(i&0x0000FFFF); // ori v0,v0,xxxx | |
| 50 | + } else { | |
| 51 | + // 16 bit | |
| 52 | + check_obj_space(1); | |
| 53 | + g_object[g_objpos++]=0x34020000|(i&0x0000FFFF); // ori v0,zero,xxxx | |
| 54 | + } | |
| 55 | + } else { | |
| 56 | + if ('A'<=b1 && b1<='Z' && b2=='#' && b3=='(') { | |
| 57 | + // A( - Z( | |
| 58 | + // Dimension | |
| 59 | + g_srcpos++; | |
| 60 | + g_srcpos++; | |
| 61 | + g_srcpos++; | |
| 62 | + return get_dim_value(b1); | |
| 63 | + } else if ('A'<=b1 && b1<='Z' && b2=='#') { | |
| 64 | + // A-Z | |
| 65 | + // Simple value | |
| 66 | + g_srcpos++; | |
| 67 | + g_srcpos++; | |
| 68 | + check_obj_space(1); | |
| 69 | + g_object[g_objpos++]=0x8FC20000|((b1-'A')*4); // lw v0,xx(s8) | |
| 70 | + } else if ('A'<=b1 && b1<='Z') { | |
| 71 | + // Starts with A-Z | |
| 72 | + // Functions | |
| 73 | + return float_function(); | |
| 74 | + } else { | |
| 75 | + return ERR_SYNTAX; | |
| 76 | + } | |
| 77 | + } | |
| 78 | + } | |
| 79 | + // No error | |
| 80 | + return 0; | |
| 81 | +} | |
| 82 | + | |
| 83 | +char* get_float_sub(int pr){ | |
| 84 | + char* err; | |
| 85 | + enum operator op; | |
| 86 | + char b1,b2,b3; | |
| 87 | + int prevpos; | |
| 88 | + // Get a value in $v0. | |
| 89 | + err=get_simple_float(); | |
| 90 | + if (err) return err; | |
| 91 | + while(1){ | |
| 92 | + // Get the operator in op. If not valid operator, simply return without error. | |
| 93 | + prevpos=g_srcpos; | |
| 94 | + err=get_floatOperator(); | |
| 95 | + if (err) return 0; | |
| 96 | + op=g_last_op; | |
| 97 | + // Compair current and previous operators. | |
| 98 | + // If the previous operator has higher priolity, return. | |
| 99 | + if (pr>=priority(op)) { | |
| 100 | + g_srcpos=prevpos; | |
| 101 | + return 0; | |
| 102 | + } | |
| 103 | + // Store $v0 in stack | |
| 104 | + g_sdepth+=4; | |
| 105 | + if (g_maxsdepth<g_sdepth) g_maxsdepth=g_sdepth; | |
| 106 | + check_obj_space(1); | |
| 107 | + g_object[g_objpos++]=0xAFA20000|g_sdepth; // sw v0,xx(sp) | |
| 108 | + // Get next value. | |
| 109 | + err=get_float_sub(priority(op)); | |
| 110 | + if (err) return err; | |
| 111 | + // Get value from stack to $a0. | |
| 112 | + check_obj_space(1); | |
| 113 | + g_object[g_objpos++]=0x8FA40000|g_sdepth; // lw a0,xx(sp) | |
| 114 | + g_sdepth-=4; | |
| 115 | + // Calculation. Result will be in $v0. | |
| 116 | + err=calculation_float(op); | |
| 117 | + if (err) return err; | |
| 118 | + } | |
| 119 | +} | |
| 120 | + | |
| 121 | +char* get_float(){ | |
| 122 | + // Note that this can be called recursively. | |
| 123 | + // Value may contain function with a parameter of another value. | |
| 124 | + char* err; | |
| 125 | + int prevpos; | |
| 126 | + if (g_sdepth==0) { | |
| 127 | + // Initialize stack handler | |
| 128 | + g_maxsdepth=0; | |
| 129 | + prevpos=g_objpos; | |
| 130 | + // Stack decrement command will be filled later | |
| 131 | + check_obj_space(1); | |
| 132 | + g_objpos++; | |
| 133 | + } | |
| 134 | + err=get_float_sub(priority(OP_VOID)); | |
| 135 | + if (err) return err; | |
| 136 | + if (g_sdepth==0) { | |
| 137 | + if (g_maxsdepth==0) { | |
| 138 | + // Stack was not used. | |
| 139 | + shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1); | |
| 140 | + g_objpos--; | |
| 141 | + } else { | |
| 142 | + // Stack was used. | |
| 143 | + check_obj_space(1); | |
| 144 | + g_object[prevpos]=0x27BD0000 | (0-g_maxsdepth) & 0x0000FFFF; // addiu sp,sp,-xx | |
| 145 | + g_object[g_objpos++]=0x27BD0000 | g_maxsdepth & 0x0000FFFF; // addiu sp,sp,xx | |
| 146 | + } | |
| 147 | + } | |
| 148 | + g_lastvar=VAR_FLOAT; | |
| 149 | + return 0; | |
| 150 | +} | |
| \ No newline at end of file |
| @@ -0,0 +1,108 @@ | ||
| 1 | +#define WIDTH_X 30 // 横方向文字数 | |
| 2 | +#define WIDTH_Y 27 // 縦方向文字数 | |
| 3 | +#define ATTROFFSET (WIDTH_X*WIDTH_Y) // VRAM上のカラーパレット格納位置 | |
| 4 | + | |
| 5 | +#define G_X_RES 256 // 横方向解像度 | |
| 6 | +#define G_Y_RES 224 // 縦方向解像度 | |
| 7 | +#define G_H_WORD (G_X_RES/4) // 1行当りのワード数(16bit単位) | |
| 8 | + | |
| 9 | + | |
| 10 | +// 入力ボタンのポート、ビット定義 | |
| 11 | +#define KEYPORT PORTB | |
| 12 | +#define KEYUP 0x0400 | |
| 13 | +#define KEYDOWN 0x0080 | |
| 14 | +#define KEYLEFT 0x0100 | |
| 15 | +#define KEYRIGHT 0x0200 | |
| 16 | +#define KEYSTART 0x0800 | |
| 17 | +#define KEYFIRE 0x4000 | |
| 18 | + | |
| 19 | +extern volatile char drawing; // 表示期間中は-1 | |
| 20 | +extern volatile unsigned short drawcount; // 1画面表示終了ごとに1足す。アプリ側で0にする。 | |
| 21 | + // 最低1回は画面表示したことのチェックと、アプリの処理が何画面期間必要かの確認に利用。 | |
| 22 | +extern unsigned char TVRAM[]; //テキストビデオメモリ | |
| 23 | +extern unsigned short *gVRAM; //グラフィックVRAM開始位置のポインタ | |
| 24 | + | |
| 25 | +extern const unsigned char FontData[]; //フォントパターン定義 | |
| 26 | +extern unsigned char *cursor; | |
| 27 | +extern unsigned char cursorcolor; | |
| 28 | +extern unsigned char *fontp; | |
| 29 | + | |
| 30 | +void start_composite(void); //カラーコンポジット出力開始 | |
| 31 | +void stop_composite(void); //カラーコンポジット出力停止 | |
| 32 | +void init_composite(void); //カラーコンポジット出力初期化 | |
| 33 | +void clearscreen(void); //テキスト画面クリア | |
| 34 | +void set_palette(unsigned char n,unsigned char b,unsigned char r,unsigned char g); //テキストパレット設定 | |
| 35 | +void set_bgcolor(unsigned char b,unsigned char r,unsigned char g); //バックグランドカラー設定 | |
| 36 | +void set_graphmode(unsigned char m); //グラフィックモード変更 | |
| 37 | +void init_graphic(unsigned short *gvram); //グラフィック機能利用準備 | |
| 38 | + | |
| 39 | +void vramscroll(void); | |
| 40 | + //1行スクロール | |
| 41 | +void setcursor(unsigned char x,unsigned char y,unsigned char c); | |
| 42 | + //カーソル位置とカラーを設定 | |
| 43 | +void setcursorcolor(unsigned char c); | |
| 44 | + //カーソル位置そのままでカラー番号をcに設定 | |
| 45 | +void printchar(unsigned char n); | |
| 46 | + //カーソル位置にテキストコードnを1文字表示し、カーソルを1文字進める | |
| 47 | +void printstr(unsigned char *s); | |
| 48 | + //カーソル位置に文字列sを表示 | |
| 49 | +void printnum(unsigned int n); | |
| 50 | + //カーソル位置に符号なし整数nを10進数表示 | |
| 51 | +void printnum2(unsigned int n,unsigned char e); | |
| 52 | + //カーソル位置に符号なし整数nをe桁の10進数表示(前の空き桁部分はスペースで埋める) | |
| 53 | +void cls(void); | |
| 54 | + //テキスト画面消去し、カーソルを先頭に移動 | |
| 55 | +void startPCG(unsigned char *p,int a); | |
| 56 | + // RAMフォント(PCG)の利用開始、pがフォント格納場所、aが0以外でシステムフォントをコピー | |
| 57 | +void stopPCG(void); | |
| 58 | + // RAMフォント(PCG)の利用停止 | |
| 59 | + | |
| 60 | +void g_clearscreen(void); | |
| 61 | +//グラフィック画面クリア | |
| 62 | +void g_set_palette(unsigned char n,unsigned char b,unsigned char r,unsigned char g); | |
| 63 | +//グラフィック用カラーパレット設定 | |
| 64 | + | |
| 65 | +void g_pset(int x,int y,unsigned int c); | |
| 66 | +// (x,y)の位置にカラーcで点を描画 | |
| 67 | + | |
| 68 | +void g_putbmpmn(int x,int y,char m,char n,const unsigned char bmp[]); | |
| 69 | +// 横m*縦nドットのキャラクターを座標x,yに表示 | |
| 70 | +// unsigned char bmp[m*n]配列に、単純にカラー番号を並べる | |
| 71 | +// カラー番号が0の部分は透明色として扱う | |
| 72 | + | |
| 73 | +void g_clrbmpmn(int x,int y,char m,char n); | |
| 74 | +// 縦m*横nドットのキャラクター消去 | |
| 75 | +// カラー0で塗りつぶし | |
| 76 | + | |
| 77 | +void g_gline(int x1,int y1,int x2,int y2,unsigned int c); | |
| 78 | +// (x1,y1)-(x2,y2)にカラーcで線分を描画 | |
| 79 | + | |
| 80 | +void g_hline(int x1,int x2,int y,unsigned int c); | |
| 81 | +// (x1,y)-(x2,y)への水平ラインを高速描画 | |
| 82 | + | |
| 83 | +void g_circle(int x0,int y0,unsigned int r,unsigned int c); | |
| 84 | +// (x0,y0)を中心に、半径r、カラーcの円を描画 | |
| 85 | + | |
| 86 | +void g_boxfill(int x1,int y1,int x2,int y2,unsigned int c); | |
| 87 | +// (x1,y1),(x2,y2)を対角線とするカラーcで塗られた長方形を描画 | |
| 88 | + | |
| 89 | +void g_circlefill(int x0,int y0,unsigned int r,unsigned int c); | |
| 90 | +// (x0,y0)を中心に、半径r、カラーcで塗られた円を描画 | |
| 91 | + | |
| 92 | +void g_putfont(int x,int y,unsigned int c,int bc,unsigned char n); | |
| 93 | +//8*8ドットのアルファベットフォント表示 | |
| 94 | +//座標(x,y)、カラー番号c | |
| 95 | +//bc:バックグランドカラー、負数の場合無視 | |
| 96 | +//n:文字番号 | |
| 97 | + | |
| 98 | +void g_printstr(int x,int y,unsigned int c,int bc,unsigned char *s); | |
| 99 | +//座標(x,y)からカラー番号cで文字列sを表示、bc:バックグランドカラー | |
| 100 | + | |
| 101 | +void g_printnum(int x,int y,unsigned char c,int bc,unsigned int n); | |
| 102 | +//座標(x,y)にカラー番号cで数値nを表示、bc:バックグランドカラー | |
| 103 | + | |
| 104 | +void g_printnum2(int x,int y,unsigned char c,int bc,unsigned int n,unsigned char e); | |
| 105 | +//座標(x,y)にカラー番号cで数値nを表示、bc:バックグランドカラー、e桁で表示 | |
| 106 | + | |
| 107 | +unsigned int g_color(int x,int y); | |
| 108 | +//座標(x,y)のVRAM上の現在のパレット番号を返す、画面外は0を返す |
| @@ -0,0 +1,143 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include "compiler.h" | |
| 9 | + | |
| 10 | +const char* g_err_str[]={ | |
| 11 | + "Syntax error", | |
| 12 | + "Not enough binary space", | |
| 13 | + "Not enough memory", | |
| 14 | + "Divided by zero", | |
| 15 | + "Not yet implemented", | |
| 16 | + "Label or line number not found: ", | |
| 17 | + "Label too long or too short", | |
| 18 | + "String too complexed", | |
| 19 | + "Data not found", | |
| 20 | + "Unknown error", | |
| 21 | + "Music syntax error:'", | |
| 22 | + " found more than twice", | |
| 23 | + "Break", | |
| 24 | + "Unexpected NEXT or RETURN statement", | |
| 25 | + "Cannot assign temporary block", | |
| 26 | + "GOSUB fuction cannot be used after string-handling", | |
| 27 | + "Invalid BREAK statement in line ", | |
| 28 | + "Invalid ELSE/IF statement in line ", | |
| 29 | +}; | |
| 30 | + | |
| 31 | +char* resolve_label(int s6){ | |
| 32 | + static char str[7]; | |
| 33 | + int i,j; | |
| 34 | + if (s6<65536) { | |
| 35 | + // Line number | |
| 36 | + for(i=0;i<5;i++){ | |
| 37 | + str[5-i]='0'+rem10_32(s6); | |
| 38 | + s6=div10_32(s6); | |
| 39 | + } | |
| 40 | + str[6]=0x00; | |
| 41 | + for(j=1;j<5;j++){ | |
| 42 | + if (str[j]!='0') break; | |
| 43 | + } | |
| 44 | + return (char*)(str+j); | |
| 45 | + } else { | |
| 46 | + // Label | |
| 47 | + s6-=65536; | |
| 48 | + str[6]=0x00; | |
| 49 | + for(i=5;0<=i;i--){ | |
| 50 | + if (s6<36) { | |
| 51 | + // First character must be A-Z, corresponding to 1-26 but not 10-35. | |
| 52 | + // See get_label() for the detail. | |
| 53 | + str[i]=s6-1+'A'; | |
| 54 | + break; | |
| 55 | + } else { | |
| 56 | + // From second, 0-9 corresponds to 0-9 and A-Z corresponds to 10-35. | |
| 57 | + str[i]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[rem36_32(s6)]; | |
| 58 | + s6=div36_32(s6); | |
| 59 | + } | |
| 60 | + } | |
| 61 | + return (char*)(str+i); | |
| 62 | + } | |
| 63 | +} | |
| 64 | + | |
| 65 | +void pre_end_addr(int s6){ | |
| 66 | + int i,j; | |
| 67 | + char str[7]; | |
| 68 | + if (s6<0) s6=s6&0x7fffffff; | |
| 69 | + g_label=s6; | |
| 70 | + if (s6<65536) { | |
| 71 | + // Line number | |
| 72 | + printstr("\nIn line "); | |
| 73 | + } else { | |
| 74 | + // Label | |
| 75 | + printstr("\nAfter label "); | |
| 76 | + } | |
| 77 | + printstr(resolve_label(s6)); | |
| 78 | + asm volatile("la $v0,%0"::"i"(&g_end_addr)); | |
| 79 | + asm volatile("lw $v0,0($v0)"); | |
| 80 | + asm volatile("nop"); | |
| 81 | + asm volatile("jr $v0"); | |
| 82 | +} | |
| 83 | + | |
| 84 | +#define end_exec() \ | |
| 85 | + asm volatile("addu $a0,$s6,$zero");\ | |
| 86 | + asm volatile("j pre_end_addr") | |
| 87 | + | |
| 88 | +void err_break(void){ | |
| 89 | + printstr(ERR_BREAK); | |
| 90 | + end_exec(); | |
| 91 | +} | |
| 92 | + | |
| 93 | +void err_data_not_found(void){ | |
| 94 | + printstr(ERR_DATA_NF); | |
| 95 | + end_exec(); | |
| 96 | +} | |
| 97 | + | |
| 98 | +void err_label_not_found(void){ | |
| 99 | + printstr(ERR_LABEL_NF); | |
| 100 | + printstr(resolve_label(g_label)); | |
| 101 | + printstr("\n"); | |
| 102 | + end_exec(); | |
| 103 | +} | |
| 104 | + | |
| 105 | +void err_div_zero(void){ | |
| 106 | + printstr(ERR_DIV_0); | |
| 107 | + end_exec(); | |
| 108 | +} | |
| 109 | + | |
| 110 | +void err_no_mem(void){ | |
| 111 | + printstr(ERR_NE_MEMORY); | |
| 112 | + end_exec(); | |
| 113 | +} | |
| 114 | + | |
| 115 | +void err_str_complex(void){ | |
| 116 | + printstr(ERR_STR_COMPLEX); | |
| 117 | + end_exec(); | |
| 118 | +} | |
| 119 | + | |
| 120 | +void err_unknown(void){ | |
| 121 | + printstr(ERR_UNKNOWN); | |
| 122 | + end_exec(); | |
| 123 | +} | |
| 124 | + | |
| 125 | +void err_music(char* str){ | |
| 126 | + printstr(ERR_MUSIC); | |
| 127 | + printstr(str); | |
| 128 | + printstr("'\n"); | |
| 129 | + // Restore s6 from g_s6 | |
| 130 | + asm volatile("la $s6,%0"::"i"(&g_s6)); | |
| 131 | + asm volatile("lw $s6,0($s6)"); | |
| 132 | + end_exec(); | |
| 133 | +} | |
| 134 | + | |
| 135 | +void err_unexp_next(void){ | |
| 136 | + printstr(ERR_UNEXP_NEXT); | |
| 137 | + end_exec(); | |
| 138 | +} | |
| 139 | + | |
| 140 | +void err_no_block(void){ | |
| 141 | + printstr(ERR_NO_BLOCK); | |
| 142 | + end_exec(); | |
| 143 | +} |
| @@ -0,0 +1,71 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by K.Tanaka & Katsumi | |
| 4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
| 5 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include "compiler.h" | |
| 9 | +#include "main.h" | |
| 10 | + | |
| 11 | +// Contain the valus of $gp and $s6 (GPR of MIPS32) | |
| 12 | +int g_gp; | |
| 13 | +int g_s6; | |
| 14 | + | |
| 15 | +// Line data when compiling | |
| 16 | +int g_line; | |
| 17 | +int g_fileline; | |
| 18 | + | |
| 19 | +// Contain the address to which return in "END" statement. | |
| 20 | +int g_end_addr; | |
| 21 | + | |
| 22 | +// Following vars are used in value.c and string.c. | |
| 23 | +// These define the depth of stack pointer used for | |
| 24 | +// handling values and strings. | |
| 25 | +int g_sdepth; | |
| 26 | +int g_maxsdepth; | |
| 27 | + | |
| 28 | +// Following var shows what type of variable was defined | |
| 29 | +// in compiling the last code. | |
| 30 | +enum variable g_lastvar; | |
| 31 | + | |
| 32 | +// Vars used for handling constant integer | |
| 33 | +int g_intconst; | |
| 34 | +char g_valueisconst; | |
| 35 | + | |
| 36 | +// Global vars associated to RAM | |
| 37 | +char* g_source; | |
| 38 | +int g_srcpos; | |
| 39 | +int* g_object; | |
| 40 | +int g_objpos; | |
| 41 | +int* g_objmax; | |
| 42 | +char RAM[RAMSIZE] __attribute__((persistent,address(0xA0000000+PIC32MX_RAMSIZE-PERSISTENT_RAM_SIZE))); | |
| 43 | +unsigned int g_ex_data[EXCEPTION_DATA_SIZE/4] __attribute__((persistent,address(0xA0000000+PIC32MX_RAMSIZE-EXCEPTION_DATA_SIZE))); | |
| 44 | + | |
| 45 | +// Global area for vars A-Z and three temporary string pointers | |
| 46 | +int g_var_mem[ALLOC_BLOCK_NUM]; | |
| 47 | +unsigned short g_var_pointer[ALLOC_BLOCK_NUM]; | |
| 48 | +unsigned short g_var_size[ALLOC_BLOCK_NUM]; | |
| 49 | + | |
| 50 | +// Flag to use temporary area when compiling | |
| 51 | +char g_temp_area_used; | |
| 52 | + | |
| 53 | +// Heap area | |
| 54 | +int* g_heap_mem; | |
| 55 | +int g_max_mem; | |
| 56 | + | |
| 57 | +// Random seed | |
| 58 | +int g_rnd_seed; | |
| 59 | + | |
| 60 | +// Enable/disable Break keys | |
| 61 | +char g_disable_break; | |
| 62 | + | |
| 63 | +// Font data used for PCG | |
| 64 | +unsigned char* g_pcg_font; | |
| 65 | + | |
| 66 | +// Use or do not use graphic | |
| 67 | +char g_use_graphic; | |
| 68 | + | |
| 69 | +// Pointer to graphic RAM | |
| 70 | +unsigned short* g_graphic_area; | |
| 71 | + |
| @@ -0,0 +1,271 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +/* | |
| 9 | + Public function is only get_value(). | |
| 10 | +*/ | |
| 11 | + | |
| 12 | +#include "compiler.h" | |
| 13 | + | |
| 14 | +char* get_value(); | |
| 15 | +char* get_value_sub(int pr); | |
| 16 | + | |
| 17 | +char* get_dim_value(char b1){ | |
| 18 | + char* err; | |
| 19 | + err=get_value_sub(priority(OP_VOID)); | |
| 20 | + if (err) return err; | |
| 21 | + check_obj_space(4); | |
| 22 | + g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
| 23 | + g_object[g_objpos++]=0x8FC30000|((b1-'A')*4); // lw v1,xx(s8) | |
| 24 | + g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
| 25 | + g_object[g_objpos++]=0x8C620000; // lw v0,0(v1) | |
| 26 | + next_position(); | |
| 27 | + if (g_source[g_srcpos]==','){ | |
| 28 | + // 2D, 3D or more | |
| 29 | + check_obj_space(2); | |
| 30 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
| 31 | + do { | |
| 32 | + g_srcpos++; | |
| 33 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
| 34 | + err=get_value_sub(priority(OP_VOID)); | |
| 35 | + if (err) return err; | |
| 36 | + check_obj_space(5); | |
| 37 | + g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
| 38 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
| 39 | + g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
| 40 | + g_object[g_objpos++]=0x8C620000; // lw v0,0(v1) | |
| 41 | + } while (g_source[g_srcpos]==','); | |
| 42 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
| 43 | + } | |
| 44 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
| 45 | + g_srcpos++; | |
| 46 | + return 0; | |
| 47 | +} | |
| 48 | + | |
| 49 | +char* get_simple_value(void){ | |
| 50 | + int i; | |
| 51 | + char* err; | |
| 52 | + char b1,b2; | |
| 53 | + next_position(); | |
| 54 | + b1=g_source[g_srcpos]; | |
| 55 | + if (b1=='(') { | |
| 56 | + // (...) | |
| 57 | + // Parenthesis | |
| 58 | + g_srcpos++; | |
| 59 | + next_position(); | |
| 60 | + err=get_value_sub(priority(OP_VOID)); | |
| 61 | + if (err) return err; | |
| 62 | + next_position(); | |
| 63 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
| 64 | + g_srcpos++; | |
| 65 | + } else if (b1=='-') { | |
| 66 | + // Unary '-' operator | |
| 67 | + // Note that unary operators ( + and - ) have higher priority than the other operators | |
| 68 | + g_srcpos++; | |
| 69 | + err=get_simple_value(); | |
| 70 | + if (err) return err; | |
| 71 | + check_obj_space(1); | |
| 72 | + g_object[g_objpos++]=0x00021023; // subu v0,zero,v0 | |
| 73 | + g_intconst=-g_intconst; | |
| 74 | + } else { | |
| 75 | + // Main routine of getting value here | |
| 76 | + if (b1=='+') g_srcpos++; // Ignore unary '+' operator | |
| 77 | + next_position(); | |
| 78 | + b1=g_source[g_srcpos]; | |
| 79 | + b2=g_source[g_srcpos+1]; | |
| 80 | + if (b1=='0' && b2=='X' || b1=='$') { | |
| 81 | + // Starts with '0x' or '$' | |
| 82 | + // Hex number | |
| 83 | + g_srcpos++; | |
| 84 | + if (b1=='0') g_srcpos++; | |
| 85 | + i=0; | |
| 86 | + while(b1=g_source[g_srcpos]) { | |
| 87 | + if ('0'<=b1 && b1<='9') { | |
| 88 | + i*=16; | |
| 89 | + i+=b1-'0'; | |
| 90 | + } else if ('A'<=b1 && b1<='F') { | |
| 91 | + i*=16; | |
| 92 | + i+=b1-'A'+0x0A; | |
| 93 | + } else { | |
| 94 | + break; | |
| 95 | + } | |
| 96 | + g_srcpos++; | |
| 97 | + } | |
| 98 | + g_intconst=i; | |
| 99 | + if (i&0xFFFF0000) { | |
| 100 | + // 32 bit | |
| 101 | + check_obj_space(2); | |
| 102 | + g_object[g_objpos++]=0x3C020000|((i>>16)&0x0000FFFF); // lui v0,xxxx | |
| 103 | + g_object[g_objpos++]=0x34420000|(i&0x0000FFFF); // ori v0,v0,xxxx | |
| 104 | + } else { | |
| 105 | + // 16 bit | |
| 106 | + check_obj_space(1); | |
| 107 | + g_object[g_objpos++]=0x34020000|(i&0x0000FFFF); // ori v0,zero,xxxx | |
| 108 | + } | |
| 109 | + } else if ('0'<=b1 && b1<='9') { | |
| 110 | + // Starts with 0-9 | |
| 111 | + // Decimal number | |
| 112 | + i=0; | |
| 113 | + while(b1=g_source[g_srcpos]) { | |
| 114 | + if ('0'<=b1 && b1<='9') { | |
| 115 | + i*=10; | |
| 116 | + i+=b1-'0'; | |
| 117 | + } else { | |
| 118 | + break; | |
| 119 | + } | |
| 120 | + g_srcpos++; | |
| 121 | + } | |
| 122 | + // The next character should not be '.' or 'E'. | |
| 123 | + // Or, it must be recognized as a float value. | |
| 124 | + if (b1=='.' || b1=='E') return ERR_SYNTAX; | |
| 125 | + g_intconst=i; | |
| 126 | + if (i&0xFFFF0000) { | |
| 127 | + // 32 bit | |
| 128 | + check_obj_space(2); | |
| 129 | + g_object[g_objpos++]=0x3C020000|((i>>16)&0x0000FFFF); // lui v0,xxxx | |
| 130 | + g_object[g_objpos++]=0x34420000|(i&0x0000FFFF); // ori v0,v0,xxxx | |
| 131 | + } else { | |
| 132 | + // 16 bit | |
| 133 | + check_obj_space(1); | |
| 134 | + g_object[g_objpos++]=0x34020000|(i&0x0000FFFF); // ori v0,zero,xxxx | |
| 135 | + } | |
| 136 | + } else { | |
| 137 | + g_valueisconst=0; | |
| 138 | + if ('A'<=b1 && b1<='Z' && b2=='(') { | |
| 139 | + // A( - Z( | |
| 140 | + // Dimension | |
| 141 | + g_srcpos++; | |
| 142 | + g_srcpos++; | |
| 143 | + return get_dim_value(b1); | |
| 144 | + } else if ('A'<=b1 && b1<='Z' && (b2<'A' || 'Z'<b2) && b2!='#' && b2!='$') { | |
| 145 | + // A-Z | |
| 146 | + // Simple value | |
| 147 | + g_srcpos++; | |
| 148 | + check_obj_space(1); | |
| 149 | + g_object[g_objpos++]=0x8FC20000|((b1-'A')*4); // lw v0,xx(s8) | |
| 150 | + } else if ('A'<=b1 && b1<='Z') { | |
| 151 | + // Starts with A-Z | |
| 152 | + // Functions | |
| 153 | + return function(); | |
| 154 | + } else { | |
| 155 | + return ERR_SYNTAX; | |
| 156 | + } | |
| 157 | + } | |
| 158 | + } | |
| 159 | + // No error | |
| 160 | + return 0; | |
| 161 | +} | |
| 162 | + | |
| 163 | +char* get_value_sub(int pr){ | |
| 164 | + char* err; | |
| 165 | + enum operator op; | |
| 166 | + char b1,b2,b3; | |
| 167 | + int prevpos; | |
| 168 | + // Get a value in $v0. | |
| 169 | + err=get_simple_value(); | |
| 170 | + if (err) return err; | |
| 171 | + while(1){ | |
| 172 | + // Get the operator in op. If not valid operator, simply return without error. | |
| 173 | + prevpos=g_srcpos; | |
| 174 | + err=get_operator(); | |
| 175 | + if (err) return 0; | |
| 176 | + op=g_last_op; | |
| 177 | + // Compair current and previous operators. | |
| 178 | + // If the previous operator has higher priolity, return. | |
| 179 | + if (pr>=priority(op)) { | |
| 180 | + g_srcpos=prevpos; | |
| 181 | + return 0; | |
| 182 | + } | |
| 183 | + // Store $v0 in stack | |
| 184 | + g_sdepth+=4; | |
| 185 | + if (g_maxsdepth<g_sdepth) g_maxsdepth=g_sdepth; | |
| 186 | + check_obj_space(1); | |
| 187 | + g_object[g_objpos++]=0xAFA20000|g_sdepth; // sw v0,xx(sp) | |
| 188 | + // Get next value. | |
| 189 | + err=get_value_sub(priority(op)); | |
| 190 | + if (err) return err; | |
| 191 | + // Get value from stack to $v1. | |
| 192 | + check_obj_space(1); | |
| 193 | + g_object[g_objpos++]=0x8FA30000|g_sdepth; // lw v1,xx(sp) | |
| 194 | + g_sdepth-=4; | |
| 195 | + // Calculation. Result will be in $v0. | |
| 196 | + err=calculation(op); | |
| 197 | + if (err) return err; | |
| 198 | + } | |
| 199 | +} | |
| 200 | + | |
| 201 | +char* get_value(){ | |
| 202 | + // This is only the public function. | |
| 203 | + // Note that this can be called recursively. | |
| 204 | + // Value may contain function with a parameter of another value. | |
| 205 | + char* err; | |
| 206 | + int prevpos; | |
| 207 | + if (g_sdepth==0) { | |
| 208 | + // Initialize stack handler | |
| 209 | + g_maxsdepth=0; | |
| 210 | + prevpos=g_objpos; | |
| 211 | + // Stack decrement command will be filled later | |
| 212 | + check_obj_space(1); | |
| 213 | + g_objpos++; | |
| 214 | + } | |
| 215 | + err=get_value_sub(priority(OP_VOID)); | |
| 216 | + if (err) return err; | |
| 217 | + if (g_sdepth==0) { | |
| 218 | + if (g_maxsdepth==0) { | |
| 219 | + // Stack was not used. | |
| 220 | + shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1); | |
| 221 | + g_objpos--; | |
| 222 | + } else { | |
| 223 | + // Stack was used. | |
| 224 | + check_obj_space(1); | |
| 225 | + g_object[prevpos]=0x27BD0000 | (0-g_maxsdepth) & 0x0000FFFF; // addiu sp,sp,-xx | |
| 226 | + g_object[g_objpos++]=0x27BD0000 | g_maxsdepth & 0x0000FFFF; // addiu sp,sp,xx | |
| 227 | + } | |
| 228 | + } | |
| 229 | + g_lastvar=VAR_INTEGER; | |
| 230 | + return 0; | |
| 231 | +} | |
| 232 | + | |
| 233 | +char* get_floatOrValue(){ | |
| 234 | + char* err; | |
| 235 | + char b; | |
| 236 | + int opos,spos,sdpt; | |
| 237 | + sdpt=g_sdepth; | |
| 238 | + opos=g_objpos; | |
| 239 | + spos=g_srcpos; | |
| 240 | + // First try integer. | |
| 241 | + // Integer value has the higher priolity than float value. | |
| 242 | + err=get_value(); | |
| 243 | + b=g_source[g_srcpos]; | |
| 244 | + if (err) { | |
| 245 | + // Value is not integer. Let's try float. | |
| 246 | + g_sdepth=sdpt; | |
| 247 | + g_objpos=opos; | |
| 248 | + g_srcpos=spos; | |
| 249 | + return get_float(); | |
| 250 | + } else { | |
| 251 | + // Value was recognized as an integer. | |
| 252 | + return 0; | |
| 253 | + } | |
| 254 | +} | |
| 255 | + | |
| 256 | +char* get_stringFloatOrValue(){ | |
| 257 | + char* err; | |
| 258 | + int opos,spos; | |
| 259 | + opos=g_objpos; | |
| 260 | + spos=g_srcpos; | |
| 261 | + // First try string, float, then integer. | |
| 262 | + err=get_string(); | |
| 263 | + if (err) { | |
| 264 | + g_objpos=opos; | |
| 265 | + g_srcpos=spos; | |
| 266 | + return get_floatOrValue(); | |
| 267 | + } else { | |
| 268 | + return 0; | |
| 269 | + } | |
| 270 | +} | |
| 271 | + |
| @@ -0,0 +1,126 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by K.Tanaka & Katsumi | |
| 4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
| 5 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include <xc.h> | |
| 9 | +#include "api.h" | |
| 10 | +#include "main.h" | |
| 11 | +#include "compiler.h" | |
| 12 | + | |
| 13 | +void _general_exception_handler (void){ | |
| 14 | + int i; | |
| 15 | + // $v1 is g_ex_data | |
| 16 | + asm volatile("la $v1,%0"::"i"(&g_ex_data[0])); | |
| 17 | + // Prepare proper stack area before SoftReset | |
| 18 | + asm volatile("addiu $sp,$v1,0xfff0"); | |
| 19 | + // g_ex_data[2]=$s6 | |
| 20 | + asm volatile("sw $s6,8($v1)"); | |
| 21 | + // g_ex_data[3]=Cause | |
| 22 | + asm volatile("mfc0 $v0,$13"); | |
| 23 | + asm volatile("sw $v0,12($v1)"); | |
| 24 | + // g_ex_data[4]=EPC | |
| 25 | + asm volatile("mfc0 $v0,$14"); | |
| 26 | + asm volatile("sw $v0,16($v1)"); | |
| 27 | + // Exception occured | |
| 28 | + g_ex_data[0]=1; | |
| 29 | + // g_s6 | |
| 30 | + g_ex_data[1]=g_s6; | |
| 31 | + // Clear 2 MLB bits of EPC | |
| 32 | + g_ex_data[4]&=0xfffffffc; | |
| 33 | + // If EPC is within RAM, store data in exception area. | |
| 34 | + if ((int)(&RAM[0])<=g_ex_data[4] && g_ex_data[4] <(int)(&RAM[RAMSIZE])) { | |
| 35 | + // g_ex_data[5] - g_ex_data[12]: assembly | |
| 36 | + for(i=-3;i<=3;i++){ | |
| 37 | + g_ex_data[i+8]=((int*)g_ex_data[4])[i]; | |
| 38 | + } | |
| 39 | + } | |
| 40 | + // Wait until all buttons are released and reset MachiKania. | |
| 41 | + #ifdef __DEBUG | |
| 42 | + asm volatile("j 0xBFC00000"); | |
| 43 | + #else | |
| 44 | + buttonmode(); | |
| 45 | + for(i=0;i<100000;i++){ | |
| 46 | + if((KEYPORT&(KEYUP|KEYDOWN|KEYLEFT|KEYRIGHT|KEYSTART|KEYFIRE)) | |
| 47 | + !=(KEYUP|KEYDOWN|KEYLEFT|KEYRIGHT|KEYSTART|KEYFIRE)) i=0; | |
| 48 | + } | |
| 49 | + asm volatile("j SoftReset"); | |
| 50 | + #endif | |
| 51 | +} | |
| 52 | + | |
| 53 | +void blue_screen(void){ | |
| 54 | + int i,j,s6,s6g; | |
| 55 | + unsigned int* opos; | |
| 56 | + if (RCONbits.POR || RCONbits.EXTR) { | |
| 57 | + // After power on or reset. Reset flags and return. | |
| 58 | + RCONbits.POR=0; | |
| 59 | + RCONbits.EXTR=0; | |
| 60 | + for(i=0;i<RAMSIZE;i++){ | |
| 61 | + // Reset all RAM area including g_ex_data[] | |
| 62 | + RAM[i]=0; | |
| 63 | + } | |
| 64 | + return; | |
| 65 | + } else if (g_ex_data[0]==0) { | |
| 66 | + // No exception found. | |
| 67 | + return; | |
| 68 | + } | |
| 69 | + // Exception occured before SoftReset(). | |
| 70 | + // Prepare data | |
| 71 | + s6=g_ex_data[2]; | |
| 72 | + s6g=g_ex_data[1]; | |
| 73 | + s6=s6&0x7fffffff; | |
| 74 | + s6g=s6g&0x7fffffff; | |
| 75 | + opos=(int*)g_ex_data[4]; | |
| 76 | + //set_bgcolor(255,0,0); | |
| 77 | + printstr("STOP"); | |
| 78 | + printstr("\nException at "); | |
| 79 | + printhex32(g_ex_data[4]); | |
| 80 | + printstr("\n Cause: "); | |
| 81 | + printhex32(g_ex_data[3]); | |
| 82 | + printstr("\n "); | |
| 83 | + switch((g_ex_data[3]>>2)&0x1f){ | |
| 84 | + case 0: printstr("(Interrupt)"); break; | |
| 85 | + case 1: printstr("(TLB modification)"); break; | |
| 86 | + case 2: printstr("(TLB load/fetch)"); break; | |
| 87 | + case 3: printstr("(TLB store)"); break; | |
| 88 | + case 4: printstr("(Address load/fetch error )"); break; | |
| 89 | + case 5: printstr("(Address store error)"); break; | |
| 90 | + case 6: printstr("(Bus fetch error)"); break; | |
| 91 | + case 7: printstr("(Bus load/store error)"); break; | |
| 92 | + case 8: printstr("(Syscall)"); break; | |
| 93 | + case 9: printstr("(Breakpoint)"); break; | |
| 94 | + case 10: printstr("(Reserved instruction)"); break; | |
| 95 | + case 11: printstr("(Coprocessor Unusable)"); break; | |
| 96 | + case 12: printstr("(Integer Overflow)"); break; | |
| 97 | + case 13: printstr("(Trap)"); break; | |
| 98 | + case 23: printstr("(Reference to Watch address)"); break; | |
| 99 | + case 24: printstr("(Machine check)"); break; | |
| 100 | + default: printstr("(Unknown)"); break; | |
| 101 | + } | |
| 102 | + printstr("\n s6: "); | |
| 103 | + printstr(resolve_label(s6)); | |
| 104 | + printstr("\n g_s6: "); | |
| 105 | + printstr(resolve_label(s6g)); | |
| 106 | + printstr("\n"); | |
| 107 | + printstr("Reset MachiKania to contine.\n\n"); | |
| 108 | + // Show code where the exception happened. | |
| 109 | + for(i=-3;i<=3;i++){ | |
| 110 | + printstr("\n "); | |
| 111 | + printhex32((unsigned int)&opos[i]); | |
| 112 | + printstr(" "); | |
| 113 | + if ((unsigned int)&RAM[0]<=(unsigned int)&opos[i] && (unsigned int)&opos[i]<(unsigned int)&RAM[RAMSIZE]) { | |
| 114 | + // Exception in RAM[RAMSIZE] area | |
| 115 | + printhex32(g_ex_data[i+8]); | |
| 116 | + } else if ( 0xA0000000<=(unsigned int)&opos[i] && (unsigned int)&opos[i]<0xA0000000+PIC32MX_RAMSIZE | |
| 117 | + || 0x9D000000<=(unsigned int)&opos[i] && (unsigned int)&opos[i]<=0x9D000000+PIC32MX_FLASHSIZE) { | |
| 118 | + // Exception in outside RAM[RAMSIZE] or flash area | |
| 119 | + printhex32(opos[i]); | |
| 120 | + } else { | |
| 121 | + printstr("********"); | |
| 122 | + } | |
| 123 | + } | |
| 124 | + printstr("\n"); | |
| 125 | + while(1) asm("wait"); | |
| 126 | +} |
| @@ -0,0 +1,25 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by K.Tanaka & Katsumi | |
| 4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
| 5 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#ifdef __DEBUG | |
| 9 | + | |
| 10 | +// Pseudo reading config setting for debug mode | |
| 11 | +extern unsigned int g_DEVCFG1; | |
| 12 | +#define DEVCFG1 g_DEVCFG1 | |
| 13 | + | |
| 14 | +// Do not use PS/2 keyboard | |
| 15 | +#define ps2init() not_ps2init_but_init_Timer1() | |
| 16 | +int not_ps2init_but_init_Timer1(); | |
| 17 | + | |
| 18 | +// Do not use set_graphmode() | |
| 19 | +#define set_graphmode(m) (0) | |
| 20 | + | |
| 21 | +// Do not use asm("wait") but use asm("nop") | |
| 22 | +#undef WAIT | |
| 23 | +#define WAIT "nop" | |
| 24 | + | |
| 25 | +#endif // __DEBUG |
| @@ -0,0 +1,216 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by K.Tanaka & Katsumi | |
| 4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
| 5 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +// main.c | |
| 9 | +// MachiKania BASIC System Ver Zoea | |
| 10 | +// KM-BASIC 統合開発実行環境 for PIC32MX170F256B / PIC32MX270F256B by K.Tanaka | |
| 11 | + | |
| 12 | +// 利用システム | |
| 13 | +// ps2keyboard.X.a : PS/2キーボード入力システムライブラリ | |
| 14 | +// lib_colortext32.a : カラービデオ信号出力システムライブラリ(30×27テキスト版) | |
| 15 | +// libsdfsio.a : SDカードアクセス用ライブラリ | |
| 16 | + | |
| 17 | +#include <xc.h> | |
| 18 | +#include "api.h" | |
| 19 | +#include "compiler.h" | |
| 20 | +#include "editor.h" | |
| 21 | +#include "keyinput.h" | |
| 22 | +#include "main.h" | |
| 23 | + | |
| 24 | +//外付けクリスタル with PLL (16倍) | |
| 25 | +#pragma config PMDL1WAY = OFF, IOL1WAY = OFF | |
| 26 | +#pragma config FPLLIDIV = DIV_1, FPLLMUL = MUL_16, FPLLODIV = DIV_1 | |
| 27 | +#pragma config FNOSC = PRIPLL, FSOSCEN = OFF, POSCMOD = XT, OSCIOFNC = OFF | |
| 28 | +#pragma config FPBDIV = DIV_1, FWDTEN = OFF, JTAGEN = OFF, ICESEL = ICS_PGx1 | |
| 29 | +#pragma config FCKSM = CSECMD | |
| 30 | + | |
| 31 | +#define mBMXSetRAMKernProgOffset(offset) (BMXDKPBA = (offset)) | |
| 32 | +#define mBMXSetRAMUserDataOffset(offset) (BMXDUDBA = (offset)) | |
| 33 | +#define mBMXSetRAMUserProgOffset(offset) (BMXDUPBA = (offset)) | |
| 34 | + | |
| 35 | +// INIファイル指定キーワード(8文字以内) | |
| 36 | +const char InitKeywords[][9]={ | |
| 37 | + "106KEY","101KEY","NUMLOCK","CAPSLOCK","SCRLLOCK" | |
| 38 | +}; | |
| 39 | + | |
| 40 | +void freadline(char *s,FSFILE *fp){ | |
| 41 | +// ファイルから1行読み込み、配列sに返す | |
| 42 | +// 最大8文字まで。9文字以上の場合無効 | |
| 43 | +// #または0x20以下のコードを見つけた場合、以降は無視 | |
| 44 | +// s:9バイト以上の配列 | |
| 45 | +// fp:ファイルポインタ | |
| 46 | + int n; | |
| 47 | + char c,*p; | |
| 48 | + n=0; | |
| 49 | + p=s; | |
| 50 | + *p=0; | |
| 51 | + while(n<=8){ | |
| 52 | + if(FSfread(p,1,1,fp)==0 || *p=='\n'){ | |
| 53 | + *p=0; | |
| 54 | + return; | |
| 55 | + } | |
| 56 | + if(*p=='#'){ | |
| 57 | + *p=0; | |
| 58 | + break; | |
| 59 | + } | |
| 60 | + if(*p<=' '){ | |
| 61 | + if(n>0){ | |
| 62 | + *p=0; | |
| 63 | + break; | |
| 64 | + } | |
| 65 | + continue; | |
| 66 | + } | |
| 67 | + p++; | |
| 68 | + n++; | |
| 69 | + } | |
| 70 | + if(n>8) *s=0; //9文字以上の文字列の場合は無効 | |
| 71 | + //以降の文字は無視 | |
| 72 | + while(FSfread(&c,1,1,fp) && c!='\n') ; | |
| 73 | +} | |
| 74 | +int searchinittext(char *s){ | |
| 75 | +// InitKeywords配列の中から文字列sを探し、位置した場合何番目かを返す | |
| 76 | +// 見つからなかった場合-1を返す | |
| 77 | + int i; | |
| 78 | + char *p1; | |
| 79 | + const char *p2; | |
| 80 | + for(i=0;i<sizeof(InitKeywords)/sizeof(InitKeywords[0]);i++){ | |
| 81 | + p1=s; | |
| 82 | + p2=InitKeywords[i]; | |
| 83 | + while(*p1==*p2){ | |
| 84 | + if(*p1==0) return i; | |
| 85 | + p1++; | |
| 86 | + p2++; | |
| 87 | + } | |
| 88 | + } | |
| 89 | + return -1; | |
| 90 | +} | |
| 91 | +void readinifile(void){ | |
| 92 | + FSFILE *fp; | |
| 93 | + char inittext[9]; | |
| 94 | + | |
| 95 | + fp=FSfopen(INIFILE,"r"); | |
| 96 | + if(fp==NULL) return; | |
| 97 | + printstr("Initialization File Found\n"); | |
| 98 | + lockkey=0; //INIファイルが存在する場合、Lock関連キーはINIファイルに従う | |
| 99 | + while(1){ | |
| 100 | + if(FSfeof(fp)) break; | |
| 101 | + freadline(inittext,fp); | |
| 102 | + switch(searchinittext(inittext)){ | |
| 103 | + case 0: | |
| 104 | + keytype=0;//日本語キーボード | |
| 105 | + break; | |
| 106 | + case 1: | |
| 107 | + keytype=1;//英語キーボード | |
| 108 | + break; | |
| 109 | + case 2: | |
| 110 | + lockkey|=2;//Num Lock | |
| 111 | + break; | |
| 112 | + case 3: | |
| 113 | + lockkey|=4;//CAPS Lock | |
| 114 | + break; | |
| 115 | + case 4: | |
| 116 | + lockkey|=1;//Scroll Lock | |
| 117 | + break; | |
| 118 | + } | |
| 119 | + } | |
| 120 | + FSfclose(fp); | |
| 121 | +} | |
| 122 | + | |
| 123 | +void printhex8(unsigned char d){ | |
| 124 | + printchar("0123456789ABCDEF"[d>>4]); | |
| 125 | + printchar("0123456789ABCDEF"[d&0x0f]); | |
| 126 | +} | |
| 127 | + | |
| 128 | +void printhex16(unsigned short d){ | |
| 129 | + printhex8(d>>8); | |
| 130 | + printhex8(d&0x00ff); | |
| 131 | +} | |
| 132 | + | |
| 133 | +void printhex32(unsigned int d){ | |
| 134 | + printhex16(d>>16); | |
| 135 | + printhex16(d&0x0000ffff); | |
| 136 | +} | |
| 137 | + | |
| 138 | +int main(void){ | |
| 139 | + char *appname,*s; | |
| 140 | + | |
| 141 | + if(DEVCFG1 & 0x8000){ | |
| 142 | + // Set Clock switching enabled and reset | |
| 143 | + NVMWriteWord(&DEVCFG1,DEVCFG1 & 0xffff7fff); | |
| 144 | + SoftReset(); | |
| 145 | + } | |
| 146 | + | |
| 147 | + /* ポートの初期設定 */ | |
| 148 | + TRISA = 0x0000; // PORTA全て出力 | |
| 149 | + ANSELA = 0x0000; // 全てデジタル | |
| 150 | + TRISB = KEYSTART | KEYFIRE | KEYUP | KEYDOWN | KEYLEFT | KEYRIGHT;// ボタン接続ポート入力設定 | |
| 151 | + ANSELB = 0x0000; // 全てデジタル | |
| 152 | + CNPUBSET=KEYSTART | KEYFIRE | KEYUP | KEYDOWN | KEYLEFT | KEYRIGHT;// プルアップ設定 | |
| 153 | + ODCB = 0x0300; //RB8,RB9はオープンドレイン | |
| 154 | + | |
| 155 | + // 周辺機能ピン割り当て | |
| 156 | + SDI2R=2; //RPA4:SDI2 | |
| 157 | + RPB5R=4; //RPB5:SDO2 | |
| 158 | + | |
| 159 | + // Make RAM executable. See also "char RAM[RAMSIZE]" in globalvars.c | |
| 160 | + mBMXSetRAMKernProgOffset(PIC32MX_RAMSIZE-RAMSIZE); | |
| 161 | + mBMXSetRAMUserDataOffset(PIC32MX_RAMSIZE); | |
| 162 | + mBMXSetRAMUserProgOffset(PIC32MX_RAMSIZE); | |
| 163 | + | |
| 164 | + ps2mode(); //RA1オン(PS/2有効化マクロ) | |
| 165 | + init_composite(); // ビデオメモリクリア、割り込み初期化、カラービデオ出力開始 | |
| 166 | + setcursor(0,0,COLOR_NORMALTEXT); | |
| 167 | + | |
| 168 | + // Show blue screen if exception before soft reset. | |
| 169 | + blue_screen(); | |
| 170 | + | |
| 171 | + printstr("MachiKania BASIC System\n"); | |
| 172 | + printstr(" Ver "SYSVER1" "SYSVER2" by KENKEN\n"); | |
| 173 | + printstr("BASIC Compiler "BASVER"\n"); | |
| 174 | + printstr(" by Katsumi\n\n"); | |
| 175 | + //SDカードファイルシステム初期化 | |
| 176 | + setcursorcolor(COLOR_NORMALTEXT); | |
| 177 | + printstr("Init File System..."); | |
| 178 | + // Initialize the File System | |
| 179 | + if(FSInit()==FALSE){ //ファイルシステム初期化 | |
| 180 | + //エラーの場合停止 | |
| 181 | + setcursorcolor(COLOR_ERRORTEXT); | |
| 182 | + printstr("\nFile System Error\n"); | |
| 183 | + printstr("Insert Correct Card\n"); | |
| 184 | + printstr("And Reset\n"); | |
| 185 | + while(1) asm("wait"); | |
| 186 | + } | |
| 187 | + printstr("OK\n"); | |
| 188 | + lockkey=2; // NumLockキーオン | |
| 189 | + keytype=0; // 日本語キーボード | |
| 190 | + readinifile(); //INIファイル読み込み | |
| 191 | + printstr("Init PS/2..."); | |
| 192 | + if(ps2init()){ //PS/2初期化 | |
| 193 | + //キーボードが見つからない場合 | |
| 194 | + printstr("Keyboard Not Found\n"); | |
| 195 | + } | |
| 196 | + else printstr("OK\n"); | |
| 197 | + | |
| 198 | + wait60thsec(60); //1秒待ち | |
| 199 | + | |
| 200 | + // 実行中HEXファイル名がHEXFILEと一致した場合はエディタ起動 | |
| 201 | + appname=(char*)FILENAME_FLASH_ADDRESS; | |
| 202 | + s=HEXFILE; | |
| 203 | + while(*s++==*appname++) if(*s==0) texteditor(); //テキストエディター呼び出し | |
| 204 | + | |
| 205 | + // 実行中HEXファイル名の「.HEX」を「.BAS」に置き換えてBASファイルを実行 | |
| 206 | + appname=(char*)FILENAME_FLASH_ADDRESS; | |
| 207 | + s=tempfile; | |
| 208 | + while(*appname!='.') *s++=*appname++; | |
| 209 | + appname=".BAS"; | |
| 210 | + while(*appname!=0) *s++=*appname++; | |
| 211 | + *s=0; | |
| 212 | + // buttonmode(); //ボタン有効化 | |
| 213 | + g_disable_break=1; // Breakキー無効化 | |
| 214 | + runbasic(tempfile,0); | |
| 215 | + while(1) asm(WAIT); | |
| 216 | +} |
| @@ -0,0 +1,38 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#ifndef BOOL | |
| 9 | + typedef enum _BOOL { FALSE = 0, TRUE } BOOL; | |
| 10 | +#endif | |
| 11 | + | |
| 12 | +#ifndef BYTE | |
| 13 | + #define BYTE unsigned char | |
| 14 | +#endif | |
| 15 | + | |
| 16 | +#ifndef WORD | |
| 17 | + #define WORD unsigned short | |
| 18 | +#endif | |
| 19 | + | |
| 20 | +#ifndef DWORD | |
| 21 | + #define DWORD unsigned long | |
| 22 | +#endif | |
| 23 | + | |
| 24 | +#ifndef UINT16 | |
| 25 | + #define UINT16 unsigned short | |
| 26 | +#endif | |
| 27 | + | |
| 28 | +#ifndef size_t | |
| 29 | + #define size_t unsigned int | |
| 30 | +#endif | |
| 31 | + | |
| 32 | +// Used for asm("wait") | |
| 33 | +#define WAIT "wait" | |
| 34 | + | |
| 35 | +#include "videoout.h" | |
| 36 | +#include "SDFSIO.h" | |
| 37 | +#include "ps2keyboard.h" | |
| 38 | +#include "debug.h" |
| @@ -0,0 +1,275 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include "compiler.h" | |
| 9 | + | |
| 10 | +/* | |
| 11 | +Operators: (upper ones have higher priority | |
| 12 | +() | |
| 13 | +* / % | |
| 14 | ++ - | |
| 15 | +<< >> | |
| 16 | +< <= > >= | |
| 17 | += != | |
| 18 | +XOR | |
| 19 | +AND | |
| 20 | +OR | |
| 21 | +*/ | |
| 22 | + | |
| 23 | + | |
| 24 | +const unsigned char g_priority[]={ | |
| 25 | + 0, // OP_VOID | |
| 26 | + 1, // OP_OR | |
| 27 | + 2, // OP_AND | |
| 28 | + 3, // OP_XOR | |
| 29 | + 4,4, // OP_EQ, OP_NEQ | |
| 30 | + 5,5,5,5, // OP_LT, OP_LTE, OP_MT, OP_MTE | |
| 31 | + 6,6, // OP_SHL, OP_SHR | |
| 32 | + 7,7, // OP_ADD, OP_SUB | |
| 33 | + 8,8,8 // OP_MUL, OP_DIV, OP_REM | |
| 34 | +}; | |
| 35 | + | |
| 36 | +enum operator g_last_op; | |
| 37 | + | |
| 38 | +char* get_operator(void){ | |
| 39 | + char b1,b2,b3; | |
| 40 | + next_position(); | |
| 41 | + b1=g_source[g_srcpos]; | |
| 42 | + b2=g_source[g_srcpos+1]; | |
| 43 | + b3=g_source[g_srcpos+2]; | |
| 44 | + switch(b1){ | |
| 45 | + case '%': g_last_op=OP_REM; break; | |
| 46 | + case '/': g_last_op=OP_DIV; break; | |
| 47 | + case '*': g_last_op=OP_MUL; break; | |
| 48 | + case '-': g_last_op=OP_SUB; break; | |
| 49 | + case '+': g_last_op=OP_ADD; break; | |
| 50 | + case '>': | |
| 51 | + if (b2=='>') { | |
| 52 | + g_srcpos++; | |
| 53 | + g_last_op=OP_SHR; | |
| 54 | + } else if (b2=='=') { | |
| 55 | + g_srcpos++; | |
| 56 | + g_last_op=OP_MTE; | |
| 57 | + } else { | |
| 58 | + g_last_op=OP_MT; | |
| 59 | + } | |
| 60 | + break; | |
| 61 | + case '<': | |
| 62 | + if (b2=='<') { | |
| 63 | + g_srcpos++; | |
| 64 | + g_last_op=OP_SHL; | |
| 65 | + } else if (b2=='=') { | |
| 66 | + g_srcpos++; | |
| 67 | + g_last_op=OP_LTE; | |
| 68 | + } else { | |
| 69 | + g_last_op=OP_LT; | |
| 70 | + } | |
| 71 | + break; | |
| 72 | + case '!': | |
| 73 | + if (b2!='=') return ERR_SYNTAX; | |
| 74 | + g_srcpos++; | |
| 75 | + g_last_op=OP_NEQ; | |
| 76 | + break; | |
| 77 | + case '=': | |
| 78 | + if (b2=='=') g_srcpos++; | |
| 79 | + g_last_op=OP_EQ; | |
| 80 | + break; | |
| 81 | + case 'X': | |
| 82 | + if (b2!='O') return ERR_SYNTAX; | |
| 83 | + if (b3!='R') return ERR_SYNTAX; | |
| 84 | + g_srcpos++; | |
| 85 | + g_srcpos++; | |
| 86 | + g_last_op=OP_XOR; | |
| 87 | + break; | |
| 88 | + case 'O': | |
| 89 | + if (b2!='R') return ERR_SYNTAX; | |
| 90 | + g_srcpos++; | |
| 91 | + g_last_op=OP_OR; | |
| 92 | + break; | |
| 93 | + case 'A': | |
| 94 | + if (b2!='N') return ERR_SYNTAX; | |
| 95 | + if (b3!='D') return ERR_SYNTAX; | |
| 96 | + g_srcpos++; | |
| 97 | + g_srcpos++; | |
| 98 | + g_last_op=OP_AND; | |
| 99 | + break; | |
| 100 | + default: | |
| 101 | + return ERR_SYNTAX; | |
| 102 | + } | |
| 103 | + g_srcpos++; | |
| 104 | + return 0; | |
| 105 | +} | |
| 106 | + | |
| 107 | +char* get_floatOperator(void){ | |
| 108 | + char* err; | |
| 109 | + int spos; | |
| 110 | + next_position(); | |
| 111 | + spos=g_srcpos; | |
| 112 | + err=get_operator(); | |
| 113 | + if (err) return err; | |
| 114 | + switch(g_last_op){ | |
| 115 | + // Following operators cannot be used for float values. | |
| 116 | + case OP_XOR: | |
| 117 | + case OP_REM: | |
| 118 | + case OP_SHR: | |
| 119 | + case OP_SHL: | |
| 120 | + g_srcpos=spos; | |
| 121 | + return ERR_SYNTAX; | |
| 122 | + default: | |
| 123 | + return 0; | |
| 124 | + } | |
| 125 | +} | |
| 126 | + | |
| 127 | +char* calculation(enum operator op){ | |
| 128 | + // $v0 = $v1 <op> $v0; | |
| 129 | + switch(op){ | |
| 130 | + case OP_OR: | |
| 131 | + check_obj_space(1); | |
| 132 | + g_object[g_objpos++]=0x00621025; // or v0,v1,v0 | |
| 133 | + break; | |
| 134 | + case OP_AND: | |
| 135 | + check_obj_space(1); | |
| 136 | + g_object[g_objpos++]=0x00621024; // and v0,v1,v0 | |
| 137 | + break; | |
| 138 | + case OP_XOR: | |
| 139 | + check_obj_space(1); | |
| 140 | + g_object[g_objpos++]=0x00621026; // xor v0,v1,v0 | |
| 141 | + break; | |
| 142 | + case OP_EQ: | |
| 143 | + check_obj_space(2); | |
| 144 | + g_object[g_objpos++]=0x00621026; // xor v0,v1,v0 | |
| 145 | + g_object[g_objpos++]=0x2C420001; // sltiu v0,v0,1 | |
| 146 | + break; | |
| 147 | + case OP_NEQ: | |
| 148 | + check_obj_space(2); | |
| 149 | + g_object[g_objpos++]=0x00621026; // xor v0,v1,v0 | |
| 150 | + g_object[g_objpos++]=0x0002102B; // sltu v0,zero,v0 | |
| 151 | + break; | |
| 152 | + case OP_LT: | |
| 153 | + check_obj_space(1); | |
| 154 | + g_object[g_objpos++]=0x0062102A; // slt v0,v1,v0 | |
| 155 | + break; | |
| 156 | + case OP_LTE: | |
| 157 | + check_obj_space(2); | |
| 158 | + g_object[g_objpos++]=0x0043102A; // slt v0,v0,v1 | |
| 159 | + g_object[g_objpos++]=0x38420001; // xori v0,v0,0x1 | |
| 160 | + break; | |
| 161 | + case OP_MT: | |
| 162 | + check_obj_space(1); | |
| 163 | + g_object[g_objpos++]=0x0043102A; // slt v0,v0,v1 | |
| 164 | + break; | |
| 165 | + case OP_MTE: | |
| 166 | + check_obj_space(2); | |
| 167 | + g_object[g_objpos++]=0x0062102A; // slt v0,v1,v0 | |
| 168 | + g_object[g_objpos++]=0x38420001; // xori v0,v0,0x1 | |
| 169 | + break; | |
| 170 | + case OP_SHR: | |
| 171 | + check_obj_space(1); | |
| 172 | + g_object[g_objpos++]=0x00431006; // srlv v0,v1,v0 | |
| 173 | + break; | |
| 174 | + case OP_SHL: | |
| 175 | + check_obj_space(1); | |
| 176 | + g_object[g_objpos++]=0x00431004; // sllv v0,v1,v0 | |
| 177 | + break; | |
| 178 | + case OP_ADD: | |
| 179 | + check_obj_space(1); | |
| 180 | + g_object[g_objpos++]=0x00621021; // addu v0,v1,v0 | |
| 181 | + break; | |
| 182 | + case OP_SUB: | |
| 183 | + check_obj_space(1); | |
| 184 | + g_object[g_objpos++]=0x00621023; // subu v0,v1,v0 | |
| 185 | + break; | |
| 186 | + case OP_MUL: | |
| 187 | + check_obj_space(1); | |
| 188 | + g_object[g_objpos++]=0x70621002; // mul v0,v1,v0 | |
| 189 | + break; | |
| 190 | + case OP_DIV: | |
| 191 | + // Note that intterupt functions do not use mflo and mfhi. | |
| 192 | + // Probably using div does not cause delay of interrupt. | |
| 193 | + check_obj_space(5); | |
| 194 | + g_object[g_objpos++]=0x14400003; // bne v0,zero,label | |
| 195 | + g_object[g_objpos++]=0x0062001A; // div v1,v0 | |
| 196 | + call_lib_code(LIB_DIV0); // 2 words | |
| 197 | + // label: | |
| 198 | + g_object[g_objpos++]=0x00001012; // mflo v0 | |
| 199 | + break; | |
| 200 | + case OP_REM: | |
| 201 | + check_obj_space(5); | |
| 202 | + g_object[g_objpos++]=0x14400003; // bne v0,zero,label | |
| 203 | + g_object[g_objpos++]=0x0062001A; // div v1,v0 | |
| 204 | + call_lib_code(LIB_DIV0); // 2 words | |
| 205 | + // label: | |
| 206 | + g_object[g_objpos++]=0x00001010; // mfhi v0 | |
| 207 | + break; | |
| 208 | + default: | |
| 209 | + return ERR_SYNTAX; | |
| 210 | + } | |
| 211 | + return 0; | |
| 212 | +} | |
| 213 | + | |
| 214 | +char* calculation_float(enum operator op){ | |
| 215 | + // $v0 = $a0 <op> $v0; | |
| 216 | + check_obj_space(1); | |
| 217 | + g_object[g_objpos++]=0x34050000|(op&0x0000FFFF); // ori a1,zero,xxxx | |
| 218 | + // All the calculations will be done in library code, lib_float function (see below). | |
| 219 | + call_lib_code(LIB_FLOAT); | |
| 220 | + return 0; | |
| 221 | +} | |
| 222 | + | |
| 223 | +int lib_float(int ia0,int iv0, enum operator a1){ | |
| 224 | + // This function was called from _call_library(). | |
| 225 | + // Variable types must be all int. | |
| 226 | + // Casting cannot be used. | |
| 227 | + // Instead, by using pointer, put as int value, get as float value, | |
| 228 | + // calculate, put as float value, then get as int value for returning. | |
| 229 | + volatile float a0,v0; | |
| 230 | + ((int*)(&a0))[0]=ia0; | |
| 231 | + ((int*)(&v0))[0]=iv0; | |
| 232 | + switch(a1){ | |
| 233 | + case OP_EQ: | |
| 234 | + v0= a0==v0?1:0; | |
| 235 | + break; | |
| 236 | + case OP_NEQ: | |
| 237 | + v0= a0!=v0?1:0; | |
| 238 | + break; | |
| 239 | + case OP_LT: | |
| 240 | + v0= a0<v0?1:0; | |
| 241 | + break; | |
| 242 | + case OP_LTE: | |
| 243 | + v0= a0<=v0?1:0; | |
| 244 | + break; | |
| 245 | + case OP_MT: | |
| 246 | + v0= a0>v0?1:0; | |
| 247 | + break; | |
| 248 | + case OP_MTE: | |
| 249 | + v0= a0>=v0?1:0; | |
| 250 | + break; | |
| 251 | + case OP_ADD: | |
| 252 | + v0= a0+v0; | |
| 253 | + break; | |
| 254 | + case OP_SUB: | |
| 255 | + v0= a0-v0; | |
| 256 | + break; | |
| 257 | + case OP_MUL: | |
| 258 | + v0= a0*v0; | |
| 259 | + break; | |
| 260 | + case OP_DIV: | |
| 261 | + if (v0==0) err_div_zero(); | |
| 262 | + v0= a0/v0; | |
| 263 | + break; | |
| 264 | + case OP_OR: | |
| 265 | + v0= a0||v0?1:0; | |
| 266 | + break; | |
| 267 | + case OP_AND: | |
| 268 | + v0= a0&&v0?1:0; | |
| 269 | + break; | |
| 270 | + default: | |
| 271 | + err_unknown(); | |
| 272 | + return 0; | |
| 273 | + } | |
| 274 | + return ((int*)(&v0))[0]; | |
| 275 | +}; | |
| \ No newline at end of file |
| @@ -0,0 +1,175 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by Katsumi. | |
| 4 | + http://hp.vector.co.jp/authors/VA016157/ | |
| 5 | + kmorimatsu@users.sourceforge.jp | |
| 6 | +*/ | |
| 7 | + | |
| 8 | +#include "compiler.h" | |
| 9 | + | |
| 10 | +/* | |
| 11 | + ALLOC_VAR_NUM: # of variables used for allocation of memory (string/dimension). | |
| 12 | + 0 is for A, 1 is for B, ... , and 25 is for Z. | |
| 13 | + This number also includes temporary area used for string construction etc. | |
| 14 | + Temporary area is cleared every line of BASIC code in alloc_memory(). | |
| 15 | + ALLOC_BLOCK_NUM: # of blocks that can be used for memory allocation. | |
| 16 | + This # also includes the ones for ALLOC_VAR_NUM. | |
| 17 | + After ALLOC_VAR_NUM area, dedicated memory area and permanent area follows. | |
| 18 | + Currently, only PCG is used for permanent pourpose. | |
| 19 | + 10 permanant blocks can be used. | |
| 20 | + Therefore, ALLOC_VAR_NUM+11 == ALLOC_BLOCK_NUM | |
| 21 | + ALLOC_PERM_BLOCK: Start # of permanent blocks. | |
| 22 | + The blocks after this number is permanently stored. | |
| 23 | + Therefore, it must be released when it's not used any more. | |
| 24 | +*/ | |
| 25 | + | |
| 26 | +void set_free_area(void* begin, void* end){ | |
| 27 | + int i; | |
| 28 | + for(i=0;i<ALLOC_BLOCK_NUM;i++){ | |
| 29 | + g_var_size[i]=0; | |
| 30 | + } | |
| 31 | + g_heap_mem=(int*)begin; | |
| 32 | + g_max_mem=(int)((end-begin)/4); | |
| 33 | +} | |
| 34 | + | |
| 35 | +void* calloc_memory(int size, int var_num){ | |
| 36 | + int i; | |
| 37 | + void* ret; | |
| 38 | + // Allocate memory | |
| 39 | + ret=alloc_memory(size,var_num); | |
| 40 | + // Fill zero in allocated memory | |
| 41 | + for(i=0;i<size;i++){ | |
| 42 | + ((int*)ret)[i]=0; | |
| 43 | + } | |
| 44 | + // return pointer to allocated memory | |
| 45 | + return ret; | |
| 46 | +} | |
| 47 | +void* alloc_memory(int size, int var_num){ | |
| 48 | + // Remove temporary blocks once a line. | |
| 49 | + asm volatile("nop"); | |
| 50 | + asm volatile("bltz $s6,_alloc_memory_main"); // Skip if $s6<0 | |
| 51 | + // Following code will be activated after setting $s6 register | |
| 52 | + // every line and after label statement. | |
| 53 | + asm volatile("lui $v0,0x8000"); | |
| 54 | + asm volatile("or $s6,$v0,$s6"); // $s6=0x80000000|$s6; | |
| 55 | + // Remove all temporary blocks | |
| 56 | + // Note that g_var_size is short integer. | |
| 57 | + // Note that ALLOC_VAR_NUM is used here (but not ALLOC_BLOC_NUM) | |
| 58 | + // for(i=26;i<ALLOC_VAR_NUM;i++)g_var_size[i]=0; | |
| 59 | + asm volatile("addiu $v0,$zero,%0"::"n"((ALLOC_VAR_NUM-26)/2)); // $v0=(ALLOC_VAR_NUM-26)/2 | |
| 60 | + asm volatile("la $v1,%0"::"i"(&g_var_size[0])); // $v1=g_var_size | |
| 61 | + asm volatile("loop:"); | |
| 62 | + asm volatile("sw $zero,(26*2)($v1)"); // $v1[26]=0, $v1[27]=0 | |
| 63 | + asm volatile("addiu $v0,$v0,-1"); // $v0-- | |
| 64 | + asm volatile("addiu $v1,$v1,4"); // $v1+=2 | |
| 65 | + asm volatile("bne $v0,$zero,loop"); // loop if 0<$v0 | |
| 66 | + asm volatile("b _alloc_memory_main"); | |
| 67 | +} | |
| 68 | +void* _alloc_memory_main(int size, int var_num){ | |
| 69 | + int i,j,candidate; | |
| 70 | + // Assign temp var number | |
| 71 | + if (var_num<0) { | |
| 72 | + // Use ALLOC_VAR_NUM here but not ALLOC_BLOCK_NUM | |
| 73 | + for(i=26;i<ALLOC_VAR_NUM;i++){ | |
| 74 | + if (g_var_size[i]==0) { | |
| 75 | + var_num=i; | |
| 76 | + break; | |
| 77 | + } | |
| 78 | + } | |
| 79 | + if (var_num<0) { | |
| 80 | + err_str_complex(); | |
| 81 | + return 0; | |
| 82 | + } | |
| 83 | + } | |
| 84 | + // Clear var to be assigned. | |
| 85 | + g_var_size[var_num]=0; | |
| 86 | + g_var_pointer[var_num]=0; | |
| 87 | + while(1){ | |
| 88 | + // Try the block after last block | |
| 89 | + candidate=0; | |
| 90 | + for(i=0;i<ALLOC_BLOCK_NUM;i++){ | |
| 91 | + if (g_var_size[i]==0) continue; | |
| 92 | + if (candidate<=g_var_pointer[i]) { | |
| 93 | + candidate=g_var_pointer[i]+g_var_size[i]; | |
| 94 | + } | |
| 95 | + } | |
| 96 | + if (candidate+size<=g_max_mem) break; | |
| 97 | + // Check between blocks | |
| 98 | + // Note that there is at least one block with zero pointer and zero size (see above). | |
| 99 | + for(i=0;i<ALLOC_BLOCK_NUM;i++){ | |
| 100 | + // Candidate is after this block. | |
| 101 | + candidate=g_var_pointer[i]+g_var_size[i]; | |
| 102 | + // Check if there is an overlap. | |
| 103 | + for(j=0;j<ALLOC_BLOCK_NUM;j++){ | |
| 104 | + if (g_var_size[j]==0) continue; | |
| 105 | + if (candidate+size<=g_var_pointer[j]) continue; | |
| 106 | + if (g_var_pointer[j]+g_var_size[j]<=candidate) continue; | |
| 107 | + // This block overlaps with the candidate | |
| 108 | + candidate=-1; | |
| 109 | + break; | |
| 110 | + } | |
| 111 | + if (0<=candidate && candidate+size<=g_max_mem) { | |
| 112 | + // Available block found | |
| 113 | + break; | |
| 114 | + } else { | |
| 115 | + candidate=-1; | |
| 116 | + } | |
| 117 | + } | |
| 118 | + if (0<=candidate) break; | |
| 119 | + // New memory block cannot be allocated. | |
| 120 | + err_no_mem(); | |
| 121 | + return 0; | |
| 122 | + } | |
| 123 | + // Available block found. | |
| 124 | + g_var_pointer[var_num]=candidate; | |
| 125 | + g_var_size[var_num]=size; | |
| 126 | + g_var_mem[var_num]=(int)(&(g_heap_mem[candidate])); | |
| 127 | + return (void*)g_var_mem[var_num]; | |
| 128 | +} | |
| 129 | + | |
| 130 | +void free_temp_str(char* str){ | |
| 131 | + int i,pointer; | |
| 132 | + if (!str) return; | |
| 133 | + pointer=(int)str-(int)g_heap_mem; | |
| 134 | + pointer>>=2; | |
| 135 | + for(i=0;i<ALLOC_BLOCK_NUM;i++){ | |
| 136 | + if (g_var_pointer[i]==pointer) { | |
| 137 | + g_var_size[i]=0; | |
| 138 | + break; | |
| 139 | + } | |
| 140 | + } | |
| 141 | +} | |
| 142 | + | |
| 143 | +void move_to_perm_block(int var_num){ | |
| 144 | + int i; | |
| 145 | + // Find available permanent block | |
| 146 | + for (i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++){ | |
| 147 | + if (g_var_size[i]==0) break; | |
| 148 | + } | |
| 149 | + if (ALLOC_BLOCK_NUM<=i) err_no_block(); // Not found | |
| 150 | + // Available block found. | |
| 151 | + // Copy value from variable. | |
| 152 | + g_var_size[i]=g_var_size[var_num]; | |
| 153 | + g_var_pointer[i]=g_var_pointer[var_num]; | |
| 154 | + g_var_mem[i]=g_var_mem[var_num]; | |
| 155 | + // Clear variable | |
| 156 | + g_var_size[var_num]=0; | |
| 157 | + g_var_mem[var_num]=0; | |
| 158 | +} | |
| 159 | + | |
| 160 | +void move_from_perm_block(int var_num){ | |
| 161 | + int i,pointer; | |
| 162 | + pointer=(int)g_var_mem[var_num]-(int)g_heap_mem; | |
| 163 | + pointer>>=2; | |
| 164 | + // Find stored block | |
| 165 | + for (i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++){ | |
| 166 | + if (0<g_var_size[i] && g_var_pointer[i]==pointer) break; | |
| 167 | + } | |
| 168 | + if (ALLOC_BLOCK_NUM<=i) err_unknown(); // Not found | |
| 169 | + // Stored block found. | |
| 170 | + // Replace pointer | |
| 171 | + g_var_size[var_num]=g_var_size[i]; | |
| 172 | + g_var_pointer[var_num]=g_var_pointer[i]; | |
| 173 | + // Clear block | |
| 174 | + g_var_size[i]=0; | |
| 175 | +} | |
| \ No newline at end of file |
| @@ -0,0 +1,199 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by K.Tanaka | |
| 4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
| 5 | +*/ | |
| 6 | +// キー入力、カーソル表示関連機能 by K.Tanaka | |
| 7 | +// PS/2キーボード入力システム、カラーテキスト出力システム利用 | |
| 8 | + | |
| 9 | +#include "videoout.h" | |
| 10 | +#include "ps2keyboard.h" | |
| 11 | +#include "keyinput.h" | |
| 12 | + | |
| 13 | +unsigned char lineinputbuf[256]; //lineinput関数用一時バッファ | |
| 14 | +unsigned char blinkchar,blinkcolor; | |
| 15 | +int blinktimer; | |
| 16 | +int insertmode; //挿入モード:1、上書きモード:0 | |
| 17 | + | |
| 18 | +void getcursorchar(){ | |
| 19 | +// カーソル点滅用に元の文字コードを退避 | |
| 20 | + blinkchar=*cursor; | |
| 21 | + blinkcolor=*(cursor+ATTROFFSET); | |
| 22 | +} | |
| 23 | +void resetcursorchar(){ | |
| 24 | +// カーソルを元の文字に戻す | |
| 25 | + *cursor=blinkchar; | |
| 26 | + *(cursor+ATTROFFSET)=blinkcolor; | |
| 27 | +} | |
| 28 | +void blinkcursorchar(){ | |
| 29 | +// 定期的に呼び出すことでカーソルを点滅表示させる | |
| 30 | +// BLINKTIMEで点滅間隔を設定 | |
| 31 | +// 事前にgetcursorchar()を呼び出しておく | |
| 32 | + blinktimer++; | |
| 33 | + if(blinktimer>=BLINKTIME*2) blinktimer=0; | |
| 34 | + if(blinktimer<BLINKTIME){ | |
| 35 | + if(insertmode) *cursor=CURSORCHAR; | |
| 36 | + else *cursor=CURSORCHAR2; | |
| 37 | + *(cursor+ATTROFFSET)=CURSORCOLOR; | |
| 38 | + } | |
| 39 | + else{ | |
| 40 | + *cursor=blinkchar; | |
| 41 | + *(cursor+ATTROFFSET)=blinkcolor; | |
| 42 | + } | |
| 43 | +} | |
| 44 | + | |
| 45 | +unsigned char inputchar(void){ | |
| 46 | +// キーボードから1キー入力待ち | |
| 47 | +// 戻り値 通常文字の場合ASCIIコード、その他は0、グローバル変数vkeyに仮想キーコード | |
| 48 | + unsigned char k; | |
| 49 | + unsigned short d; | |
| 50 | + d=drawcount; | |
| 51 | + while(1){ | |
| 52 | + while(d==drawcount) asm("wait"); //60分の1秒ウェイト | |
| 53 | + d=drawcount; | |
| 54 | + k=ps2readkey(); //キーバッファから読み込み、k1:通常文字入力の場合ASCIIコード | |
| 55 | + if(vkey) return k; | |
| 56 | + } | |
| 57 | +} | |
| 58 | + | |
| 59 | +unsigned char cursorinputchar(void){ | |
| 60 | +// カーソル表示しながらキーボードから1キー入力待ち | |
| 61 | +// 戻り値 通常文字の場合ASCIIコード、その他は0、グローバル変数vkeyに仮想キーコード | |
| 62 | + unsigned char k; | |
| 63 | + unsigned short d; | |
| 64 | + getcursorchar(); //カーソル位置の文字を退避(カーソル点滅用) | |
| 65 | + d=drawcount; | |
| 66 | + while(1){ | |
| 67 | + while(d==drawcount) asm("wait"); //60分の1秒ウェイト | |
| 68 | + d=drawcount; | |
| 69 | + blinkcursorchar(); //カーソル点滅させる | |
| 70 | + k=ps2readkey(); //キーバッファから読み込み、k1:通常文字入力の場合ASCIIコード | |
| 71 | + if(vkey) break; //キーが押された場合ループから抜ける | |
| 72 | + } | |
| 73 | + resetcursorchar(); //カーソルを元の文字表示に戻す | |
| 74 | + return k; | |
| 75 | +} | |
| 76 | + | |
| 77 | +unsigned char printinputchar(void){ | |
| 78 | +// カーソル表示しながらキーボードから通常文字キー入力待ちし、入力された文字を表示 | |
| 79 | +// 戻り値 入力された文字のASCIIコード、グローバル変数vkeyに最後に押されたキーの仮想キーコード | |
| 80 | + unsigned char k; | |
| 81 | + while(1){ | |
| 82 | + k=cursorinputchar(); | |
| 83 | + if(k) break; | |
| 84 | + } | |
| 85 | + printchar(k); | |
| 86 | + return k; | |
| 87 | +} | |
| 88 | + | |
| 89 | +int lineinput(char *s,int n){ | |
| 90 | +// キー入力して文字列配列sに格納 | |
| 91 | +// sに初期文字列を入れておくと最初に表示して文字列の最後にカーソル移動する | |
| 92 | +// 初期文字列を使用しない場合は*s=0としておく | |
| 93 | +// カーソル位置はsetcursor関数で指定しておく | |
| 94 | +// 最大文字数n、最後に0を格納するのでn+1バイトの領域必要、ただしnの最大値は255 | |
| 95 | +// 戻り値 Enterで終了した場合0、ESCで終了時は-1(sは壊さない) | |
| 96 | +// | |
| 97 | + unsigned char *ps,*pd,*pc; | |
| 98 | + unsigned char k1,k2; | |
| 99 | + int i; | |
| 100 | + | |
| 101 | + if(n>255) return -1; | |
| 102 | + ps=s; | |
| 103 | + pd=lineinputbuf; | |
| 104 | + i=0; | |
| 105 | + //初期文字列をlineinputbufにコピーし、文字数をiに入れる | |
| 106 | + while(*ps!=0 && i<n){ | |
| 107 | + *pd++=*ps++; | |
| 108 | + i++; | |
| 109 | + } | |
| 110 | + *pd=0;//バッファ内の文字列最後に0 | |
| 111 | + pc=pd;//現在の文字入力位置ポインタ(最後尾) | |
| 112 | + if(i>0) printstr(lineinputbuf); //初期文字列表示 | |
| 113 | + while(1){ | |
| 114 | + k1=cursorinputchar(); //カーソル表示しながら1キー入力待ち | |
| 115 | + k2=(unsigned char)vkey; //k2:仮想キーコード | |
| 116 | + if(k1){ | |
| 117 | + //通常文字の場合 | |
| 118 | + if(insertmode || *pc==0){ | |
| 119 | + //挿入モードまたは最後尾の場合 | |
| 120 | + if(i==n) continue; //入力文字数最大値の場合無視 | |
| 121 | + for(pd=lineinputbuf+i;pd>=pc;pd--) *(pd+1)=*pd; //1文字分挿入 | |
| 122 | + i++; | |
| 123 | + } | |
| 124 | + *pc=k1; //入力文字を追加 | |
| 125 | + printstr(pc); //入力文字以降を表示 | |
| 126 | + pc++; | |
| 127 | + for(ps=lineinputbuf+i;ps>pc;ps--) cursor--; //カーソル位置戻し | |
| 128 | + } | |
| 129 | + else switch(k2){ | |
| 130 | + //制御文字の場合 | |
| 131 | + case VK_LEFT: | |
| 132 | + case VK_NUMPAD4: | |
| 133 | + //左矢印キー | |
| 134 | + if(pc>lineinputbuf){ | |
| 135 | + pc--; | |
| 136 | + cursor--; | |
| 137 | + } | |
| 138 | + break; | |
| 139 | + case VK_RIGHT: | |
| 140 | + case VK_NUMPAD6: | |
| 141 | + //右矢印キー | |
| 142 | + if(*pc!=0){ | |
| 143 | + pc++; | |
| 144 | + cursor++; | |
| 145 | + } | |
| 146 | + break; | |
| 147 | + case VK_RETURN: //Enterキー | |
| 148 | + case VK_SEPARATOR: //テンキーのEnter | |
| 149 | + //入力用バッファから呼び出し元のバッファにコピーして終了 | |
| 150 | + printchar('\n'); | |
| 151 | + ps=lineinputbuf; | |
| 152 | + pd=s; | |
| 153 | + while(*ps!=0) *pd++=*ps++; | |
| 154 | + *pd=0; | |
| 155 | + return 0; | |
| 156 | + case VK_HOME: | |
| 157 | + case VK_NUMPAD7: | |
| 158 | + //Homeキー、文字列先頭にカーソル移動 | |
| 159 | + while(pc>lineinputbuf){ | |
| 160 | + pc--; | |
| 161 | + cursor--; | |
| 162 | + } | |
| 163 | + break; | |
| 164 | + case VK_END: | |
| 165 | + case VK_NUMPAD1: | |
| 166 | + //Endキー、文字列最後尾にカーソル移動 | |
| 167 | + while(*pc!=0){ | |
| 168 | + pc++; | |
| 169 | + cursor++; | |
| 170 | + } | |
| 171 | + break; | |
| 172 | + case VK_BACK: | |
| 173 | + //Back Spaceキー、1文字左に移動しDelete処理 | |
| 174 | + if(pc==lineinputbuf) break;//カーソルが先頭の場合、無視 | |
| 175 | + pc--; | |
| 176 | + cursor--; | |
| 177 | + case VK_DELETE: | |
| 178 | + case VK_DECIMAL: | |
| 179 | + //Deleteキー、カーソル位置の1文字削除 | |
| 180 | + if(*pc==0) break;//カーソルが最後尾の場合、無視 | |
| 181 | + for(pd=pc;*(pd+1)!=0;pd++) *pd=*(pd+1); | |
| 182 | + *pd=0; | |
| 183 | + i--; | |
| 184 | + printstr(pc); | |
| 185 | + printchar(0);//NULL文字表示 | |
| 186 | + for(ps=lineinputbuf+i+1;ps>pc;ps--) cursor--; | |
| 187 | + break; | |
| 188 | + case VK_INSERT: | |
| 189 | + case VK_NUMPAD0: | |
| 190 | + //Insertキー、挿入モードトグル動作 | |
| 191 | + insertmode^=1; | |
| 192 | + break; | |
| 193 | + case VK_ESCAPE: | |
| 194 | + case VK_CANCEL: | |
| 195 | + //ESCキーまたはCTRL+Breakキー、-1で終了 | |
| 196 | + return -1; | |
| 197 | + } | |
| 198 | + } | |
| 199 | +} |
| @@ -0,0 +1,174 @@ | ||
| 1 | +#define CHK_SHIFT 0x01 | |
| 2 | +#define CHK_CTRL 0x02 | |
| 3 | +#define CHK_ALT 0x04 | |
| 4 | +#define CHK_WIN 0x08 | |
| 5 | +#define CHK_SCRLK 0x10 | |
| 6 | +#define CHK_NUMLK 0x20 | |
| 7 | +#define CHK_CAPSLK 0x40 | |
| 8 | +#define CHK_SHIFT_L 0x01 | |
| 9 | +#define CHK_SHIFT_R 0x02 | |
| 10 | +#define CHK_CTRL_L 0x04 | |
| 11 | +#define CHK_CTRL_R 0x08 | |
| 12 | +#define CHK_ALT_L 0x10 | |
| 13 | +#define CHK_ALT_R 0x20 | |
| 14 | +#define CHK_WIN_L 0x40 | |
| 15 | +#define CHK_WIN_R 0x80 | |
| 16 | +#define CHK_SCRLK_A 0x100 | |
| 17 | +#define CHK_NUMLK_A 0x200 | |
| 18 | +#define CHK_CAPSLK_A 0x400 | |
| 19 | + | |
| 20 | +#define VK_LBUTTON 0x01 | |
| 21 | +#define VK_RBUTTON 0x02 | |
| 22 | +#define VK_CANCEL 0x03 | |
| 23 | +#define VK_MBUTTON 0x04 | |
| 24 | +#define VK_XBUTTON1 0x05 | |
| 25 | +#define VK_XBUTTON2 0x06 | |
| 26 | +#define VK_BACK 0x08 | |
| 27 | +#define VK_TAB 0x09 | |
| 28 | +#define VK_CLEAR 0x0C | |
| 29 | +#define VK_RETURN 0x0D | |
| 30 | +#define VK_SHIFT 0x10 | |
| 31 | +#define VK_CONTROL 0x11 | |
| 32 | +#define VK_MENU 0x12 | |
| 33 | +#define VK_PAUSE 0x13 | |
| 34 | +#define VK_CAPITAL 0x14 | |
| 35 | +#define VK_KANA 0x15 | |
| 36 | +#define VK_HANGUEL 0x15 | |
| 37 | +#define VK_HANGUL 0x15 | |
| 38 | +#define VK_JUNJA 0x17 | |
| 39 | +#define VK_FINAL 0x18 | |
| 40 | +#define VK_HANJA 0x19 | |
| 41 | +#define VK_KANJI 0x19 | |
| 42 | +#define VK_ESCAPE 0x1B | |
| 43 | +#define VK_CONVERT 0x1C | |
| 44 | +#define VK_NONCONVERT 0x1D | |
| 45 | +#define VK_ACCEPT 0x1E | |
| 46 | +#define VK_MODECHANGE 0x1F | |
| 47 | +#define VK_SPACE 0x20 | |
| 48 | +#define VK_PRIOR 0x21 | |
| 49 | +#define VK_NEXT 0x22 | |
| 50 | +#define VK_END 0x23 | |
| 51 | +#define VK_HOME 0x24 | |
| 52 | +#define VK_LEFT 0x25 | |
| 53 | +#define VK_UP 0x26 | |
| 54 | +#define VK_RIGHT 0x27 | |
| 55 | +#define VK_DOWN 0x28 | |
| 56 | +#define VK_SELECT 0x29 | |
| 57 | +#define VK_PRINT 0x2A | |
| 58 | +#define VK_EXECUTE 0x2B | |
| 59 | +#define VK_SNAPSHOT 0x2C | |
| 60 | +#define VK_INSERT 0x2D | |
| 61 | +#define VK_DELETE 0x2E | |
| 62 | +#define VK_HELP 0x2F | |
| 63 | +#define VK_LWIN 0x5B | |
| 64 | +#define VK_RWIN 0x5C | |
| 65 | +#define VK_APPS 0x5D | |
| 66 | +#define VK_SLEEP 0x5F | |
| 67 | +#define VK_NUMPAD0 0x60 | |
| 68 | +#define VK_NUMPAD1 0x61 | |
| 69 | +#define VK_NUMPAD2 0x62 | |
| 70 | +#define VK_NUMPAD3 0x63 | |
| 71 | +#define VK_NUMPAD4 0x64 | |
| 72 | +#define VK_NUMPAD5 0x65 | |
| 73 | +#define VK_NUMPAD6 0x66 | |
| 74 | +#define VK_NUMPAD7 0x67 | |
| 75 | +#define VK_NUMPAD8 0x68 | |
| 76 | +#define VK_NUMPAD9 0x69 | |
| 77 | +#define VK_MULTIPLY 0x6A | |
| 78 | +#define VK_ADD 0x6B | |
| 79 | +#define VK_SEPARATOR 0x6C | |
| 80 | +#define VK_SUBTRACT 0x6D | |
| 81 | +#define VK_DECIMAL 0x6E | |
| 82 | +#define VK_DIVIDE 0x6F | |
| 83 | +#define VK_F1 0x70 | |
| 84 | +#define VK_F2 0x71 | |
| 85 | +#define VK_F3 0x72 | |
| 86 | +#define VK_F4 0x73 | |
| 87 | +#define VK_F5 0x74 | |
| 88 | +#define VK_F6 0x75 | |
| 89 | +#define VK_F7 0x76 | |
| 90 | +#define VK_F8 0x77 | |
| 91 | +#define VK_F9 0x78 | |
| 92 | +#define VK_F10 0x79 | |
| 93 | +#define VK_F11 0x7A | |
| 94 | +#define VK_F12 0x7B | |
| 95 | +#define VK_F13 0x7C | |
| 96 | +#define VK_F14 0x7D | |
| 97 | +#define VK_F15 0x7E | |
| 98 | +#define VK_F16 0x7F | |
| 99 | +#define VK_F17 0x80 | |
| 100 | +#define VK_F18 0x81 | |
| 101 | +#define VK_F19 0x82 | |
| 102 | +#define VK_F20 0x83 | |
| 103 | +#define VK_F21 0x84 | |
| 104 | +#define VK_F22 0x85 | |
| 105 | +#define VK_F23 0x86 | |
| 106 | +#define VK_F24 0x87 | |
| 107 | +#define VK_NUMLOCK 0x90 | |
| 108 | +#define VK_SCROLL 0x91 | |
| 109 | +#define VK_LSHIFT 0xA0 | |
| 110 | +#define VK_RSHIFT 0xA1 | |
| 111 | +#define VK_LCONTROL 0xA2 | |
| 112 | +#define VK_RCONTROL 0xA3 | |
| 113 | +#define VK_LMENU 0xA4 | |
| 114 | +#define VK_RMENU 0xA5 | |
| 115 | +#define VK_BROWSER_BACK 0xA6 | |
| 116 | +#define VK_BROWSER_FORWARD 0xA7 | |
| 117 | +#define VK_BROWSER_REFRESH 0xA8 | |
| 118 | +#define VK_BROWSER_STOP 0xA9 | |
| 119 | +#define VK_BROWSER_SEARCH 0xAA | |
| 120 | +#define VK_BROWSER_FAVORITES 0xAB | |
| 121 | +#define VK_BROWSER_HOME 0xAC | |
| 122 | +#define VK_VOLUME_MUTE 0xAD | |
| 123 | +#define VK_VOLUME_DOWN 0xAE | |
| 124 | +#define VK_VOLUME_UP 0xAF | |
| 125 | +#define VK_MEDIA_NEXT_TRACK 0xB0 | |
| 126 | +#define VK_MEDIA_PREV_TRACK 0xB1 | |
| 127 | +#define VK_MEDIA_STOP 0xB2 | |
| 128 | +#define VK_MEDIA_PLAY_PAUSE 0xB3 | |
| 129 | +#define VK_LAUNCH_MAIL 0xB4 | |
| 130 | +#define VK_LAUNCH_MEDIA_SELECT 0xB5 | |
| 131 | +#define VK_LAUNCH_APP1 0xB6 | |
| 132 | +#define VK_LAUNCH_APP2 0xB7 | |
| 133 | +#define VK_OEM_1 0xBA | |
| 134 | +#define VK_OEM_PLUS 0xBB | |
| 135 | +#define VK_OEM_COMMA 0xBC | |
| 136 | +#define VK_OEM_MINUS 0xBD | |
| 137 | +#define VK_OEM_PERIOD 0xBE | |
| 138 | +#define VK_OEM_2 0xBF | |
| 139 | +#define VK_OEM_3 0xC0 | |
| 140 | +#define VK_OEM_4 0xDB | |
| 141 | +#define VK_OEM_5 0xDC | |
| 142 | +#define VK_OEM_6 0xDD | |
| 143 | +#define VK_OEM_7 0xDE | |
| 144 | +#define VK_OEM_8 0xDF | |
| 145 | +#define VK_OEM_102 0xE2 | |
| 146 | +#define VK_PROCESSKEY 0xE5 | |
| 147 | +#define VK_PACKE 0xE7 | |
| 148 | +#define VK_ATTN 0xF6 | |
| 149 | +#define VK_CRSEL 0xF7 | |
| 150 | +#define VK_EXSEL 0xF8 | |
| 151 | +#define VK_EREOF 0xF9 | |
| 152 | +#define VK_PLAY 0xFA | |
| 153 | +#define VK_ZOOM 0xFB | |
| 154 | +#define VK_NONAME 0xFC | |
| 155 | +#define VK_PA1 0xFD | |
| 156 | +#define VK_OEM_CLEAR 0xFE | |
| 157 | + | |
| 158 | +extern volatile unsigned char ps2keystatus[256]; // 仮想コードに相当するキーの状態(Onの時1) | |
| 159 | +extern volatile unsigned short vkey; //仮想キーコード | |
| 160 | +extern unsigned char lockkey; // 初期化時にLockキーの状態指定。下位3ビットが<CAPSLK><NUMLK><SCRLK> | |
| 161 | +extern unsigned char keytype; // キーボードの種類。0:日本語109キー、1:英語104キー | |
| 162 | + | |
| 163 | +int ps2init(); // PS/2ライブラリ関連初期化。正常終了0、エラーで-1を返す | |
| 164 | +unsigned char shiftkeys(); // SHIFT関連キーの押下状態を返す | |
| 165 | +unsigned char ps2readkey(); | |
| 166 | +// 入力された1つのキーのキーコードをグローバル変数vkeyに格納(押されていなければ0を返す) | |
| 167 | +// 下位8ビット:キーコード | |
| 168 | +// 上位8ビット:シフト状態(押下:1)、上位から<0><CAPSLK><NUMLK><SCRLK><Win><ALT><CTRL><SHIFT> | |
| 169 | +// 英数・記号文字の場合、戻り値としてASCIIコード(それ以外は0を返す) | |
| 170 | + | |
| 171 | +// PIC32MX1xx/2xx版のキーボードとボタンの排他利用システムで使用する関数、マクロ | |
| 172 | +void ps2mode(); // PS/2を有効にする | |
| 173 | +void buttonmode(); // ボタンを有効にする | |
| 174 | +#define inPS2MODE() ((LATA&2)>>1) // モード確認用マクロ。PS/2モードの場合1、ボタンモードの場合0を返す |
| @@ -0,0 +1,45 @@ | ||
| 1 | +/* | |
| 2 | + This file is provided under the LGPL license ver 2.1. | |
| 3 | + Written by K.Tanaka | |
| 4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
| 5 | +*/ | |
| 6 | + | |
| 7 | +#define BLINKTIME 15 | |
| 8 | +#define CURSORCHAR 0x87 | |
| 9 | +#define CURSORCHAR2 0x80 | |
| 10 | +#define CURSORCOLOR 7 | |
| 11 | + | |
| 12 | +void getcursorchar(); | |
| 13 | +// カーソル点滅用に元の文字コードを退避 | |
| 14 | + | |
| 15 | +void resetcursorchar(); | |
| 16 | +// カーソルを元の文字に戻す | |
| 17 | + | |
| 18 | +void blinkcursorchar(); | |
| 19 | +// 定期的に呼び出すことでカーソルを点滅表示させる | |
| 20 | +// BLINKTIMEで点滅間隔を設定 | |
| 21 | +// 事前にgetcursorchar()を呼び出しておく | |
| 22 | + | |
| 23 | +int lineinput(char *s,int n); | |
| 24 | +// キー入力して文字列配列sに格納 | |
| 25 | +// sに初期文字列を入れておくと最初に表示して文字列の最後にカーソル移動する | |
| 26 | +// 初期文字列を使用しない場合は*s=0としておく | |
| 27 | +// カーソル位置はsetcursor関数で指定しておく | |
| 28 | +// 最大文字数n、最後に0を格納するのでn+1バイトの領域必要、ただしnの最大値は255 | |
| 29 | +// 戻り値 Enterで終了した場合0、ESCで終了時は-1(sは壊さない) | |
| 30 | + | |
| 31 | +unsigned char inputchar(void); | |
| 32 | +// キーボードから1キー入力待ち | |
| 33 | +// 戻り値 通常文字の場合ASCIIコード、その他は0、グローバル変数vkeyに仮想キーコード | |
| 34 | + | |
| 35 | +unsigned char printinputchar(void); | |
| 36 | +// カーソル表示しながらキーボードから通常文字キー入力待ちし、入力された文字を表示 | |
| 37 | +// 戻り値 入力された文字のASCIIコード、グローバル変数vkeyに最後に押されたキーの仮想キーコード | |
| 38 | + | |
| 39 | +unsigned char cursorinputchar(void); | |
| 40 | +// カーソル表示しながらキーボードから1キー入力待ち | |
| 41 | +// 戻り値 通常文字の場合ASCIIコード、その他は0、グローバル変数vkeyに仮想キーコード | |
| 42 | + | |
| 43 | +extern unsigned char blinkchar,blinkcolor; | |
| 44 | +extern int blinktimer; | |
| 45 | +extern int insertmode; //挿入モード:1、上書きモード:0 |
| @@ -0,0 +1,2344 @@ | ||
| 1 | +/****************************************************************************** | |
| 2 | + * | |
| 3 | + * Microchip Memory Disk Drive File System | |
| 4 | + * | |
| 5 | + ****************************************************************************** | |
| 6 | + * FileName: FSIO.h | |
| 7 | + * Dependencies: GenericTypeDefs.h | |
| 8 | + * FSconfig.h | |
| 9 | + * FSDefs.h | |
| 10 | + * stddef.h | |
| 11 | + * Processor: PIC18/PIC24/dsPIC30/dsPIC33/PIC32 | |
| 12 | + * Compiler: C18/C30/C32 | |
| 13 | + * Company: Microchip Technology, Inc. | |
| 14 | + * Version: 1.3.0 | |
| 15 | + * | |
| 16 | + * Software License Agreement | |
| 17 | + * | |
| 18 | + * The software supplied herewith by Microchip Technology Incorporated | |
| 19 | + * (the 鼎ompany・ for its PICmicroョ Microcontroller is intended and | |
| 20 | + * supplied to you, the Company痴 customer, for use solely and | |
| 21 | + * exclusively on Microchip PICmicro Microcontroller products. The | |
| 22 | + * software is owned by the Company and/or its supplier, and is | |
| 23 | + * protected under applicable copyright laws. All rights are reserved. | |
| 24 | + * Any use in violation of the foregoing restrictions may subject the | |
| 25 | + * user to criminal sanctions under applicable laws, as well as to | |
| 26 | + * civil liability for the breach of the terms and conditions of this | |
| 27 | + * license. | |
| 28 | + * | |
| 29 | + * THIS SOFTWARE IS PROVIDED IN AN 鄭S IS・CONDITION. NO WARRANTIES, | |
| 30 | + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED | |
| 31 | + * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | |
| 32 | + * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, | |
| 33 | + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR | |
| 34 | + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. | |
| 35 | + * | |
| 36 | +*****************************************************************************/ | |
| 37 | + | |
| 38 | +#ifndef FS_DOT_H | |
| 39 | +#define FS_DOT_H | |
| 40 | + | |
| 41 | +#define ALLOW_FILESEARCH | |
| 42 | +#define ALLOW_WRITES | |
| 43 | +#define ALLOW_DIRS | |
| 44 | +#define SUPPORT_FAT32 | |
| 45 | + | |
| 46 | +#define MDD_MediaInitialize MDD_SDSPI_MediaInitialize | |
| 47 | +#define MDD_MediaDetect MDD_SDSPI_MediaDetect | |
| 48 | +#define MDD_SectorRead MDD_SDSPI_SectorRead | |
| 49 | +#define MDD_SectorWrite MDD_SDSPI_SectorWrite | |
| 50 | +#define MDD_InitIO MDD_SDSPI_InitIO | |
| 51 | +#define MDD_ShutdownMedia MDD_SDSPI_ShutdownMedia | |
| 52 | +#define MDD_WriteProtectState MDD_SDSPI_WriteProtectState | |
| 53 | + | |
| 54 | +// Summary: An enumeration used for various error codes. | |
| 55 | +// Description: The CETYPE enumeration is used to indicate different error conditions during device operation. | |
| 56 | +typedef enum _CETYPE | |
| 57 | +{ | |
| 58 | + CE_GOOD = 0, // No error | |
| 59 | + CE_ERASE_FAIL, // An erase failed | |
| 60 | + CE_NOT_PRESENT, // No device was present | |
| 61 | + CE_NOT_FORMATTED, // The disk is of an unsupported format | |
| 62 | + CE_BAD_PARTITION, // The boot record is bad | |
| 63 | + CE_UNSUPPORTED_FS, // The file system type is unsupported | |
| 64 | + CE_INIT_ERROR, // An initialization error has occured | |
| 65 | + CE_NOT_INIT, // An operation was performed on an uninitialized device | |
| 66 | + CE_BAD_SECTOR_READ, // A bad read of a sector occured | |
| 67 | + CE_WRITE_ERROR, // Could not write to a sector | |
| 68 | + CE_INVALID_CLUSTER, // Invalid cluster value > maxcls | |
| 69 | + CE_FILE_NOT_FOUND, // Could not find the file on the device | |
| 70 | + CE_DIR_NOT_FOUND, // Could not find the directory | |
| 71 | + CE_BAD_FILE, // File is corrupted | |
| 72 | + CE_DONE, // No more files in this directory | |
| 73 | + CE_COULD_NOT_GET_CLUSTER, // Could not load/allocate next cluster in file | |
| 74 | + CE_FILENAME_2_LONG, // A specified file name is too long to use | |
| 75 | + CE_FILENAME_EXISTS, // A specified filename already exists on the device | |
| 76 | + CE_INVALID_FILENAME, // Invalid file name | |
| 77 | + CE_DELETE_DIR, // The user tried to delete a directory with FSremove | |
| 78 | + CE_DIR_FULL, // All root dir entry are taken | |
| 79 | + CE_DISK_FULL, // All clusters in partition are taken | |
| 80 | + CE_DIR_NOT_EMPTY, // This directory is not empty yet, remove files before deleting | |
| 81 | + CE_NONSUPPORTED_SIZE, // The disk is too big to format as FAT16 | |
| 82 | + CE_WRITE_PROTECTED, // Card is write protected | |
| 83 | + CE_FILENOTOPENED, // File not opened for the write | |
| 84 | + CE_SEEK_ERROR, // File location could not be changed successfully | |
| 85 | + CE_BADCACHEREAD, // Bad cache read | |
| 86 | + CE_CARDFAT32, // FAT 32 - card not supported | |
| 87 | + CE_READONLY, // The file is read-only | |
| 88 | + CE_WRITEONLY, // The file is write-only | |
| 89 | + CE_INVALID_ARGUMENT, // Invalid argument | |
| 90 | + CE_TOO_MANY_FILES_OPEN, // Too many files are already open | |
| 91 | + CE_UNSUPPORTED_SECTOR_SIZE // Unsupported sector size | |
| 92 | +} CETYPE; | |
| 93 | + | |
| 94 | + | |
| 95 | +// Summary: A macro indicating a dir entry was found | |
| 96 | +// Description: The FOUND macro indicates that a directory entry was found in the specified position | |
| 97 | +#define FOUND 0 | |
| 98 | + | |
| 99 | +// Summary: A macro indicating no dir entry was found | |
| 100 | +// Description: The NOT_FOUND macro indicates that the specified directory entry to load was deleted | |
| 101 | +#define NOT_FOUND 1 | |
| 102 | + | |
| 103 | +// Summary: A macro indicating that no more files were found | |
| 104 | +// Description: The NO_MORE macro indicates that there are no more directory entries to search for | |
| 105 | +#define NO_MORE 2 | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | +// Summary: A macro indicating the device is formatted with FAT12 | |
| 110 | +// Description: The FAT12 macro is used to indicate that the file system on the device being accessed is a FAT12 file system. | |
| 111 | +#define FAT12 1 | |
| 112 | + | |
| 113 | +// Summary: A macro indicating the device is formatted with FAT16 | |
| 114 | +// Description: The FAT16 macro is used to indicate that the file system on the device being accessed is a FAT16 file system. | |
| 115 | +#define FAT16 2 | |
| 116 | + | |
| 117 | +// Summary: A macro indicating the device is formatted with FAT32 | |
| 118 | +// Description: The FAT32 macro is used to indicate that the file system on the device being accessed is a FAT32 file system. | |
| 119 | +#define FAT32 3 | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | +// Summary: A read-only attribute macro | |
| 124 | +// Description: A macro for the read-only attribute. A file with this attribute should not be written to. Note that this | |
| 125 | +// attribute will not actually prevent a write to the file; that functionality is operating-system dependant. The | |
| 126 | +// user should take care not to write to a read-only file. | |
| 127 | +#define ATTR_READ_ONLY 0x01 | |
| 128 | + | |
| 129 | +// Summary: A hidden attribute macro | |
| 130 | +// Description: A macro for the hidden attribute. A file with this attribute may be hidden from the user, depending on the | |
| 131 | +// implementation of the operating system. | |
| 132 | +#define ATTR_HIDDEN 0x02 | |
| 133 | + | |
| 134 | +// Summary: A system attribute macro | |
| 135 | +// Description: A macro for the system attribute. A file with this attribute is used by the operating system, and should not be | |
| 136 | +// modified. Note that this attribute will not actually prevent a write to the file. | |
| 137 | +#define ATTR_SYSTEM 0x04 | |
| 138 | + | |
| 139 | +// Summary: A volume attribute macro | |
| 140 | +// Description: A macro for the volume attribute. If the first directory entry in the root directory has the volume attribute set, | |
| 141 | +// the device will use the name in that directory entry as the volume name. | |
| 142 | +#define ATTR_VOLUME 0x08 | |
| 143 | + | |
| 144 | +// Summary: A macro for the attributes for a long-file name entry | |
| 145 | +// Description: A macro for the long-name attributes. If a directory entry is used in a long-file name implementation, it will have | |
| 146 | +// all four lower bits set. This indicates that any software that does not support long file names should ignore that | |
| 147 | +// entry. | |
| 148 | +#define ATTR_LONG_NAME 0x0f | |
| 149 | + | |
| 150 | +// Summary: A directory attribute macro | |
| 151 | +// Description: A macro for the directory attribute. If a directory entry has this attribute set, the file it points to is a directory- | |
| 152 | +// type file, and will contain directory entries that point to additional directories or files. | |
| 153 | +#define ATTR_DIRECTORY 0x10 | |
| 154 | + | |
| 155 | +// Summary: An archive attribute macro | |
| 156 | +// Description: A macro for the archive attribute. This attribute will indicate to some archiving programs that the file with this | |
| 157 | +// attribute needs to be backed up. Most operating systems create files with the archive attribute set. | |
| 158 | +#define ATTR_ARCHIVE 0x20 | |
| 159 | + | |
| 160 | +// Summary: A macro for all attributes | |
| 161 | +// Description: A macro for all attributes. The search functions in this library require an argument that determines which attributes | |
| 162 | +// a file is allowed to have in order to be found. If ATTR_MASK is specified as this argument, any file may be found, regardless | |
| 163 | +// of its attributes. | |
| 164 | +#define ATTR_MASK 0x3f | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | +// Summary: A macro to indicate an empty FAT entry | |
| 169 | +// Description: The CLUSTER_EMPTY value is used to indicate that a FAT entry and it's corresponding cluster are available. | |
| 170 | +#define CLUSTER_EMPTY 0x0000 | |
| 171 | + | |
| 172 | +// Summary: A macro to indicate the last cluster value for FAT12 | |
| 173 | +// Description: The LAST_CLUSTER_FAT12 macro is used when reading the FAT to indicate that the next FAT12 entry for a file contains | |
| 174 | +// the end-of-file value. | |
| 175 | +#define LAST_CLUSTER_FAT12 0xff8 | |
| 176 | + | |
| 177 | +// Summary: A macro to indicate the last cluster value for FAT16 | |
| 178 | +// Description: The LAST_CLUSTER_FAT16 macro is used when reading the FAT to indicate that the next FAT16 entry for a file contains | |
| 179 | +// the end-of-file value. | |
| 180 | +#define LAST_CLUSTER_FAT16 0xfff8 | |
| 181 | + | |
| 182 | +// Summary: A macro to indicate the last allocatable cluster for FAT12 | |
| 183 | +// Description: The END_CLUSTER_FAT12 value is used as a comparison in FAT12 to determine that the firmware has reached the end of | |
| 184 | +// the range of allowed allocatable clusters. | |
| 185 | +#define END_CLUSTER_FAT12 0xFF7 | |
| 186 | + | |
| 187 | +// Summary: A macro to indicate the last allocatable cluster for FAT16 | |
| 188 | +// Description: The END_CLUSTER_FAT16 value is used as a comparison in FAT16 to determine that the firmware has reached the end of | |
| 189 | +// the range of allowed allocatable clusters. | |
| 190 | +#define END_CLUSTER_FAT16 0xFFF7 | |
| 191 | + | |
| 192 | +// Summary: A macro to indicate the failure of the ReadFAT function | |
| 193 | +// Description: The CLUSTER_FAIL_FAT16 macro is used by the ReadFAT function to indicate that an error occured reading a FAT12 or FAT16 | |
| 194 | +// file allocation table. Note that since '0xFFF8' is used for the last cluster return value in the FAT16 implementation | |
| 195 | +// the end-of-file value '0xFFFF' can be used to indicate an error condition. | |
| 196 | +#define CLUSTER_FAIL_FAT16 0xFFFF | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | +#ifdef SUPPORT_FAT32 | |
| 201 | + // Summary: A macro to indicate the last cluster value for FAT32 | |
| 202 | + // Description: The LAST_CLUSTER_FAT32 macro is used when reading the FAT to indicate that the next FAT32 entry for a file contains | |
| 203 | + // the end-of-file value. | |
| 204 | + #define LAST_CLUSTER_FAT32 0x0FFFFFF8 | |
| 205 | + | |
| 206 | + // Summary: A macro to indicate the last allocatable cluster for FAT32 | |
| 207 | + // Description: The END_CLUSTER_FAT32 value is used as a comparison in FAT32 to determine that the firmware has reached the end of | |
| 208 | + // the range of allowed allocatable clusters. | |
| 209 | + #define END_CLUSTER_FAT32 0x0FFFFFF7 | |
| 210 | + | |
| 211 | + // Summary: A macro to indicate the failure of the ReadFAT function | |
| 212 | + // Description: The CLUSTER_FAIL_FAT32 macro is used by the ReadFAT function to indicate that an error occured reading a FAT32 | |
| 213 | + // file allocation able. | |
| 214 | + #define CLUSTER_FAIL_FAT32 0x0FFFFFFF | |
| 215 | + | |
| 216 | +#endif | |
| 217 | + | |
| 218 | +// Summary: A macro indicating the number of bytes in a directory entry. | |
| 219 | +// Description: The NUMBER_OF_BYTES_IN_DIR_ENTRY macro represents the number of bytes in one directory entry. It is used to calculate | |
| 220 | +// the number of sectors in the root directory based on information in the boot sector. | |
| 221 | +#define NUMBER_OF_BYTES_IN_DIR_ENTRY 32 | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | +// Summary: A macro for a deleted dir entry marker. | |
| 226 | +// Description: The DIR_DEL macro is used to mark a directory entry as deleted. When a file is deleted, this value will replace the | |
| 227 | +// first character in the file name, and will indicate that the file the entry points to was deleted. | |
| 228 | +#define DIR_DEL 0xE5 | |
| 229 | + | |
| 230 | +// Summary: A macro for the last dir entry marker. | |
| 231 | +// Description: The DIR_EMPTY macro is used to indicate the last entry in a directory. Since entries in use cannot start with a 0 and | |
| 232 | +// deleted entries start with the DIR_DEL character, a 0 will mark the end of the in-use or previously used group of | |
| 233 | +// entries in a directory | |
| 234 | +#define DIR_EMPTY 0 | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | +// Summary: A macro used to indicate the length of an 8.3 file name | |
| 239 | +// Description: The DIR_NAMESIZE macro is used when validing the name portion of 8.3 filenames | |
| 240 | +#define DIR_NAMESIZE 8 | |
| 241 | + | |
| 242 | +// Summary: A macro used to indicate the length of an 8.3 file extension | |
| 243 | +// Description: The DIR_EXTENSION macro is used when validating the extension portion of 8.3 filenames | |
| 244 | +#define DIR_EXTENSION 3 | |
| 245 | + | |
| 246 | +// Summary: A macro used to indicate the length of an 8.3 file name and extension | |
| 247 | +// Description: The DIR_NAMECOMP macro is used when validating 8.3 filenames | |
| 248 | +#define DIR_NAMECOMP (DIR_NAMESIZE+DIR_EXTENSION) | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | +// Summary: A macro to write a byte to RAM | |
| 253 | +// Description: The RAMwrite macro is used to write a byte of data to a RAM array | |
| 254 | +#define RAMwrite( a, f, d) *(a+f) = d | |
| 255 | + | |
| 256 | +// Summary: A macro to read a byte from RAM | |
| 257 | +// Description: The RAMread macro is used to read a byte of data from a RAM array | |
| 258 | +#define RAMread( a, f) *(a+f) | |
| 259 | + | |
| 260 | +// Summary: A macro to read a 16-bit word from RAM | |
| 261 | +// Description: The RAMreadW macro is used to read two bytes of data from a RAM array | |
| 262 | +#define RAMreadW( a, f) *(WORD *)(a+f) | |
| 263 | + | |
| 264 | +// Summary: A macro to read a 32-bit word from RAM | |
| 265 | +// Description: The RAMreadD macro is used to read four bytes of data from a RAM array | |
| 266 | +#define RAMreadD( a, f) *(DWORD *)(a+f) | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | +#ifndef EOF | |
| 271 | + // Summary: Indicates error conditions or end-of-file conditions | |
| 272 | + // Description: The EOF macro is used to indicate error conditions in some function calls. It is also used to indicate | |
| 273 | + // that the end-of-file has been reached. | |
| 274 | + #define EOF ((int)-1) | |
| 275 | +#endif | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | +// Summary: A structure containing information about the device. | |
| 280 | +// Description: The DISK structure contains information about the device being accessed. | |
| 281 | +typedef struct | |
| 282 | +{ | |
| 283 | + BYTE * buffer; // Address of the global data buffer used to read and write file information | |
| 284 | + DWORD firsts; // Logical block address of the first sector of the FAT partition on the device | |
| 285 | + DWORD fat; // Logical block address of the FAT | |
| 286 | + DWORD root; // Logical block address of the root directory | |
| 287 | + DWORD data; // Logical block address of the data section of the device. | |
| 288 | + WORD maxroot; // The maximum number of entries in the root directory. | |
| 289 | + DWORD maxcls; // The maximum number of clusters in the partition. | |
| 290 | + DWORD sectorSize; // The size of a sector in bytes | |
| 291 | + DWORD fatsize; // The number of sectors in the FAT | |
| 292 | + BYTE fatcopy; // The number of copies of the FAT in the partition | |
| 293 | + BYTE SecPerClus; // The number of sectors per cluster in the data region | |
| 294 | + BYTE type; // The file system type of the partition (FAT12, FAT16 or FAT32) | |
| 295 | + BYTE mount; // Device mount flag (TRUE if disk was mounted successfully, FALSE otherwise) | |
| 296 | +#if defined __PIC32MX__ || defined __C30__ | |
| 297 | +} __attribute__ ((packed)) DISK; | |
| 298 | +#else | |
| 299 | +} DISK; | |
| 300 | +#endif | |
| 301 | + | |
| 302 | + | |
| 303 | +#ifdef __18CXX | |
| 304 | + // Summary: A 24-bit data type | |
| 305 | + // Description: The SWORD macro is used to defined a 24-bit data type. For 16+ bit architectures, this must be represented as | |
| 306 | + // an array of three bytes. | |
| 307 | + typedef unsigned short long SWORD; | |
| 308 | +#else | |
| 309 | + // Summary: A 24-bit data type | |
| 310 | + // Description: The SWORD macro is used to defined a 24-bit data type. For 16+ bit architectures, this must be represented as | |
| 311 | + // an array of three bytes. | |
| 312 | + typedef struct | |
| 313 | + { | |
| 314 | + unsigned char array[3]; | |
| 315 | +#if defined __PIC32MX__ || defined __C30__ | |
| 316 | + } __attribute__ ((packed)) SWORD; | |
| 317 | +#else | |
| 318 | + } SWORD; | |
| 319 | +#endif | |
| 320 | +#endif | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | +// Summary: A structure containing the bios parameter block for a FAT12 file system (in the boot sector) | |
| 325 | +// Description: The _BPB_FAT12 structure provides a layout of the "bios parameter block" in the boot sector of a FAT12 partition. | |
| 326 | +typedef struct { | |
| 327 | + SWORD BootSec_JumpCmd; // Jump Command | |
| 328 | + BYTE BootSec_OEMName[8]; // OEM name | |
| 329 | + WORD BootSec_BPS; // Number of bytes per sector | |
| 330 | + BYTE BootSec_SPC; // Number of sectors per cluster | |
| 331 | + WORD BootSec_ResrvSec; // Number of reserved sectors at the beginning of the partition | |
| 332 | + BYTE BootSec_FATCount; // Number of FATs on the partition | |
| 333 | + WORD BootSec_RootDirEnts; // Number of root directory entries | |
| 334 | + WORD BootSec_TotSec16; // Total number of sectors | |
| 335 | + BYTE BootSec_MDesc; // Media descriptor | |
| 336 | + WORD BootSec_SPF; // Number of sectors per FAT | |
| 337 | + WORD BootSec_SPT; // Number of sectors per track | |
| 338 | + WORD BootSec_HeadCnt; // Number of heads | |
| 339 | + DWORD BootSec_HiddenSecCnt; // Number of hidden sectors | |
| 340 | + DWORD BootSec_Reserved; // Reserved space | |
| 341 | + BYTE BootSec_DriveNum; // Drive number | |
| 342 | + BYTE BootSec_Reserved2; // Reserved space | |
| 343 | + BYTE BootSec_BootSig; // Boot signature - equal to 0x29 | |
| 344 | + BYTE BootSec_VolID[4]; // Volume ID | |
| 345 | + BYTE BootSec_VolLabel[11]; // Volume Label | |
| 346 | + BYTE BootSec_FSType[8]; // File system type in ASCII. Not used for determination | |
| 347 | +#if defined __PIC32MX__ || defined __C30__ | |
| 348 | + } __attribute__ ((packed)) _BPB_FAT12; | |
| 349 | +#else | |
| 350 | + } _BPB_FAT12; | |
| 351 | +#endif | |
| 352 | + | |
| 353 | +// Summary: A structure containing the bios parameter block for a FAT16 file system (in the boot sector) | |
| 354 | +// Description: The _BPB_FAT16 structure provides a layout of the "bios parameter block" in the boot sector of a FAT16 partition. | |
| 355 | +typedef struct { | |
| 356 | + SWORD BootSec_JumpCmd; // Jump Command | |
| 357 | + BYTE BootSec_OEMName[8]; // OEM name | |
| 358 | + WORD BootSec_BPS; // Number of bytes per sector | |
| 359 | + BYTE BootSec_SPC; // Number of sectors per cluster | |
| 360 | + WORD BootSec_ResrvSec; // Number of reserved sectors at the beginning of the partition | |
| 361 | + BYTE BootSec_FATCount; // Number of FATs on the partition | |
| 362 | + WORD BootSec_RootDirEnts; // Number of root directory entries | |
| 363 | + WORD BootSec_TotSec16; // Total number of sectors | |
| 364 | + BYTE BootSec_MDesc; // Media descriptor | |
| 365 | + WORD BootSec_SPF; // Number of sectors per FAT | |
| 366 | + WORD BootSec_SPT; // Number of sectors per track | |
| 367 | + WORD BootSec_HeadCnt; // Number of heads | |
| 368 | + DWORD BootSec_HiddenSecCnt; // Number of hidden sectors | |
| 369 | + DWORD BootSec_TotSec32; // Total sector count (32 bits) | |
| 370 | + BYTE BootSec_DriveNum; // Drive number | |
| 371 | + BYTE BootSec_Reserved; // Reserved space | |
| 372 | + BYTE BootSec_BootSig; // Boot signature - equal to 0x29 | |
| 373 | + BYTE BootSec_VolID[4]; // Volume ID | |
| 374 | + BYTE BootSec_VolLabel[11]; // Volume Label | |
| 375 | + BYTE BootSec_FSType[8]; // File system type in ASCII. Not used for determination | |
| 376 | +#if defined __PIC32MX__ || defined __C30__ | |
| 377 | + } __attribute__ ((packed)) _BPB_FAT16; | |
| 378 | +#else | |
| 379 | + } _BPB_FAT16; | |
| 380 | +#endif | |
| 381 | + | |
| 382 | +// Summary: A structure containing the bios parameter block for a FAT32 file system (in the boot sector) | |
| 383 | +// Description: The _BPB_FAT32 structure provides a layout of the "bios parameter block" in the boot sector of a FAT32 partition. | |
| 384 | +typedef struct { | |
| 385 | + SWORD BootSec_jmpBoot; // Jump Command | |
| 386 | + BYTE BootSec_OEMName[8]; // OEM name | |
| 387 | + WORD BootSec_BytsPerSec; // Number of bytes per sector | |
| 388 | + BYTE BootSec_SecPerClus; // Number of sectors per cluster | |
| 389 | + WORD BootSec_RsvdSecCnt; // Number of reserved sectors at the beginning of the partition | |
| 390 | + BYTE BootSec_NumFATs; // Number of FATs on the partition | |
| 391 | + WORD BootSec_RootEntCnt; // Number of root directory entries | |
| 392 | + WORD BootSec_TotSec16; // Total number of sectors | |
| 393 | + BYTE BootSec_Media; // Media descriptor | |
| 394 | + WORD BootSec_FATSz16; // Number of sectors per FAT | |
| 395 | + WORD BootSec_SecPerTrk; // Number of sectors per track | |
| 396 | + WORD BootSec_NumHeads; // Number of heads | |
| 397 | + DWORD BootSec_HiddSec; // Number of hidden sectors | |
| 398 | + DWORD BootSec_TotSec32; // Total sector count (32 bits) | |
| 399 | + DWORD BootSec_FATSz32; // Sectors per FAT (32 bits) | |
| 400 | + WORD BootSec_ExtFlags; // Presently active FAT. Defined by bits 0-3 if bit 7 is 1. | |
| 401 | + WORD BootSec_FSVers; // FAT32 filesystem version. Should be 0:0 | |
| 402 | + DWORD BootSec_RootClus; // Start cluster of the root directory (should be 2) | |
| 403 | + WORD BootSec_FSInfo; // File system information | |
| 404 | + WORD BootSec_BkBootSec; // Backup boot sector address. | |
| 405 | + BYTE BootSec_Reserved[12]; // Reserved space | |
| 406 | + BYTE BootSec_DrvNum; // Drive number | |
| 407 | + BYTE BootSec_Reserved1; // Reserved space | |
| 408 | + BYTE BootSec_BootSig; // Boot signature - 0x29 | |
| 409 | + BYTE BootSec_VolID[4]; // Volume ID | |
| 410 | + BYTE BootSec_VolLab[11]; // Volume Label | |
| 411 | + BYTE BootSec_FilSysType[8]; // File system type in ASCII. Not used for determination | |
| 412 | +#if defined __PIC32MX__ || defined __C30__ | |
| 413 | + } __attribute__ ((packed)) _BPB_FAT32; | |
| 414 | +#else | |
| 415 | + } _BPB_FAT32; | |
| 416 | +#endif | |
| 417 | + | |
| 418 | + | |
| 419 | +// Description: A macro for the boot sector bytes per sector value offset | |
| 420 | +#define BSI_BPS 11 | |
| 421 | + | |
| 422 | +// Description: A macro for the boot sector sector per cluster value offset | |
| 423 | +#define BSI_SPC 13 | |
| 424 | + | |
| 425 | +// Description: A macro for the boot sector reserved sector count value offset | |
| 426 | +#define BSI_RESRVSEC 14 | |
| 427 | + | |
| 428 | +// Description: A macro for the boot sector FAT count value offset | |
| 429 | +#define BSI_FATCOUNT 16 | |
| 430 | + | |
| 431 | +// Description: A macro for the boot sector root directory entry count value offset | |
| 432 | +#define BSI_ROOTDIRENTS 17 | |
| 433 | + | |
| 434 | +// Description: A macro for the boot sector 16-bit total sector count value offset | |
| 435 | +#define BSI_TOTSEC16 19 | |
| 436 | + | |
| 437 | +// Description: A macro for the boot sector sectors per FAT value offset | |
| 438 | +#define BSI_SPF 22 | |
| 439 | + | |
| 440 | +// Description: A macro for the boot sector 32-bit total sector count value offset | |
| 441 | +#define BSI_TOTSEC32 32 | |
| 442 | + | |
| 443 | +// Description: A macro for the boot sector boot signature offset | |
| 444 | +#define BSI_BOOTSIG 38 | |
| 445 | + | |
| 446 | +// Description: A macro for the boot sector file system type string offset | |
| 447 | +#define BSI_FSTYPE 54 | |
| 448 | + | |
| 449 | +// Description: A macro for the boot sector 32-bit sector per FAT value offset | |
| 450 | +#define BSI_FATSZ32 36 | |
| 451 | + | |
| 452 | +// Description: A macro for the boot sector start cluster of root directory value offset | |
| 453 | +#define BSI_ROOTCLUS 44 | |
| 454 | + | |
| 455 | +// Description: A macro for the FAT32 boot sector boot signature offset | |
| 456 | +#define BSI_FAT32_BOOTSIG 66 | |
| 457 | + | |
| 458 | +// Description: A macro for the FAT32 boot sector file system type string offset | |
| 459 | +#define BSI_FAT32_FSTYPE 82 | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | +// Summary: A partition table entry structure. | |
| 464 | +// Description: The PTE_MBR structure contains values found in a partition table entry in the MBR of a device. | |
| 465 | +typedef struct | |
| 466 | +{ | |
| 467 | + BYTE PTE_BootDes; // The boot descriptor (should be 0x00 in a non-bootable device) | |
| 468 | + SWORD PTE_FrstPartSect; // The cylinder-head-sector address of the first sector of the partition | |
| 469 | + BYTE PTE_FSDesc; // The file system descriptor | |
| 470 | + SWORD PTE_LstPartSect; // The cylinder-head-sector address of the last sector of the partition | |
| 471 | + DWORD PTE_FrstSect; // The logical block address of the first sector of the partition | |
| 472 | + DWORD PTE_NumSect; // The number of sectors in a partition | |
| 473 | +#if defined __PIC32MX__ || defined __C30__ | |
| 474 | + } __attribute__ ((packed)) PTE_MBR; | |
| 475 | +#else | |
| 476 | + } PTE_MBR; | |
| 477 | +#endif | |
| 478 | + | |
| 479 | + | |
| 480 | +// Summary: A structure of the organization of a master boot record. | |
| 481 | +// Description: The _PT_MBR structure has the same form as a master boot record. When the MBR is loaded from the device, it will | |
| 482 | +// be cast as a _PT_MBR structure so the MBR elements can be accessed. | |
| 483 | +typedef struct | |
| 484 | +{ | |
| 485 | + BYTE ConsChkRtn[446]; // Boot code | |
| 486 | + PTE_MBR Partition0; // The first partition table entry | |
| 487 | + PTE_MBR Partition1; // The second partition table entry | |
| 488 | + PTE_MBR Partition2; // The third partition table entry | |
| 489 | + PTE_MBR Partition3; // The fourth partition table entry | |
| 490 | + BYTE Signature0; // MBR signature code - equal to 0x55 | |
| 491 | + BYTE Signature1; // MBR signature code - equal to 0xAA | |
| 492 | +#if defined __PIC32MX__ || defined __C30__ | |
| 493 | +}__attribute__((packed)) _PT_MBR; | |
| 494 | +#else | |
| 495 | +}_PT_MBR; | |
| 496 | +#endif | |
| 497 | + | |
| 498 | +// Summary: A pointer to a _PT_MBR structure | |
| 499 | +// Description: The PT_MBR pointer points to a _PT_MBR structure. | |
| 500 | +typedef _PT_MBR * PT_MBR; | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | +// Summary: A structure of the organization of a boot sector. | |
| 505 | +// Description: The _BootSec structure has the same form as a boot sector. When the boot sector is loaded from the device, it will | |
| 506 | +// be cast as a _BootSec structure so the boot sector elements can be accessed. | |
| 507 | +typedef struct | |
| 508 | +{ | |
| 509 | + // A union of different bios parameter blocks | |
| 510 | + union | |
| 511 | + { | |
| 512 | + _BPB_FAT32 FAT_32; | |
| 513 | + _BPB_FAT16 FAT_16; | |
| 514 | + _BPB_FAT12 FAT_12; | |
| 515 | + }FAT; | |
| 516 | + BYTE Reserved[512-sizeof(_BPB_FAT32)-2]; // Reserved space | |
| 517 | + BYTE Signature0; // Boot sector signature code - equal to 0x55 | |
| 518 | + BYTE Signature1; // Boot sector signature code - equal to 0xAA | |
| 519 | +#if defined __PIC32MX__ || defined __C30__ | |
| 520 | + } __attribute__ ((packed)) _BootSec; | |
| 521 | +#else | |
| 522 | + } _BootSec; | |
| 523 | +#endif | |
| 524 | + | |
| 525 | +// Summary: A pointer to a _BootSec structure | |
| 526 | +// Description: The BootSec pointer points to a _BootSec structure. | |
| 527 | +typedef _BootSec * BootSec; | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | +// Summary: A macro indicating the offset for the master boot record | |
| 532 | +// Description: FO_MBR is a macro that indicates the addresss of the master boot record on the device. When the device is initialized | |
| 533 | +// this sector will be read | |
| 534 | +#define FO_MBR 0L | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | +// Summary: A macro for the first boot sector/MBR signature byte | |
| 539 | +// Description: The FAT_GOOD_SIGN_0 macro is used to determine that the first byte of the MBR or boot sector signature code is correct | |
| 540 | +#define FAT_GOOD_SIGN_0 0x55 | |
| 541 | + | |
| 542 | +// Summary: A macro for the second boot sector/MBR signature byte | |
| 543 | +// Description: The FAT_GOOD_SIGN_1 macro is used to determine that the second byte of the MBR or boot sector signature code is correct | |
| 544 | +#define FAT_GOOD_SIGN_1 0xAA | |
| 545 | + | |
| 546 | + | |
| 547 | +typedef struct | |
| 548 | +{ | |
| 549 | + BYTE errorCode; | |
| 550 | + union | |
| 551 | + { | |
| 552 | + BYTE value; | |
| 553 | + struct | |
| 554 | + { | |
| 555 | + BYTE sectorSize : 1; | |
| 556 | + BYTE maxLUN : 1; | |
| 557 | + } bits; | |
| 558 | + } validityFlags; | |
| 559 | + | |
| 560 | + WORD sectorSize; | |
| 561 | + BYTE maxLUN; | |
| 562 | +} MEDIA_INFORMATION; | |
| 563 | + | |
| 564 | +typedef enum | |
| 565 | +{ | |
| 566 | + MEDIA_NO_ERROR, // No errors | |
| 567 | + MEDIA_DEVICE_NOT_PRESENT, // The requested device is not present | |
| 568 | + MEDIA_CANNOT_INITIALIZE // Cannot initialize media | |
| 569 | +} MEDIA_ERRORS; | |
| 570 | + | |
| 571 | + | |
| 572 | +/*******************************************************************/ | |
| 573 | +/* Strunctures and defines */ | |
| 574 | +/*******************************************************************/ | |
| 575 | + | |
| 576 | +#ifndef FALSE | |
| 577 | + // Summary: False value | |
| 578 | + // Description: This macro will indicate that a condition is false. | |
| 579 | + #define FALSE 0 | |
| 580 | +#endif | |
| 581 | +#ifndef TRUE | |
| 582 | + // Summary: True value | |
| 583 | + // Description: This macro will indicate that a condition is true. | |
| 584 | + #define TRUE !FALSE // True value | |
| 585 | +#endif | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | +#ifndef SEEK_SET | |
| 591 | + // Summary: Macro for the FSfseek SEEK_SET base location. | |
| 592 | + // Description: Functions as an input for FSfseek that specifies that the position in the file will be changed | |
| 593 | + // relative to the beginning of the file. | |
| 594 | + #define SEEK_SET 0 | |
| 595 | + | |
| 596 | +#endif | |
| 597 | +#ifndef SEEK_CUR | |
| 598 | + | |
| 599 | + // Summary: Macro for the FSfseek SEEK_CUR base location. | |
| 600 | + // Description: Functions as an input for FSfseek that specifies that the position in the file will be changed | |
| 601 | + // relative to the current location of the file | |
| 602 | + #define SEEK_CUR 1 | |
| 603 | + | |
| 604 | +#endif | |
| 605 | +#ifndef SEEK_END | |
| 606 | + | |
| 607 | + // Summary: Macro for the FSfseek SEEK_END base location | |
| 608 | + // Description: Functions as an input for FSfseek that specifies that the position in the file will be changed | |
| 609 | + // relative to the end of the file. For this macro, the offset value will be subtracted from | |
| 610 | + // the end location of the file by default. | |
| 611 | + #define SEEK_END 2 | |
| 612 | + | |
| 613 | +#endif | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | +// Summary: Macro for the FSfopen FS_APPEND mode | |
| 619 | +// Description: If this macro is specified as the mode argument in a call of FSfopen, the file being opened will | |
| 620 | +// be created if it doesn't exist. If it does exist, it's file information will be loaded and the | |
| 621 | +// current location in the file will be set to the end. The user will then be able to write to the file. | |
| 622 | +#define FS_APPEND "a" | |
| 623 | +#define APPEND "a" //deprecated | |
| 624 | + | |
| 625 | +// Summary: Macro for the FSfopen FS_WRITE mode | |
| 626 | +// Description: If this macro is specified as the mode argument in a call of FSfopen, the file being opened will | |
| 627 | +// be created if it doesn't exist. If it does exist, it will be erased and replaced by an empty file | |
| 628 | +// of the same name. The user will then be able to write to the file. | |
| 629 | +#define FS_WRITE "w" | |
| 630 | +#define WRITE "w" //deprecated | |
| 631 | + | |
| 632 | +// Summary: Macro for the FSfopen FS_READ mode | |
| 633 | +// Description: If this macro is specified as the mode argument in a call of FSfopen, the file information for the | |
| 634 | +// specified file will be loaded. If the file does not exist, the FSfopen function will fail. The user | |
| 635 | +// will then be able to read from the file. | |
| 636 | +#define FS_READ "r" | |
| 637 | +#if defined(__32MX795F512L__) | |
| 638 | +// #warning FSfopen must use "r" and not READ as input on this device | |
| 639 | +#else | |
| 640 | + #define READ "r" //deprecated | |
| 641 | +#endif | |
| 642 | + | |
| 643 | +// Summary: Macro for the FSfopen FS_APPEND+ mode | |
| 644 | +// Description: If this macro is specified as the mode argument in a call of FSfopen, the file being opened will | |
| 645 | +// be created if it doesn't exist. If it does exist, it's file information will be loaded and the | |
| 646 | +// current location in the file will be set to the end. The user will then be able to write to the file | |
| 647 | +// or read from the file. | |
| 648 | +#define FS_APPENDPLUS "a+" | |
| 649 | +#define APPENDPLUS "a+" //deprecated | |
| 650 | + | |
| 651 | +// Summary: Macro for the FSfopen FS_WRITE+ mode | |
| 652 | +// Description: If this macro is specified as the mode argument in a call of FSfopen, the file being opened will | |
| 653 | +// be created if it doesn't exist. If it does exist, it will be erased and replaced by an empty file | |
| 654 | +// of the same name. The user will then be able to write to the file or read from the file. | |
| 655 | +#define FS_WRITEPLUS "w+" | |
| 656 | +#define WRITEPLUS "w+" //deprecated | |
| 657 | + | |
| 658 | +// Summary: Macro for the FSfopen FS_READ+ mode | |
| 659 | +// Description: If this macro is specified as the mode argument in a call of FSfopen, the file information for the | |
| 660 | +// specified file will be loaded. If the file does not exist, the FSfopen function will fail. The user | |
| 661 | +// will then be able to read from the file or write to the file. | |
| 662 | +#define FS_READPLUS "r+" | |
| 663 | +#define READPLUS "r+" //deprecated | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | +#ifndef intmax_t | |
| 668 | + #ifdef __PIC24F__ | |
| 669 | + // Summary: A data type indicating the maximum integer size in an architecture | |
| 670 | + // Description: The intmax_t data type refers to the maximum-sized data type on any given architecture. This | |
| 671 | + // data type can be specified as a format specifier size specification for the FSfprintf function. | |
| 672 | + #define intmax_t long long | |
| 673 | + #elif defined __PIC24H__ | |
| 674 | + #define intmax_t long long | |
| 675 | + #elif defined __dsPIC30F__ | |
| 676 | + #define intmax_t long long | |
| 677 | + #elif defined __dsPIC33F__ | |
| 678 | + #define intmax_t long long | |
| 679 | + #endif | |
| 680 | +#endif | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | +// Summary: Indicates flag conditions for a file object | |
| 685 | +// Description: The FILEFLAGS structure is used to indicate conditions in a file. It contains three flags: 'write' indicates | |
| 686 | +// that the file was opened in a mode that allows writes, 'read' indicates that the file was opened in a mode | |
| 687 | +// that allows reads, and 'FileWriteEOF' indicates that additional data that is written to the file will increase | |
| 688 | +// the file size. | |
| 689 | +typedef struct | |
| 690 | +{ | |
| 691 | + unsigned write :1; // Indicates a file was opened in a mode that allows writes | |
| 692 | + unsigned read :1; // Indicates a file was opened in a mode that allows reads | |
| 693 | + unsigned FileWriteEOF :1; // Indicates the current position in a file is at the end of the file | |
| 694 | +}FILEFLAGS; | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | +// Summary: Indicates how to search for file entries in the FILEfind function | |
| 699 | +// Description: The values in the SEARCH_TYPE enumeration are used internally by the library to indicate how the FILEfind function | |
| 700 | +// how to perform a search. The 'LOOK_FOR_EMPTY_ENTRY' value indicates that FILEfind should search for an empty file entry. | |
| 701 | +// The 'LOOK_FOR_MATCHING_ENTRY' value indicates that FILEfind should search for an entry that matches the FSFILE object | |
| 702 | +// that was passed into the FILEfind function. | |
| 703 | +typedef enum{ | |
| 704 | + LOOK_FOR_EMPTY_ENTRY = 0, | |
| 705 | + LOOK_FOR_MATCHING_ENTRY | |
| 706 | +} SEARCH_TYPE; | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | +// Summary: Macro indicating the length of a 8.3 file name | |
| 711 | +// Description: The TOTAL_FILE_SIZE_8P3 macro indicates the maximum number of characters in an 8.3 file name. This value includes | |
| 712 | +// 8 characters for the name, three for the extentsion, and 1 for the radix ('.') | |
| 713 | +#define TOTAL_FILE_SIZE_8P3 (8+3+1) | |
| 714 | +#define TOTAL_FILE_SIZE TOTAL_FILE_SIZE_8P3 | |
| 715 | + | |
| 716 | +// Summary: Macro indicating the max length of a LFN file name | |
| 717 | +// Description: The MAX_FILE_NAME_LENGTH_LFN macro indicates the maximum number of characters in an LFN file name. | |
| 718 | +#define MAX_FILE_NAME_LENGTH_LFN 256 | |
| 719 | + | |
| 720 | +// Summary: A mask that indicates the limit of directory entries in a sector | |
| 721 | +// Description: The MASK_MAX_FILE_ENTRY_LIMIT_BITS is used to indicate to the Cache_File_Entry function that a new sector needs to | |
| 722 | +// be loaded. | |
| 723 | +#define MASK_MAX_FILE_ENTRY_LIMIT_BITS 0x0f | |
| 724 | + | |
| 725 | +// Summary: Value used for shift operations to calculate the sector offset in a directory | |
| 726 | +// Description: The VALUE_BASED_ON_ENTRIES_PER_CLUSTER macro is used to calculate sector offsets for directories. The position of the | |
| 727 | +// entry is shifted by 4 bits (divided by 16, since there are 16 entries in a sector) to calculate how many sectors a | |
| 728 | +// specified entry is offset from the beginning of the directory. | |
| 729 | +#define VALUE_BASED_ON_ENTRIES_PER_CLUSTER 4 | |
| 730 | + | |
| 731 | +// Summary: A value that will indicate that a dotdot directory entry points to the root. | |
| 732 | +// Description: The VALUE_DOTDOT_CLUSTER_VALUE_FOR_ROOT macro is used as an absolute address when writing information to a dotdot entry | |
| 733 | +// in a newly created directory. If a dotdot entry points to the root directory, it's cluster value must be set to 0, | |
| 734 | +// regardless of the actual cluster number of the root directory. | |
| 735 | +#define VALUE_DOTDOT_CLUSTER_VALUE_FOR_ROOT 0 | |
| 736 | + | |
| 737 | +// Summary: MAcro indicating the length of an 8.3 file name in a directory entry | |
| 738 | +// Description: The FILE_NAME_SIZE_8P3 macro indicates the number of characters that an 8.3 file name will take up when packed in | |
| 739 | +// a directory entry. This value includes 8 characters for the name and 3 for the extension. Note that the radix is not | |
| 740 | +// stored in the directory entry. | |
| 741 | +#define FILE_NAME_SIZE_8P3 11 | |
| 742 | +#define FILE_NAME_SIZE FILE_NAME_SIZE_8P3 | |
| 743 | + | |
| 744 | + | |
| 745 | +// Summary: Contains file information and is used to indicate which file to access. | |
| 746 | +// Description: The FSFILE structure is used to hold file information for an open file as it's being modified or accessed. A pointer to | |
| 747 | +// an open file's FSFILE structure will be passeed to any library function that will modify that file. | |
| 748 | +typedef struct | |
| 749 | +{ | |
| 750 | + DISK * dsk; // Pointer to a DISK structure | |
| 751 | + DWORD cluster; // The first cluster of the file | |
| 752 | + DWORD ccls; // The current cluster of the file | |
| 753 | + WORD sec; // The current sector in the current cluster of the file | |
| 754 | + WORD pos; // The position in the current sector | |
| 755 | + DWORD seek; // The absolute position in the file | |
| 756 | + DWORD size; // The size of the file | |
| 757 | + FILEFLAGS flags; // A structure containing file flags | |
| 758 | + WORD time; // The file's last update time | |
| 759 | + WORD date; // The file's last update date | |
| 760 | + char name[FILE_NAME_SIZE_8P3]; // The short name of the file | |
| 761 | + #ifdef SUPPORT_LFN | |
| 762 | + BOOL AsciiEncodingType; // Ascii file name or Non-Ascii file name indicator | |
| 763 | + unsigned short int *utf16LFNptr; // Pointer to long file name in UTF16 format | |
| 764 | + unsigned short int utf16LFNlength; // LFN length in terms of words including the NULL word at the last. | |
| 765 | + #endif | |
| 766 | + WORD entry; // The position of the file's directory entry in it's directory | |
| 767 | + WORD chk; // File structure checksum | |
| 768 | + WORD attributes; // The file attributes | |
| 769 | + DWORD dirclus; // The base cluster of the file's directory | |
| 770 | + DWORD dirccls; // The current cluster of the file's directory | |
| 771 | +} FSFILE; | |
| 772 | + | |
| 773 | +/* Summary: Possible results of the FSGetDiskProperties() function. | |
| 774 | +** Description: See the FSGetDiskProperties() function for more information. | |
| 775 | +*/ | |
| 776 | +typedef enum | |
| 777 | +{ | |
| 778 | + FS_GET_PROPERTIES_NO_ERRORS = 0, | |
| 779 | + FS_GET_PROPERTIES_DISK_NOT_MOUNTED, | |
| 780 | + FS_GET_PROPERTIES_CLUSTER_FAILURE, | |
| 781 | + FS_GET_PROPERTIES_STILL_WORKING = 0xFF | |
| 782 | +} FS_DISK_ERRORS; | |
| 783 | + | |
| 784 | + | |
| 785 | +/* Summary: Contains the disk search information, intermediate values, and results | |
| 786 | +** Description: This structure is used in conjunction with the FSGetDiskProperties() | |
| 787 | +** function. See that function for more information about the usage. | |
| 788 | +*/ | |
| 789 | +typedef struct | |
| 790 | +{ | |
| 791 | + DISK * disk; /* pointer to the disk we are searching */ | |
| 792 | + BOOL new_request; /* is this a new request or a continued request */ | |
| 793 | + FS_DISK_ERRORS properties_status; /* status of the last call of the function */ | |
| 794 | + | |
| 795 | + struct | |
| 796 | + { | |
| 797 | + BYTE disk_format; /* disk format: FAT12, FAT16, FAT32 */ | |
| 798 | + WORD sector_size; /* sector size of the drive */ | |
| 799 | + BYTE sectors_per_cluster; /* number of sectors per cluster */ | |
| 800 | + DWORD total_clusters; /* the number of total clusters on the drive */ | |
| 801 | + DWORD free_clusters; /* the number of free (unused) clusters on drive */ | |
| 802 | + } results; /* the results of the current search */ | |
| 803 | + | |
| 804 | + struct | |
| 805 | + { | |
| 806 | + DWORD c; | |
| 807 | + DWORD curcls; | |
| 808 | + DWORD EndClusterLimit; | |
| 809 | + DWORD ClusterFailValue; | |
| 810 | + } private; /* intermediate values used to continue searches. This | |
| 811 | + member should be used only by the FSGetDiskProperties() | |
| 812 | + function */ | |
| 813 | + | |
| 814 | +} FS_DISK_PROPERTIES; | |
| 815 | + | |
| 816 | +// Summary: A structure used for searching for files on a device. | |
| 817 | +// Description: The SearchRec structure is used when searching for file on a device. It contains parameters that will be loaded with | |
| 818 | +// file information when a file is found. It also contains the parameters that the user searched for, allowing further | |
| 819 | +// searches to be perfomed in the same directory for additional files that meet the specified criteria. | |
| 820 | +typedef struct | |
| 821 | +{ | |
| 822 | + char filename[FILE_NAME_SIZE_8P3 + 2]; // The name of the file that has been found | |
| 823 | + unsigned char attributes; // The attributes of the file that has been found | |
| 824 | + unsigned long filesize; // The size of the file that has been found | |
| 825 | + unsigned long timestamp; // The last modified time of the file that has been found (create time for directories) | |
| 826 | + #ifdef SUPPORT_LFN | |
| 827 | + BOOL AsciiEncodingType; // Ascii file name or Non-Ascii file name indicator | |
| 828 | + unsigned short int *utf16LFNfound; // Pointer to long file name found in UTF16 format | |
| 829 | + unsigned short int utf16LFNfoundLength; // LFN Found length in terms of words including the NULL word at the last. | |
| 830 | + #endif | |
| 831 | + unsigned int entry; // The directory entry of the last file found that matches the specified attributes. (Internal use only) | |
| 832 | + char searchname[FILE_NAME_SIZE_8P3 + 2]; // The 8.3 format name specified when the user began the search. (Internal use only) | |
| 833 | + unsigned char searchattr; // The attributes specified when the user began the search. (Internal use only) | |
| 834 | + unsigned long cwdclus; // The directory that this search was performed in. (Internal use only) | |
| 835 | + unsigned char initialized; // Check to determine if the structure was initialized by FindFirst (Internal use only) | |
| 836 | +} SearchRec; | |
| 837 | + | |
| 838 | + | |
| 839 | +/*************************************************************************** | |
| 840 | +* Prototypes * | |
| 841 | +***************************************************************************/ | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | +/************************************************************************* | |
| 847 | + Function: | |
| 848 | + int FSInit(void) | |
| 849 | + Summary: | |
| 850 | + Function to initialize the device. | |
| 851 | + Conditions: | |
| 852 | + The physical device should be connected to the microcontroller. | |
| 853 | + Input: | |
| 854 | + None | |
| 855 | + Return Values: | |
| 856 | + TRUE - Initialization successful | |
| 857 | + FALSE - Initialization unsuccessful | |
| 858 | + Side Effects: | |
| 859 | + The FSerrno variable will be changed. | |
| 860 | + Description: | |
| 861 | + Initializes the static or dynamic memory slots for holding file | |
| 862 | + structures. Initializes the device with the DISKmount function. Loads | |
| 863 | + MBR and boot sector information. Initializes the current working | |
| 864 | + directory to the root directory for the device if directory support | |
| 865 | + is enabled. | |
| 866 | + Remarks: | |
| 867 | + None | |
| 868 | + *************************************************************************/ | |
| 869 | + | |
| 870 | +int FSInit(void); | |
| 871 | + | |
| 872 | + | |
| 873 | +/********************************************************************* | |
| 874 | + Function: | |
| 875 | + FSFILE * FSfopen (const char * fileName, const char *mode) | |
| 876 | + Summary: | |
| 877 | + Open a Ascii file | |
| 878 | + Conditions: | |
| 879 | + For read modes, file exists; FSInit performed | |
| 880 | + Input: | |
| 881 | + fileName - The name of the file to open | |
| 882 | + mode - | |
| 883 | + - WRITE - Create a new file or replace an existing file | |
| 884 | + - READ - Read data from an existing file | |
| 885 | + - APPEND - Append data to an existing file | |
| 886 | + - WRITEPLUS - Create a new file or replace an existing file (reads also enabled) | |
| 887 | + - READPLUS - Read data from an existing file (writes also enabled) | |
| 888 | + - APPENDPLUS - Append data to an existing file (reads also enabled) | |
| 889 | + Return Values: | |
| 890 | + FSFILE * - The pointer to the file object | |
| 891 | + NULL - The file could not be opened | |
| 892 | + Side Effects: | |
| 893 | + The FSerrno variable will be changed. | |
| 894 | + Description: | |
| 895 | + This function will open a file or directory. First, RAM in the | |
| 896 | + dynamic heap or static array will be allocated to a new FSFILE object. | |
| 897 | + Then, the specified file name will be formatted to ensure that it's | |
| 898 | + in 8.3 format or LFN format. Next, the FILEfind function will be used | |
| 899 | + to search for the specified file name. If the name is found, one of three | |
| 900 | + things will happen: if the file was opened in read mode, its file | |
| 901 | + info will be loaded using the FILEopen function; if it was opened in | |
| 902 | + write mode, it will be erased, and a new file will be constructed in | |
| 903 | + its place; if it was opened in append mode, its file info will be | |
| 904 | + loaded with FILEopen and the current location will be moved to the | |
| 905 | + end of the file using the FSfseek function. If the file was not | |
| 906 | + found by FILEfind, a new file will be created if the mode was specified as | |
| 907 | + a write or append mode. In these cases, a pointer to the heap or | |
| 908 | + static FSFILE object array will be returned. If the file was not | |
| 909 | + found and the mode was specified as a read mode, the memory | |
| 910 | + allocated to the file will be freed and the NULL pointer value | |
| 911 | + will be returned. | |
| 912 | + Remarks: | |
| 913 | + None. | |
| 914 | + *********************************************************************/ | |
| 915 | + | |
| 916 | +FSFILE * FSfopen(const char * fileName, const char *mode); | |
| 917 | + | |
| 918 | +#ifdef SUPPORT_LFN | |
| 919 | +/********************************************************************* | |
| 920 | + Function: | |
| 921 | + FSFILE * wFSfopen (const unsigned short int * fileName, const char *mode) | |
| 922 | + Summary: | |
| 923 | + Open a UTF16 file. | |
| 924 | + Conditions: | |
| 925 | + For read modes, file exists; FSInit performed | |
| 926 | + Input: | |
| 927 | + fileName - The name of the file to open | |
| 928 | + mode - | |
| 929 | + - WRITE - Create a new file or replace an existing file | |
| 930 | + - READ - Read data from an existing file | |
| 931 | + - APPEND - Append data to an existing file | |
| 932 | + - WRITEPLUS - Create a new file or replace an existing file (reads also enabled) | |
| 933 | + - READPLUS - Read data from an existing file (writes also enabled) | |
| 934 | + - APPENDPLUS - Append data to an existing file (reads also enabled) | |
| 935 | + Return Values: | |
| 936 | + FSFILE * - The pointer to the file object | |
| 937 | + NULL - The file could not be opened | |
| 938 | + Side Effects: | |
| 939 | + The FSerrno variable will be changed. | |
| 940 | + Description: | |
| 941 | + This function will open a file or directory. First, RAM in the | |
| 942 | + dynamic heap or static array will be allocated to a new FSFILE object. | |
| 943 | + Then, the specified file name will be formatted to ensure that it's | |
| 944 | + in 8.3 format or LFN format. Next, the FILEfind function will be used | |
| 945 | + to search for the specified file name. If the name is found, one of three | |
| 946 | + things will happen: if the file was opened in read mode, its file | |
| 947 | + info will be loaded using the FILEopen function; if it was opened in | |
| 948 | + write mode, it will be erased, and a new file will be constructed in | |
| 949 | + its place; if it was opened in append mode, its file info will be | |
| 950 | + loaded with FILEopen and the current location will be moved to the | |
| 951 | + end of the file using the FSfseek function. If the file was not | |
| 952 | + found by FILEfind, a new file will be created if the mode was specified as | |
| 953 | + a write or append mode. In these cases, a pointer to the heap or | |
| 954 | + static FSFILE object array will be returned. If the file was not | |
| 955 | + found and the mode was specified as a read mode, the memory | |
| 956 | + allocated to the file will be freed and the NULL pointer value | |
| 957 | + will be returned. | |
| 958 | + Remarks: | |
| 959 | + None. | |
| 960 | + *********************************************************************/ | |
| 961 | + | |
| 962 | +FSFILE * wFSfopen(const unsigned short int * fileName, const char *mode); | |
| 963 | +#endif | |
| 964 | + | |
| 965 | +#ifdef ALLOW_PGMFUNCTIONS | |
| 966 | + | |
| 967 | +/****************************************************************************** | |
| 968 | + Function: | |
| 969 | + FSFILE * FSfopenpgm(const rom char * fileName, const rom char *mode) | |
| 970 | + Summary: | |
| 971 | + Open a Ascii file named with a ROM string on PIC18 | |
| 972 | + Conditions: | |
| 973 | + For read modes, file exists; FSInit performed | |
| 974 | + Input: | |
| 975 | + fileName - The name of the file to be opened (ROM) | |
| 976 | + mode - The mode the file will be opened in (ROM) | |
| 977 | + Return Values: | |
| 978 | + FSFILE * - A pointer to the file object | |
| 979 | + NULL - File could not be opened | |
| 980 | + Side Effects: | |
| 981 | + The FSerrno variable will be changed. | |
| 982 | + Description: | |
| 983 | + The FSfopenpgm function will copy a PIC18 ROM fileName and mode argument | |
| 984 | + into RAM arrays, and then pass those arrays to the FSfopen function. | |
| 985 | + Remarks: | |
| 986 | + This function is for use with PIC18 when passing arguments in ROM. | |
| 987 | + ******************************************************************************/ | |
| 988 | + | |
| 989 | + FSFILE * FSfopenpgm(const rom char * fileName, const rom char *mode); | |
| 990 | + | |
| 991 | + | |
| 992 | +/************************************************************************************** | |
| 993 | + Function: | |
| 994 | + int FindFirstpgm (const char * fileName, unsigned int attr, SearchRec * rec) | |
| 995 | + Summary: | |
| 996 | + Find a file named with a ROM string on PIC18 | |
| 997 | + Conditions: | |
| 998 | + None | |
| 999 | + Input: | |
| 1000 | + fileName - The name of the file to be found (ROM) | |
| 1001 | + attr - The attributes of the file to be found | |
| 1002 | + rec - Pointer to a search record to store the file info in | |
| 1003 | + Return Values: | |
| 1004 | + 0 - File was found | |
| 1005 | + -1 - No file matching the given parameters was found | |
| 1006 | + Side Effects: | |
| 1007 | + Search criteria from previous FindFirstpgm call on passed SearchRec object | |
| 1008 | + will be lost.The FSerrno variable will be changed. | |
| 1009 | + Description: | |
| 1010 | + The FindFirstpgm function will copy a PIC18 ROM fileName argument | |
| 1011 | + into a RAM array, and then pass that array to the FindFirst function. | |
| 1012 | + Remarks: | |
| 1013 | + Call FindFirstpgm or FindFirst before calling FindNext. | |
| 1014 | + This function is for use with PIC18 when passing arguments in ROM. | |
| 1015 | + **************************************************************************************/ | |
| 1016 | + | |
| 1017 | + int FindFirstpgm (const rom char * fileName, unsigned int attr, SearchRec * rec); | |
| 1018 | + | |
| 1019 | + | |
| 1020 | +/************************************************************************** | |
| 1021 | + Function: | |
| 1022 | + int FSchdirpgm (const rom char * path) | |
| 1023 | + Summary: | |
| 1024 | + Changed the CWD with a path in ROM on PIC18 | |
| 1025 | + Conditions: | |
| 1026 | + None | |
| 1027 | + Input: | |
| 1028 | + path - The path of the directory to change to (ROM) | |
| 1029 | + Return Values: | |
| 1030 | + 0 - The current working directory was changed successfully | |
| 1031 | + EOF - The current working directory could not be changed | |
| 1032 | + Side Effects: | |
| 1033 | + The current working directory may be changed. The FSerrno variable will | |
| 1034 | + be changed. | |
| 1035 | + Description: | |
| 1036 | + The FSchdirpgm function passes a PIC18 ROM path pointer to the | |
| 1037 | + chdirhelper function. | |
| 1038 | + Remarks: | |
| 1039 | + This function is for use with PIC18 when passing arguments in ROM | |
| 1040 | + **************************************************************************/ | |
| 1041 | + | |
| 1042 | + int FSchdirpgm (const rom char * path); | |
| 1043 | + | |
| 1044 | + #ifdef ALLOW_WRITES | |
| 1045 | + | |
| 1046 | + | |
| 1047 | +/************************************************************* | |
| 1048 | + Function: | |
| 1049 | + int FSremovepgm (const rom char * fileName) | |
| 1050 | + Summary: | |
| 1051 | + Delete a file named with a ROM string on PIC18 | |
| 1052 | + Conditions: | |
| 1053 | + File not opened; file exists | |
| 1054 | + Input: | |
| 1055 | + fileName - The name of the file to be deleted (ROM) | |
| 1056 | + Return Values: | |
| 1057 | + 0 - File was removed successfully | |
| 1058 | + -1 - File could not be removed | |
| 1059 | + Side Effects: | |
| 1060 | + The FSerrno variable will be changed. | |
| 1061 | + Description: | |
| 1062 | + The FSremovepgm function will copy a PIC18 ROM fileName argument | |
| 1063 | + into a RAM array, and then pass that array to the FSremove function. | |
| 1064 | + Remarks: | |
| 1065 | + This function is for use with PIC18 when passing arguments in ROM. | |
| 1066 | + *************************************************************/ | |
| 1067 | + | |
| 1068 | + int FSremovepgm (const rom char * fileName); | |
| 1069 | + | |
| 1070 | + | |
| 1071 | +/************************************************************************** | |
| 1072 | + Function: | |
| 1073 | + int FSmkdirpgm (const rom char * path) | |
| 1074 | + Summary: | |
| 1075 | + Create a directory with a path in ROM on PIC18 | |
| 1076 | + Conditions: | |
| 1077 | + None | |
| 1078 | + Input: | |
| 1079 | + path - The path of directories to create (ROM) | |
| 1080 | + Return Values: | |
| 1081 | + 0 - The specified directory was created successfully | |
| 1082 | + EOF - The specified directory could not be created | |
| 1083 | + Side Effects: | |
| 1084 | + Will create all non-existent directories in the path. The FSerrno | |
| 1085 | + variable will be changed. | |
| 1086 | + Description: | |
| 1087 | + The FSmkdirpgm function passes a PIC18 ROM path pointer to the | |
| 1088 | + mkdirhelper function. | |
| 1089 | + Remarks: | |
| 1090 | + This function is for use with PIC18 when passing arugments in ROM | |
| 1091 | + **************************************************************************/ | |
| 1092 | + | |
| 1093 | + int FSmkdirpgm (const rom char * path); | |
| 1094 | + | |
| 1095 | + | |
| 1096 | +/************************************************************************** | |
| 1097 | + Function: | |
| 1098 | + int FSrmdirpgm (const rom char * path) | |
| 1099 | + Summary: | |
| 1100 | + Delete a directory with a path in ROM on PIC18 | |
| 1101 | + Conditions: | |
| 1102 | + None. | |
| 1103 | + Input: | |
| 1104 | + path - The path of the directory to remove (ROM) | |
| 1105 | + rmsubdirs - | |
| 1106 | + - TRUE - All sub-dirs and files in the target dir will be removed | |
| 1107 | + - FALSE - FSrmdir will not remove non-empty directories | |
| 1108 | + Return Values: | |
| 1109 | + 0 - The specified directory was deleted successfully | |
| 1110 | + EOF - The specified directory could not be deleted | |
| 1111 | + Side Effects: | |
| 1112 | + The FSerrno variable will be changed. | |
| 1113 | + Description: | |
| 1114 | + The FSrmdirpgm function passes a PIC18 ROM path pointer to the | |
| 1115 | + rmdirhelper function. | |
| 1116 | + Remarks: | |
| 1117 | + This function is for use with PIC18 when passing arguments in ROM. | |
| 1118 | + **************************************************************************/ | |
| 1119 | + | |
| 1120 | + int FSrmdirpgm (const rom char * path, unsigned char rmsubdirs); | |
| 1121 | + | |
| 1122 | + | |
| 1123 | +/***************************************************************** | |
| 1124 | + Function: | |
| 1125 | + int FSrenamepgm(const rom char * fileName, FSFILE * fo) | |
| 1126 | + Summary: | |
| 1127 | + Rename a file named with a ROM string on PIC18 | |
| 1128 | + Conditions: | |
| 1129 | + File opened. | |
| 1130 | + Input: | |
| 1131 | + fileName - The new name of the file (in ROM) | |
| 1132 | + fo - The file to rename | |
| 1133 | + Return Values: | |
| 1134 | + 0 - File renamed successfully | |
| 1135 | + -1 - File could not be renamed | |
| 1136 | + Side Effects: | |
| 1137 | + The FSerrno variable will be changed. | |
| 1138 | + Description: | |
| 1139 | + The Fsrenamepgm function will copy the rom fileName specified | |
| 1140 | + by the user into a RAM array and pass that array into the | |
| 1141 | + FSrename function. | |
| 1142 | + Remarks: | |
| 1143 | + This function is for use with PIC18 when passing arguments in ROM. | |
| 1144 | + *****************************************************************/ | |
| 1145 | + | |
| 1146 | + int FSrenamepgm (const rom char * fileName, FSFILE * fo); | |
| 1147 | + #endif | |
| 1148 | +#endif | |
| 1149 | + | |
| 1150 | + | |
| 1151 | +/************************************************************ | |
| 1152 | + Function: | |
| 1153 | + int FSfclose(FSFILE *fo) | |
| 1154 | + Summary: | |
| 1155 | + Update file information and free FSFILE objects | |
| 1156 | + Conditions: | |
| 1157 | + File opened | |
| 1158 | + Input: | |
| 1159 | + fo - Pointer to the file to close | |
| 1160 | + Return Values: | |
| 1161 | + 0 - File closed successfully | |
| 1162 | + EOF - Error closing the file | |
| 1163 | + Side Effects: | |
| 1164 | + The FSerrno variable will be changed. | |
| 1165 | + Description: | |
| 1166 | + This function will update the directory entry for the | |
| 1167 | + file pointed to by 'fo' with the information contained | |
| 1168 | + in 'fo,' including the new file size and attributes. | |
| 1169 | + Timestamp information will also be loaded based on the | |
| 1170 | + method selected by the user and written to the entry | |
| 1171 | + as the last modified time and date. The file entry will | |
| 1172 | + then be written to the device. Finally, the memory | |
| 1173 | + used for the specified file object will be freed from | |
| 1174 | + the dynamic heap or the array of FSFILE objects. | |
| 1175 | + Remarks: | |
| 1176 | + A function to flush data to the device without closing the | |
| 1177 | + file can be created by removing the portion of this | |
| 1178 | + function that frees the memory and the line that clears | |
| 1179 | + the write flag. | |
| 1180 | + ************************************************************/ | |
| 1181 | + | |
| 1182 | +int FSfclose(FSFILE *fo); | |
| 1183 | + | |
| 1184 | + | |
| 1185 | +/********************************************************* | |
| 1186 | + Function: | |
| 1187 | + void FSrewind (FSFILE * fo) | |
| 1188 | + Summary: | |
| 1189 | + Set the current position in a file to the beginning | |
| 1190 | + Conditions: | |
| 1191 | + File opened. | |
| 1192 | + Input: | |
| 1193 | + fo - Pointer to file structure | |
| 1194 | + Return Values: | |
| 1195 | + None | |
| 1196 | + Side Effects: | |
| 1197 | + None. | |
| 1198 | + Description: | |
| 1199 | + The FSrewind funciton will reset the position of the | |
| 1200 | + specified file to the beginning of the file. This | |
| 1201 | + functionality is faster than using FSfseek to reset | |
| 1202 | + the position in the file. | |
| 1203 | + Remarks: | |
| 1204 | + None. | |
| 1205 | + *********************************************************/ | |
| 1206 | + | |
| 1207 | +void FSrewind (FSFILE *fo); | |
| 1208 | + | |
| 1209 | + | |
| 1210 | +/************************************************************************** | |
| 1211 | + Function: | |
| 1212 | + size_t FSfread(void *ptr, size_t size, size_t n, FSFILE *stream) | |
| 1213 | + Summary: | |
| 1214 | + Read data from a file | |
| 1215 | + Conditions: | |
| 1216 | + File is opened in a read mode | |
| 1217 | + Input: | |
| 1218 | + ptr - Destination buffer for read bytes | |
| 1219 | + size - Size of units in bytes | |
| 1220 | + n - Number of units to be read | |
| 1221 | + stream - File to be read from | |
| 1222 | + Return: | |
| 1223 | + size_t - number of units read | |
| 1224 | + Side Effects: | |
| 1225 | + The FSerrno variable will be changed. | |
| 1226 | + Description: | |
| 1227 | + The FSfread function will read data from the specified file. First, | |
| 1228 | + the appropriate sector of the file is loaded. Then, data is read into | |
| 1229 | + the specified buffer until the specified number of bytes have been read. | |
| 1230 | + When a cluster boundary is reached, a new cluster will be loaded. The | |
| 1231 | + parameters 'size' and 'n' indicate how much data to read. 'Size' | |
| 1232 | + refers to the size of one object to read (in bytes), and 'n' will refer | |
| 1233 | + to the number of these objects to read. The value returned will be equal | |
| 1234 | + to 'n' unless an error occured or the user tried to read beyond the end | |
| 1235 | + of the file. | |
| 1236 | + Remarks: | |
| 1237 | + None. | |
| 1238 | + **************************************************************************/ | |
| 1239 | + | |
| 1240 | +size_t FSfread(void *ptr, size_t size, size_t n, FSFILE *stream); | |
| 1241 | + | |
| 1242 | + | |
| 1243 | +/********************************************************************** | |
| 1244 | + Function: | |
| 1245 | + int FSfseek(FSFILE *stream, long offset, int whence) | |
| 1246 | + Summary: | |
| 1247 | + Change the current position in a file | |
| 1248 | + Conditions: | |
| 1249 | + File opened | |
| 1250 | + Input: | |
| 1251 | + stream - Pointer to file structure | |
| 1252 | + offset - Offset from base location | |
| 1253 | + whence - | |
| 1254 | + - SEEK_SET - Seek from start of file | |
| 1255 | + - SEEK_CUR - Seek from current location | |
| 1256 | + - SEEK_END - Seek from end of file (subtract offset) | |
| 1257 | + Return Values: | |
| 1258 | + 0 - Operation successful | |
| 1259 | + -1 - Operation unsuccesful | |
| 1260 | + Side Effects: | |
| 1261 | + The FSerrno variable will be changed. | |
| 1262 | + Description: | |
| 1263 | + The FSfseek function will change the current position in the file to | |
| 1264 | + one specified by the user. First, an absolute offset is calculated | |
| 1265 | + using the offset and base location passed in by the user. Then, the | |
| 1266 | + position variables are updated, and the sector number that corresponds | |
| 1267 | + to the new location. That sector is then loaded. If the offset | |
| 1268 | + falls exactly on a cluster boundary, a new cluster will be allocated | |
| 1269 | + to the file and the position will be set to the first byte of that | |
| 1270 | + cluster. | |
| 1271 | + Remarks: | |
| 1272 | + None | |
| 1273 | + **********************************************************************/ | |
| 1274 | + | |
| 1275 | +int FSfseek(FSFILE *stream, long offset, int whence); | |
| 1276 | + | |
| 1277 | + | |
| 1278 | +/******************************************************************* | |
| 1279 | + Function: | |
| 1280 | + long FSftell (FSFILE * fo) | |
| 1281 | + Summary: | |
| 1282 | + Determine the current location in a file | |
| 1283 | + Conditions: | |
| 1284 | + File opened | |
| 1285 | + Input: | |
| 1286 | + fo - Pointer to file structure | |
| 1287 | + Return: Current location in the file | |
| 1288 | + Side Effects: | |
| 1289 | + The FSerrno variable will be changed | |
| 1290 | + Description: | |
| 1291 | + The FSftell function will return the current position in the | |
| 1292 | + file pointed to by 'fo' by returning the 'seek' variable in the | |
| 1293 | + FSFILE object, which is used to keep track of the absolute | |
| 1294 | + location of the current position in the file. | |
| 1295 | + Remarks: | |
| 1296 | + None | |
| 1297 | + *******************************************************************/ | |
| 1298 | + | |
| 1299 | +long FSftell(FSFILE *fo); | |
| 1300 | + | |
| 1301 | + | |
| 1302 | +/**************************************************** | |
| 1303 | + Function: | |
| 1304 | + int FSfeof( FSFILE * stream ) | |
| 1305 | + Summary: | |
| 1306 | + Indicate whether the current file position is at the end | |
| 1307 | + Conditions: | |
| 1308 | + File is open in a read mode | |
| 1309 | + Input: | |
| 1310 | + stream - Pointer to the target file | |
| 1311 | + Return Values: | |
| 1312 | + Non-Zero - EOF reached | |
| 1313 | + 0 - Not at end of File | |
| 1314 | + Side Effects: | |
| 1315 | + The FSerrno variable will be changed. | |
| 1316 | + Description: | |
| 1317 | + The FSfeof function will indicate that the end-of- | |
| 1318 | + file has been reached for the specified file by | |
| 1319 | + comparing the absolute location in the file to the | |
| 1320 | + size of the file. | |
| 1321 | + Remarks: | |
| 1322 | + None. | |
| 1323 | + ****************************************************/ | |
| 1324 | + | |
| 1325 | +int FSfeof( FSFILE * stream ); | |
| 1326 | + | |
| 1327 | + | |
| 1328 | +#ifdef ALLOW_FORMATS | |
| 1329 | +/******************************************************************* | |
| 1330 | + Function: | |
| 1331 | + int FSformat (char mode, long int serialNumber, char * volumeID) | |
| 1332 | + Summary: | |
| 1333 | + Formats a device | |
| 1334 | + Conditions: | |
| 1335 | + The device must possess a valid master boot record. | |
| 1336 | + Input: | |
| 1337 | + mode - - 0 - Just erase the FAT and root | |
| 1338 | + - 1 - Create a new boot sector | |
| 1339 | + serialNumber - Serial number to write to the card | |
| 1340 | + volumeID - Name of the card | |
| 1341 | + Return Values: | |
| 1342 | + 0 - Format was successful | |
| 1343 | + EOF - Format was unsuccessful | |
| 1344 | + Side Effects: | |
| 1345 | + The FSerrno variable will be changed. | |
| 1346 | + Description: | |
| 1347 | + The FSformat function can be used to create a new boot sector | |
| 1348 | + on a device, based on the information in the master boot record. | |
| 1349 | + This function will first initialize the I/O pins and the device, | |
| 1350 | + and then attempts to read the master boot record. If the MBR | |
| 1351 | + cannot be loaded successfully, the function will fail. Next, if | |
| 1352 | + the 'mode' argument is specified as '0' the existing boot sector | |
| 1353 | + information will be loaded. If the 'mode' argument is '1' an | |
| 1354 | + entirely new boot sector will be constructed using the disk | |
| 1355 | + values from the master boot record. Once the boot sector has | |
| 1356 | + been successfully loaded/created, the locations of the FAT and | |
| 1357 | + root will be loaded from it, and they will be completely | |
| 1358 | + erased. If the user has specified a volumeID parameter, a | |
| 1359 | + VOLUME attribute entry will be created in the root directory | |
| 1360 | + to name the device. | |
| 1361 | + | |
| 1362 | + FAT12, FAT16 and FAT32 formatting are supported. | |
| 1363 | + | |
| 1364 | + Based on the number of sectors, the format function automatically | |
| 1365 | + compute the smallest possible value for the cluster size in order to | |
| 1366 | + accommodate the physical size of the media. In this case, if a media | |
| 1367 | + with a big capacity is formatted, the format function may take a very | |
| 1368 | + long time to write all the FAT tables. | |
| 1369 | + | |
| 1370 | + Therefore, the FORMAT_SECTORS_PER_CLUSTER macro may be used to | |
| 1371 | + specify the exact cluster size (in multiples of sector size). This | |
| 1372 | + macro can be defined in FSconfig.h | |
| 1373 | + | |
| 1374 | + Remarks: | |
| 1375 | + Only devices with a sector size of 512 bytes are supported by the | |
| 1376 | + format function | |
| 1377 | + *******************************************************************/ | |
| 1378 | + | |
| 1379 | +int FSformat (char mode, long int serialNumber, char * volumeID); | |
| 1380 | +#endif | |
| 1381 | + | |
| 1382 | + | |
| 1383 | +#ifdef ALLOW_WRITES | |
| 1384 | +/*************************************************************************** | |
| 1385 | + Function: | |
| 1386 | + int FSattrib (FSFILE * file, unsigned char attributes) | |
| 1387 | + Summary: | |
| 1388 | + Change the attributes of a file | |
| 1389 | + Conditions: | |
| 1390 | + File opened | |
| 1391 | + Input: | |
| 1392 | + file - Pointer to file structure | |
| 1393 | + attributes - The attributes to set for the file | |
| 1394 | + - Attribute - Value - Indications | |
| 1395 | + - ATTR_READ_ONLY - 0x01 - The read-only attribute | |
| 1396 | + - ATTR_HIDDEN - 0x02 - The hidden attribute | |
| 1397 | + - ATTR_SYSTEM - 0x04 - The system attribute | |
| 1398 | + - ATTR_ARCHIVE - 0x20 - The archive attribute | |
| 1399 | + Return Values: | |
| 1400 | + 0 - Attribute change was successful | |
| 1401 | + -1 - Attribute change was unsuccessful | |
| 1402 | + Side Effects: | |
| 1403 | + The FSerrno variable will be changed. | |
| 1404 | + Description: | |
| 1405 | + The FSattrib funciton will set the attributes of the specified file | |
| 1406 | + to the attributes passed in by the user. This function will load the | |
| 1407 | + file entry, replace the attributes with the ones specified, and write | |
| 1408 | + the attributes back. If the specified file is a directory, the | |
| 1409 | + directory attribute will be preserved. | |
| 1410 | + Remarks: | |
| 1411 | + None | |
| 1412 | + ***************************************************************************/ | |
| 1413 | + | |
| 1414 | +int FSattrib (FSFILE * file, unsigned char attributes); | |
| 1415 | + | |
| 1416 | + | |
| 1417 | +/*************************************************************** | |
| 1418 | + Function: | |
| 1419 | + int FSrename (const rom char * fileName, FSFILE * fo) | |
| 1420 | + Summary: | |
| 1421 | + Change the Ascii name of a file or directory | |
| 1422 | + Conditions: | |
| 1423 | + File opened. | |
| 1424 | + Input: | |
| 1425 | + fileName - The new name of the file | |
| 1426 | + fo - The file to rename | |
| 1427 | + Return Values: | |
| 1428 | + 0 - File was renamed successfully | |
| 1429 | + EOF - File was not renamed | |
| 1430 | + Side Effects: | |
| 1431 | + The FSerrno variable will be changed. | |
| 1432 | + Description: | |
| 1433 | + The FSrename function will rename a file. First, it will | |
| 1434 | + search through the current working directory to ensure the | |
| 1435 | + specified new filename is not already in use. If it isn't, | |
| 1436 | + the new filename will be written to the file entry of the | |
| 1437 | + file pointed to by 'fo.' | |
| 1438 | + Remarks: | |
| 1439 | + None | |
| 1440 | + ***************************************************************/ | |
| 1441 | + | |
| 1442 | +int FSrename (const char * fileName, FSFILE * fo); | |
| 1443 | + | |
| 1444 | +#ifdef SUPPORT_LFN | |
| 1445 | +/*************************************************************** | |
| 1446 | + Function: | |
| 1447 | + int wFSrename (const rom unsigned short int * fileName, FSFILE * fo) | |
| 1448 | + Summary: | |
| 1449 | + Change the name of a file or directory to the UTF16 input fileName | |
| 1450 | + Conditions: | |
| 1451 | + File opened. | |
| 1452 | + Input: | |
| 1453 | + fileName - The new name of the file | |
| 1454 | + fo - The file to rename | |
| 1455 | + Return Values: | |
| 1456 | + 0 - File was renamed successfully | |
| 1457 | + EOF - File was not renamed | |
| 1458 | + Side Effects: | |
| 1459 | + The FSerrno variable will be changed. | |
| 1460 | + Description: | |
| 1461 | + The wFSrename function will rename a file. First, it will | |
| 1462 | + search through the current working directory to ensure the | |
| 1463 | + specified new UTF16 filename is not already in use. If it isn't, | |
| 1464 | + the new filename will be written to the file entry of the | |
| 1465 | + file pointed to by 'fo.' | |
| 1466 | + Remarks: | |
| 1467 | + None | |
| 1468 | + ***************************************************************/ | |
| 1469 | + | |
| 1470 | +int wFSrename (const unsigned short int * fileName, FSFILE * fo); | |
| 1471 | +#endif | |
| 1472 | + | |
| 1473 | +/********************************************************************* | |
| 1474 | + Function: | |
| 1475 | + int FSremove (const char * fileName) | |
| 1476 | + Summary: | |
| 1477 | + Delete a Ascii file | |
| 1478 | + Conditions: | |
| 1479 | + File not opened, file exists | |
| 1480 | + Input: | |
| 1481 | + fileName - Name of the file to erase | |
| 1482 | + Return Values: | |
| 1483 | + 0 - File removed | |
| 1484 | + EOF - File was not removed | |
| 1485 | + Side Effects: | |
| 1486 | + The FSerrno variable will be changed. | |
| 1487 | + Description: | |
| 1488 | + The FSremove function will attempt to find the specified file with | |
| 1489 | + the FILEfind function. If the file is found, it will be erased | |
| 1490 | + using the FILEerase function.The user can also provide ascii alias name | |
| 1491 | + of the ascii long file name as the input to this function to get it erased | |
| 1492 | + from the memory. | |
| 1493 | + Remarks: | |
| 1494 | + None | |
| 1495 | + **********************************************************************/ | |
| 1496 | + | |
| 1497 | +int FSremove (const char * fileName); | |
| 1498 | + | |
| 1499 | +#ifdef SUPPORT_LFN | |
| 1500 | +/********************************************************************* | |
| 1501 | + Function: | |
| 1502 | + int wFSremove (const unsigned short int * fileName) | |
| 1503 | + Summary: | |
| 1504 | + Delete a UTF16 file | |
| 1505 | + Conditions: | |
| 1506 | + File not opened, file exists | |
| 1507 | + Input: | |
| 1508 | + fileName - Name of the file to erase | |
| 1509 | + Return Values: | |
| 1510 | + 0 - File removed | |
| 1511 | + EOF - File was not removed | |
| 1512 | + Side Effects: | |
| 1513 | + The FSerrno variable will be changed. | |
| 1514 | + Description: | |
| 1515 | + The wFSremove function will attempt to find the specified UTF16 file | |
| 1516 | + name with the FILEfind function. If the file is found, it will be erased | |
| 1517 | + using the FILEerase function. | |
| 1518 | + Remarks: | |
| 1519 | + None | |
| 1520 | + **********************************************************************/ | |
| 1521 | + | |
| 1522 | +int wFSremove (const unsigned short int * fileName); | |
| 1523 | +#endif | |
| 1524 | + | |
| 1525 | +/********************************************************************************* | |
| 1526 | + Function: | |
| 1527 | + size_t FSfwrite(const void *ptr, size_t size, size_t n, FSFILE *stream) | |
| 1528 | + Summary: | |
| 1529 | + Write data to a file | |
| 1530 | + Conditions: | |
| 1531 | + File opened in WRITE, APPEND, WRITE+, APPEND+, READ+ mode | |
| 1532 | + Input: | |
| 1533 | + ptr - Pointer to source buffer | |
| 1534 | + size - Size of units in bytes | |
| 1535 | + n - Number of units to transfer | |
| 1536 | + stream - Pointer to file structure | |
| 1537 | + Return: | |
| 1538 | + size_t - number of units written | |
| 1539 | + Side Effects: | |
| 1540 | + The FSerrno variable will be changed. | |
| 1541 | + Description: | |
| 1542 | + The FSfwrite function will write data to a file. First, the sector that | |
| 1543 | + corresponds to the current position in the file will be loaded (if it hasn't | |
| 1544 | + already been cached in the global data buffer). Data will then be written to | |
| 1545 | + the device from the specified buffer until the specified amount has been written. | |
| 1546 | + If the end of a cluster is reached, the next cluster will be loaded, unless | |
| 1547 | + the end-of-file flag for the specified file has been set. If it has, a new | |
| 1548 | + cluster will be allocated to the file. Finally, the new position and filesize | |
| 1549 | + will be stored in the FSFILE object. The parameters 'size' and 'n' indicate how | |
| 1550 | + much data to write. 'Size' refers to the size of one object to write (in bytes), | |
| 1551 | + and 'n' will refer to the number of these objects to write. The value returned | |
| 1552 | + will be equal to 'n' unless an error occured. | |
| 1553 | + Remarks: | |
| 1554 | + None. | |
| 1555 | + *********************************************************************************/ | |
| 1556 | + | |
| 1557 | +size_t FSfwrite(const void *ptr, size_t size, size_t n, FSFILE *stream); | |
| 1558 | + | |
| 1559 | +#endif | |
| 1560 | + | |
| 1561 | +#ifdef ALLOW_DIRS | |
| 1562 | + | |
| 1563 | + | |
| 1564 | +/************************************************************************** | |
| 1565 | + Function: | |
| 1566 | + int FSchdir (char * path) | |
| 1567 | + Summary: | |
| 1568 | + Change the current working directory as per the path specified in Ascii format | |
| 1569 | + Conditions: | |
| 1570 | + None | |
| 1571 | + Input: | |
| 1572 | + path - The path of the directory to change to. | |
| 1573 | + Return Values: | |
| 1574 | + 0 - The current working directory was changed successfully | |
| 1575 | + EOF - The current working directory could not be changed | |
| 1576 | + Side Effects: | |
| 1577 | + The current working directory may be changed. The FSerrno variable will | |
| 1578 | + be changed. | |
| 1579 | + Description: | |
| 1580 | + The FSchdir function passes a RAM pointer to the path to the | |
| 1581 | + chdirhelper function. | |
| 1582 | + Remarks: | |
| 1583 | + None | |
| 1584 | + **************************************************************************/ | |
| 1585 | + | |
| 1586 | +int FSchdir (char * path); | |
| 1587 | + | |
| 1588 | +#ifdef SUPPORT_LFN | |
| 1589 | +/************************************************************************** | |
| 1590 | + Function: | |
| 1591 | + int wFSchdir (unsigned short int * path) | |
| 1592 | + Summary: | |
| 1593 | + Change the current working directory as per the path specified in UTF16 format | |
| 1594 | + Conditions: | |
| 1595 | + None | |
| 1596 | + Input: | |
| 1597 | + path - The path of the directory to change to. | |
| 1598 | + Return Values: | |
| 1599 | + 0 - The current working directory was changed successfully | |
| 1600 | + EOF - The current working directory could not be changed | |
| 1601 | + Side Effects: | |
| 1602 | + The current working directory may be changed. The FSerrno variable will | |
| 1603 | + be changed. | |
| 1604 | + Description: | |
| 1605 | + The FSchdir function passes a RAM pointer to the path to the | |
| 1606 | + chdirhelper function. | |
| 1607 | + Remarks: | |
| 1608 | + None | |
| 1609 | + **************************************************************************/ | |
| 1610 | + | |
| 1611 | +int wFSchdir (unsigned short int * path); | |
| 1612 | +#endif | |
| 1613 | + | |
| 1614 | +/************************************************************** | |
| 1615 | + Function: | |
| 1616 | + char * FSgetcwd (char * path, int numchars) | |
| 1617 | + Summary: | |
| 1618 | + Get the current working directory path in Ascii format | |
| 1619 | + Conditions: | |
| 1620 | + None | |
| 1621 | + Input: | |
| 1622 | + path - Pointer to the array to return the cwd name in | |
| 1623 | + numchars - Number of chars in the path | |
| 1624 | + Return Values: | |
| 1625 | + char * - The cwd name string pointer (path or defaultArray) | |
| 1626 | + NULL - The current working directory name could not be loaded. | |
| 1627 | + Side Effects: | |
| 1628 | + The FSerrno variable will be changed | |
| 1629 | + Description: | |
| 1630 | + The FSgetcwd function will get the name of the current | |
| 1631 | + working directory and return it to the user. The name | |
| 1632 | + will be copied into the buffer pointed to by 'path,' | |
| 1633 | + starting at the root directory and copying as many chars | |
| 1634 | + as possible before the end of the buffer. The buffer | |
| 1635 | + size is indicated by the 'numchars' argument. The first | |
| 1636 | + thing this function will do is load the name of the current | |
| 1637 | + working directory, if it isn't already present. This could | |
| 1638 | + occur if the user switched to the dotdot entry of a | |
| 1639 | + subdirectory immediately before calling this function. The | |
| 1640 | + function will then copy the current working directory name | |
| 1641 | + into the buffer backwards, and insert a backslash character. | |
| 1642 | + Next, the function will continuously switch to the previous | |
| 1643 | + directories and copy their names backwards into the buffer | |
| 1644 | + until it reaches the root. If the buffer overflows, it | |
| 1645 | + will be treated as a circular buffer, and data will be | |
| 1646 | + copied over existing characters, starting at the beginning. | |
| 1647 | + Once the root directory is reached, the text in the buffer | |
| 1648 | + will be swapped, so that the buffer contains as much of the | |
| 1649 | + current working directory name as possible, starting at the | |
| 1650 | + root. | |
| 1651 | + Remarks: | |
| 1652 | + None | |
| 1653 | + **************************************************************/ | |
| 1654 | + | |
| 1655 | +char * FSgetcwd (char * path, int numbchars); | |
| 1656 | + | |
| 1657 | +#ifdef SUPPORT_LFN | |
| 1658 | +/************************************************************** | |
| 1659 | + Function: | |
| 1660 | + char * wFSgetcwd (unsigned short int * path, int numchars) | |
| 1661 | + Summary: | |
| 1662 | + Get the current working directory path in UTF16 format | |
| 1663 | + Conditions: | |
| 1664 | + None | |
| 1665 | + Input: | |
| 1666 | + path - Pointer to the array to return the cwd name in | |
| 1667 | + numchars - Number of chars in the path | |
| 1668 | + Return Values: | |
| 1669 | + char * - The cwd name string pointer (path or defaultArray) | |
| 1670 | + NULL - The current working directory name could not be loaded. | |
| 1671 | + Side Effects: | |
| 1672 | + The FSerrno variable will be changed | |
| 1673 | + Description: | |
| 1674 | + The FSgetcwd function will get the name of the current | |
| 1675 | + working directory and return it to the user. The name | |
| 1676 | + will be copied into the buffer pointed to by 'path,' | |
| 1677 | + starting at the root directory and copying as many chars | |
| 1678 | + as possible before the end of the buffer. The buffer | |
| 1679 | + size is indicated by the 'numchars' argument. The first | |
| 1680 | + thing this function will do is load the name of the current | |
| 1681 | + working directory, if it isn't already present. This could | |
| 1682 | + occur if the user switched to the dotdot entry of a | |
| 1683 | + subdirectory immediately before calling this function. The | |
| 1684 | + function will then copy the current working directory name | |
| 1685 | + into the buffer backwards, and insert a backslash character. | |
| 1686 | + Next, the function will continuously switch to the previous | |
| 1687 | + directories and copy their names backwards into the buffer | |
| 1688 | + until it reaches the root. If the buffer overflows, it | |
| 1689 | + will be treated as a circular buffer, and data will be | |
| 1690 | + copied over existing characters, starting at the beginning. | |
| 1691 | + Once the root directory is reached, the text in the buffer | |
| 1692 | + will be swapped, so that the buffer contains as much of the | |
| 1693 | + current working directory name as possible, starting at the | |
| 1694 | + root. | |
| 1695 | + Remarks: | |
| 1696 | + None | |
| 1697 | + **************************************************************/ | |
| 1698 | + | |
| 1699 | +char * wFSgetcwd (unsigned short int * path, int numbchars); | |
| 1700 | +#endif | |
| 1701 | + | |
| 1702 | +#ifdef ALLOW_WRITES | |
| 1703 | + | |
| 1704 | +/************************************************************************** | |
| 1705 | + Function: | |
| 1706 | + int FSmkdir (char * path) | |
| 1707 | + Summary: | |
| 1708 | + Create a directory as per the Ascii input path | |
| 1709 | + Conditions: | |
| 1710 | + None | |
| 1711 | + Input: | |
| 1712 | + path - The path of directories to create. | |
| 1713 | + Return Values: | |
| 1714 | + 0 - The specified directory was created successfully | |
| 1715 | + EOF - The specified directory could not be created | |
| 1716 | + Side Effects: | |
| 1717 | + Will create all non-existent directories in the path. The FSerrno | |
| 1718 | + variable will be changed. | |
| 1719 | + Description: | |
| 1720 | + The FSmkdir function passes a RAM pointer to the path to the | |
| 1721 | + mkdirhelper function. | |
| 1722 | + Remarks: | |
| 1723 | + None | |
| 1724 | + **************************************************************************/ | |
| 1725 | + | |
| 1726 | +int FSmkdir (char * path); | |
| 1727 | + | |
| 1728 | +#ifdef SUPPORT_LFN | |
| 1729 | +/************************************************************************** | |
| 1730 | + Function: | |
| 1731 | + int wFSmkdir (unsigned short int * path) | |
| 1732 | + Summary: | |
| 1733 | + Create a directory as per the UTF16 input path | |
| 1734 | + Conditions: | |
| 1735 | + None | |
| 1736 | + Input: | |
| 1737 | + path - The path of directories to create. | |
| 1738 | + Return Values: | |
| 1739 | + 0 - The specified directory was created successfully | |
| 1740 | + EOF - The specified directory could not be created | |
| 1741 | + Side Effects: | |
| 1742 | + Will create all non-existent directories in the path. The FSerrno | |
| 1743 | + variable will be changed. | |
| 1744 | + Description: | |
| 1745 | + The wFSmkdir function passes a RAM pointer to the path to the | |
| 1746 | + mkdirhelper function. | |
| 1747 | + Remarks: | |
| 1748 | + None | |
| 1749 | + **************************************************************************/ | |
| 1750 | + | |
| 1751 | +int wFSmkdir (unsigned short int * path); | |
| 1752 | +#endif | |
| 1753 | + | |
| 1754 | +/************************************************************************** | |
| 1755 | + Function: | |
| 1756 | + int FSrmdir (char * path) | |
| 1757 | + Summary: | |
| 1758 | + Delete a directory as per the Ascii input path | |
| 1759 | + Conditions: | |
| 1760 | + None | |
| 1761 | + Input: | |
| 1762 | + path - The path of the directory to remove | |
| 1763 | + rmsubdirs - | |
| 1764 | + - TRUE - All sub-dirs and files in the target dir will be removed | |
| 1765 | + - FALSE - FSrmdir will not remove non-empty directories | |
| 1766 | + Return Values: | |
| 1767 | + 0 - The specified directory was deleted successfully | |
| 1768 | + EOF - The specified directory could not be deleted | |
| 1769 | + Side Effects: | |
| 1770 | + The FSerrno variable will be changed. | |
| 1771 | + Description: | |
| 1772 | + The FSrmdir function passes a RAM pointer to the path to the | |
| 1773 | + rmdirhelper function. | |
| 1774 | + Remarks: | |
| 1775 | + None. | |
| 1776 | + **************************************************************************/ | |
| 1777 | + | |
| 1778 | +int FSrmdir (char * path, unsigned char rmsubdirs); | |
| 1779 | + | |
| 1780 | +#ifdef SUPPORT_LFN | |
| 1781 | +/************************************************************************** | |
| 1782 | + Function: | |
| 1783 | + int wFSrmdir (unsigned short int * path, unsigned char rmsubdirs) | |
| 1784 | + Summary: | |
| 1785 | + Delete a directory as per the UTF16 input path | |
| 1786 | + Conditions: | |
| 1787 | + None | |
| 1788 | + Input: | |
| 1789 | + path - The path of the directory to remove | |
| 1790 | + rmsubdirs - | |
| 1791 | + - TRUE - All sub-dirs and files in the target dir will be removed | |
| 1792 | + - FALSE - FSrmdir will not remove non-empty directories | |
| 1793 | + Return Values: | |
| 1794 | + 0 - The specified directory was deleted successfully | |
| 1795 | + EOF - The specified directory could not be deleted | |
| 1796 | + Side Effects: | |
| 1797 | + The FSerrno variable will be changed. | |
| 1798 | + Description: | |
| 1799 | + The wFSrmdir function passes a RAM pointer to the path to the | |
| 1800 | + rmdirhelper function. | |
| 1801 | + Remarks: | |
| 1802 | + None. | |
| 1803 | + **************************************************************************/ | |
| 1804 | + | |
| 1805 | +int wFSrmdir (unsigned short int * path, unsigned char rmsubdirs); | |
| 1806 | +#endif | |
| 1807 | + | |
| 1808 | +#endif | |
| 1809 | + | |
| 1810 | +#endif | |
| 1811 | + | |
| 1812 | +#ifdef USERDEFINEDCLOCK | |
| 1813 | + | |
| 1814 | + | |
| 1815 | +/*********************************************************************************************************** | |
| 1816 | + Function: | |
| 1817 | + int SetClockVars (unsigned int year, unsigned char month, unsigned char day, unsigned char hour, unsigned char minute, unsigned char second) | |
| 1818 | + Summary: | |
| 1819 | + Manually set timestamp variables | |
| 1820 | + Conditions: | |
| 1821 | + USERDEFINEDCLOCK macro defined in FSconfig.h. | |
| 1822 | + Input: | |
| 1823 | + year - The year (1980\-2107) | |
| 1824 | + month - The month (1\-12) | |
| 1825 | + day - The day of the month (1\-31) | |
| 1826 | + hour - The hour (0\-23) | |
| 1827 | + minute - The minute (0\-59) | |
| 1828 | + second - The second (0\-59) | |
| 1829 | + Return Values: | |
| 1830 | + None | |
| 1831 | + Side Effects: | |
| 1832 | + Modifies global timing variables | |
| 1833 | + Description: | |
| 1834 | + Lets the user manually set the timing variables. The values passed in will be converted to the format | |
| 1835 | + used by the FAT timestamps. | |
| 1836 | + Remarks: | |
| 1837 | + Call this before creating a file or directory (set create time) and | |
| 1838 | + before closing a file (set last access time, last modified time) | |
| 1839 | + ***********************************************************************************************************/ | |
| 1840 | + | |
| 1841 | +int SetClockVars (unsigned int year, unsigned char month, unsigned char day, unsigned char hour, unsigned char minute, unsigned char second); | |
| 1842 | +#endif | |
| 1843 | + | |
| 1844 | + | |
| 1845 | +#ifdef ALLOW_FILESEARCH | |
| 1846 | + | |
| 1847 | +/*********************************************************************************** | |
| 1848 | + Function: | |
| 1849 | + int FindFirst (const char * fileName, unsigned int attr, SearchRec * rec) | |
| 1850 | + Summary: | |
| 1851 | + Initial search function for the input Ascii fileName | |
| 1852 | + Conditions: | |
| 1853 | + None | |
| 1854 | + Input: | |
| 1855 | + fileName - The name to search for | |
| 1856 | + - Parital string search characters | |
| 1857 | + - * - Indicates the rest of the filename or extension can vary (e.g. FILE.*) | |
| 1858 | + - ? - Indicates that one character in a filename can vary (e.g. F?LE.T?T) | |
| 1859 | + attr - The attributes that a found file may have | |
| 1860 | + - ATTR_READ_ONLY - File may be read only | |
| 1861 | + - ATTR_HIDDEN - File may be a hidden file | |
| 1862 | + - ATTR_SYSTEM - File may be a system file | |
| 1863 | + - ATTR_VOLUME - Entry may be a volume label | |
| 1864 | + - ATTR_DIRECTORY - File may be a directory | |
| 1865 | + - ATTR_ARCHIVE - File may have archive attribute | |
| 1866 | + - ATTR_MASK - All attributes | |
| 1867 | + rec - pointer to a structure to put the file information in | |
| 1868 | + Return Values: | |
| 1869 | + 0 - File was found | |
| 1870 | + -1 - No file matching the specified criteria was found | |
| 1871 | + Side Effects: | |
| 1872 | + Search criteria from previous FindFirst call on passed SearchRec object | |
| 1873 | + will be lost. "utf16LFNfound" is overwritten after subsequent FindFirst/FindNext | |
| 1874 | + operations.It is the responsibility of the application to read the "utf16LFNfound" | |
| 1875 | + before it is lost.The FSerrno variable will be changed. | |
| 1876 | + Description: | |
| 1877 | + The FindFirst function will search for a file based on parameters passed in | |
| 1878 | + by the user. This function will use the FILEfind function to parse through | |
| 1879 | + the current working directory searching for entries that match the specified | |
| 1880 | + parameters. If a file is found, its parameters are copied into the SearchRec | |
| 1881 | + structure, as are the initial parameters passed in by the user and the position | |
| 1882 | + of the file entry in the current working directory.If the return value of the | |
| 1883 | + function is 0 then "utf16LFNfoundLength" indicates whether the file found was | |
| 1884 | + long file name or short file name(8P3 format). The "utf16LFNfoundLength" is non-zero | |
| 1885 | + for long file name and is zero for 8P3 format."utf16LFNfound" points to the | |
| 1886 | + address of long file name if found during the operation. | |
| 1887 | + Remarks: | |
| 1888 | + Call FindFirst or FindFirstpgm before calling FindNext | |
| 1889 | + ***********************************************************************************/ | |
| 1890 | + | |
| 1891 | +int FindFirst (const char * fileName, unsigned int attr, SearchRec * rec); | |
| 1892 | + | |
| 1893 | +#ifdef SUPPORT_LFN | |
| 1894 | +/*********************************************************************************** | |
| 1895 | + Function: | |
| 1896 | + int wFindFirst (const unsigned short int * fileName, unsigned int attr, SearchRec * rec) | |
| 1897 | + Summary: | |
| 1898 | + Initial search function for the input UTF16 fileName | |
| 1899 | + Conditions: | |
| 1900 | + None | |
| 1901 | + Input: | |
| 1902 | + fileName - The name to search for | |
| 1903 | + - Parital string search characters | |
| 1904 | + - * - Indicates the rest of the filename or extension can vary (e.g. FILE.*) | |
| 1905 | + - ? - Indicates that one character in a filename can vary (e.g. F?LE.T?T) | |
| 1906 | + attr - The attributes that a found file may have | |
| 1907 | + - ATTR_READ_ONLY - File may be read only | |
| 1908 | + - ATTR_HIDDEN - File may be a hidden file | |
| 1909 | + - ATTR_SYSTEM - File may be a system file | |
| 1910 | + - ATTR_VOLUME - Entry may be a volume label | |
| 1911 | + - ATTR_DIRECTORY - File may be a directory | |
| 1912 | + - ATTR_ARCHIVE - File may have archive attribute | |
| 1913 | + - ATTR_MASK - All attributes | |
| 1914 | + rec - pointer to a structure to put the file information in | |
| 1915 | + Return Values: | |
| 1916 | + 0 - File was found | |
| 1917 | + -1 - No file matching the specified criteria was found | |
| 1918 | + Side Effects: | |
| 1919 | + Search criteria from previous wFindFirst call on passed SearchRec object | |
| 1920 | + will be lost. "utf16LFNfound" is overwritten after subsequent wFindFirst/FindNext | |
| 1921 | + operations.It is the responsibility of the application to read the "utf16LFNfound" | |
| 1922 | + before it is lost.The FSerrno variable will be changed. | |
| 1923 | + Description: | |
| 1924 | + The wFindFirst function will search for a file based on parameters passed in | |
| 1925 | + by the user. This function will use the FILEfind function to parse through | |
| 1926 | + the current working directory searching for entries that match the specified | |
| 1927 | + parameters. If a file is found, its parameters are copied into the SearchRec | |
| 1928 | + structure, as are the initial parameters passed in by the user and the position | |
| 1929 | + of the file entry in the current working directory.If the return value of the | |
| 1930 | + function is 0 then "utf16LFNfoundLength" indicates whether the file found was | |
| 1931 | + long file name or short file name(8P3 format). The "utf16LFNfoundLength" is non-zero | |
| 1932 | + for long file name and is zero for 8P3 format."utf16LFNfound" points to the | |
| 1933 | + address of long file name if found during the operation. | |
| 1934 | + Remarks: | |
| 1935 | + Call FindFirst or FindFirstpgm before calling FindNext | |
| 1936 | + ***********************************************************************************/ | |
| 1937 | + | |
| 1938 | +int wFindFirst (const unsigned short int * fileName, unsigned int attr, SearchRec * rec); | |
| 1939 | +#endif | |
| 1940 | + | |
| 1941 | +/********************************************************************** | |
| 1942 | + Function: | |
| 1943 | + int FindNext (SearchRec * rec) | |
| 1944 | + Summary: | |
| 1945 | + Sequential search function | |
| 1946 | + Conditions: | |
| 1947 | + None | |
| 1948 | + Input: | |
| 1949 | + rec - The structure to store the file information in | |
| 1950 | + Return Values: | |
| 1951 | + 0 - File was found | |
| 1952 | + -1 - No additional files matching the specified criteria were found | |
| 1953 | + Side Effects: | |
| 1954 | + Search criteria from previous FindNext call on passed SearchRec object | |
| 1955 | + will be lost. "utf16LFNfound" is overwritten after subsequent FindFirst/FindNext | |
| 1956 | + operations.It is the responsibility of the application to read the "utf16LFNfound" | |
| 1957 | + before it is lost.The FSerrno variable will be changed. | |
| 1958 | + Description: | |
| 1959 | + The FindNext function performs the same function as the FindFirst | |
| 1960 | + funciton, except it does not copy any search parameters into the | |
| 1961 | + SearchRec structure (only info about found files) and it begins | |
| 1962 | + searching at the last directory entry offset at which a file was | |
| 1963 | + found, rather than at the beginning of the current working | |
| 1964 | + directory.If the return value of the function is 0 then "utf16LFNfoundLength" | |
| 1965 | + indicates whether the file found was long file name or short file | |
| 1966 | + name(8P3 format). The "utf16LFNfoundLength" is non-zero for long file name | |
| 1967 | + and is zero for 8P3 format."utf16LFNfound" points to the address of long | |
| 1968 | + file name if found during the operation. | |
| 1969 | + Remarks: | |
| 1970 | + Call FindFirst or FindFirstpgm before calling this function | |
| 1971 | + **********************************************************************/ | |
| 1972 | + | |
| 1973 | +int FindNext (SearchRec * rec); | |
| 1974 | +#endif | |
| 1975 | + | |
| 1976 | + | |
| 1977 | +/********************************************************************** | |
| 1978 | + Function: | |
| 1979 | + // PIC24/30/33/32 | |
| 1980 | + int FSfprintf (FSFILE * fptr, const char * fmt, ...) | |
| 1981 | + // PIC18 | |
| 1982 | + int FSfpritnf (FSFILE * fptr, const rom char * fmt, ...) | |
| 1983 | + Summary: | |
| 1984 | + Function to write formatted strings to a file | |
| 1985 | + Conditions: | |
| 1986 | + For PIC18, integer promotion must be enabled in the project build | |
| 1987 | + options menu. File opened in a write mode. | |
| 1988 | + Input: | |
| 1989 | + fptr - A pointer to the file to write to. | |
| 1990 | + fmt - A string of characters and format specifiers to write to | |
| 1991 | + the file | |
| 1992 | + ... - Additional arguments inserted in the string by format | |
| 1993 | + specifiers | |
| 1994 | + Returns: | |
| 1995 | + The number of characters written to the file | |
| 1996 | + Side Effects: | |
| 1997 | + The FSerrno variable will be changed. | |
| 1998 | + Description: | |
| 1999 | + Writes a specially formatted string to a file. | |
| 2000 | + Remarks: | |
| 2001 | + Consult AN1045 for a full description of how to use format | |
| 2002 | + specifiers. | |
| 2003 | + **********************************************************************/ | |
| 2004 | + | |
| 2005 | +#ifdef ALLOW_FSFPRINTF | |
| 2006 | + #ifdef __18CXX | |
| 2007 | + int FSfprintf (FSFILE *fptr, const rom char *fmt, ...); | |
| 2008 | + #else | |
| 2009 | + int FSfprintf (FSFILE *fptr, const char * fmt, ...); | |
| 2010 | + #endif | |
| 2011 | +#endif | |
| 2012 | + | |
| 2013 | + | |
| 2014 | +/************************************************************************** | |
| 2015 | + Function: | |
| 2016 | + int FSerror (void) | |
| 2017 | + Summary: | |
| 2018 | + Return an error code for the last function call | |
| 2019 | + Conditions: | |
| 2020 | + The return value depends on the last function called. | |
| 2021 | + Input: | |
| 2022 | + None | |
| 2023 | + Side Effects: | |
| 2024 | + None. | |
| 2025 | + Return Values: | |
| 2026 | + FSInit - | |
| 2027 | + - CE_GOOD ・ No Error | |
| 2028 | + - CE_INIT_ERROR ・ The physical media could not be initialized | |
| 2029 | + - CE_BAD_SECTOR_READ ・ The MBR or the boot sector could not be | |
| 2030 | + read correctly | |
| 2031 | + - CE_BAD_PARITION ・ The MBR signature code was incorrect. | |
| 2032 | + - CE_NOT_FORMATTED ・ The boot sector signature code was incorrect or | |
| 2033 | + indicates an invalid number of bytes per sector. | |
| 2034 | + - CE_CARDFAT32 ・ The physical media is FAT32 type (only an error | |
| 2035 | + when FAT32 support is disabled). | |
| 2036 | + - CE_UNSUPPORTED_FS ・ The device is formatted with an unsupported file | |
| 2037 | + system (not FAT12 or 16). | |
| 2038 | + FSfopen - | |
| 2039 | + - CE_GOOD ・ No Error | |
| 2040 | + - CE_NOT_INIT ・ The device has not been initialized. | |
| 2041 | + - CE_TOO_MANY_FILES_OPEN ・ The function could not allocate any | |
| 2042 | + additional file information to the array | |
| 2043 | + of FSFILE structures or the heap. | |
| 2044 | + - CE_INVALID_FILENAME ・ The file name argument was invalid. | |
| 2045 | + - CE_INVALID_ARGUMENT ・ The user attempted to open a directory in a | |
| 2046 | + write mode or specified an invalid mode argument. | |
| 2047 | + - CE_FILE_NOT_FOUND ・ The specified file (which was to be opened in read | |
| 2048 | + mode) does not exist on the device. | |
| 2049 | + - CE_BADCACHEREAD ・ A read from the device failed. | |
| 2050 | + - CE_ERASE_FAIL ・ The existing file could not be erased (when opening | |
| 2051 | + a file in WRITE mode). | |
| 2052 | + - CE_DIR_FULL ・ The directory is full. | |
| 2053 | + - CE_DISK_FULL・ The data memory section is full. | |
| 2054 | + - CE_WRITE_ERROR ・ A write to the device failed. | |
| 2055 | + - CE_SEEK_ERROR ・ The current position in the file could not be set to | |
| 2056 | + the end (when the file was opened in APPEND mode). | |
| 2057 | + FSfclose - | |
| 2058 | + - CE_GOOD ・ No Error | |
| 2059 | + - CE_WRITE_ERROR ・ The existing data in the data buffer or the new file | |
| 2060 | + entry information could not be written to the device. | |
| 2061 | + - CE_BADCACHEREAD ・ The file entry information could not be cached | |
| 2062 | + FSfread - | |
| 2063 | + - CE_GOOD ・ No Error | |
| 2064 | + - CE_WRITEONLY ・ The file was opened in a write-only mode. | |
| 2065 | + - CE_WRITE_ERROR ・ The existing data in the data buffer could not be | |
| 2066 | + written to the device. | |
| 2067 | + - CE_BAD_SECTOR_READ ・ The data sector could not be read. | |
| 2068 | + - CE_EOF ・ The end of the file was reached. | |
| 2069 | + - CE_COULD_NOT_GET_CLUSTER ・Additional clusters in the file could not be loaded. | |
| 2070 | + FSfwrite - | |
| 2071 | + - CE_GOOD ・ No Error | |
| 2072 | + - CE_READONLY ・ The file was opened in a read-only mode. | |
| 2073 | + - CE_WRITE_PROTECTED ・ The device write-protect check function indicated | |
| 2074 | + that the device has been write-protected. | |
| 2075 | + - CE_WRITE_ERROR ・ There was an error writing data to the device. | |
| 2076 | + - CE_BADCACHEREAD ・ The data sector to be modified could not be read from | |
| 2077 | + the device. | |
| 2078 | + - CE_DISK_FULL ・ All data clusters on the device are in use. | |
| 2079 | + FSfseek - | |
| 2080 | + - CE_GOOD ・ No Error | |
| 2081 | + - CE_WRITE_ERROR ・ The existing data in the data buffer could not be | |
| 2082 | + written to the device. | |
| 2083 | + - CE_INVALID_ARGUMENT ・ The specified offset exceeds the size of the file. | |
| 2084 | + - CE_BADCACHEREAD ・ The sector that contains the new current position | |
| 2085 | + could not be loaded. | |
| 2086 | + - CE_COULD_NOT_GET_CLUSTER ・Additional clusters in the file could not be | |
| 2087 | + loaded/allocated. | |
| 2088 | + FSftell - | |
| 2089 | + - CE_GOOD ・ No Error | |
| 2090 | + FSattrib - | |
| 2091 | + - CE_GOOD ・ No Error | |
| 2092 | + - CE_INVALID_ARGUMENT ・ The attribute argument was invalid. | |
| 2093 | + - CE_BADCACHEREAD ・ The existing file entry information could not be | |
| 2094 | + loaded. | |
| 2095 | + - CE_WRITE_ERROR ・ The file entry information could not be written to | |
| 2096 | + the device. | |
| 2097 | + FSrename - | |
| 2098 | + - CE_GOOD ・ No Error | |
| 2099 | + - CE_FILENOTOPENED ・ A null file pointer was passed into the function. | |
| 2100 | + - CE_INVALID_FILENAME ・ The file name passed into the function was invalid. | |
| 2101 | + - CE_BADCACHEREAD ・ A read from the device failed. | |
| 2102 | + - CE_FILENAME_EXISTS ・ A file with the specified name already exists. | |
| 2103 | + - CE_WRITE_ERROR ・ The new file entry data could not be written to the | |
| 2104 | + device. | |
| 2105 | + FSfeof - | |
| 2106 | + - CE_GOOD ・ No Error | |
| 2107 | + FSformat - | |
| 2108 | + - CE_GOOD ・ No Error | |
| 2109 | + - CE_INIT_ERROR ・ The device could not be initialized. | |
| 2110 | + - CE_BADCACHEREAD ・ The master boot record or boot sector could not be | |
| 2111 | + loaded successfully. | |
| 2112 | + - CE_INVALID_ARGUMENT ・ The user selected to create their own boot sector on | |
| 2113 | + a device that has no master boot record, or the mode | |
| 2114 | + argument was invalid. | |
| 2115 | + - CE_WRITE_ERROR ・ The updated MBR/Boot sector could not be written to | |
| 2116 | + the device. | |
| 2117 | + - CE_BAD_PARTITION ・ The calculated number of sectors per clusters was | |
| 2118 | + invalid. | |
| 2119 | + - CE_NONSUPPORTED_SIZE ・ The card has too many sectors to be formatted as | |
| 2120 | + FAT12 or FAT16. | |
| 2121 | + FSremove - | |
| 2122 | + - CE_GOOD ・ No Error | |
| 2123 | + - CE_WRITE_PROTECTED ・ The device write-protect check function indicated | |
| 2124 | + that the device has been write-protected. | |
| 2125 | + - CE_INVALID_FILENAME ・ The specified filename was invalid. | |
| 2126 | + - CE_FILE_NOT_FOUND ・ The specified file could not be found. | |
| 2127 | + - CE_ERASE_FAIL ・ The file could not be erased. | |
| 2128 | + FSchdir - | |
| 2129 | + - CE_GOOD ・ No Error | |
| 2130 | + - CE_INVALID_ARGUMENT ・ The path string was mis-formed or the user tried to | |
| 2131 | + change to a non-directory file. | |
| 2132 | + - CE_BADCACHEREAD ・ A directory entry could not be cached. | |
| 2133 | + - CE_DIR_NOT_FOUND ・ Could not find a directory in the path. | |
| 2134 | + FSgetcwd - | |
| 2135 | + - CE_GOOD ・ No Error | |
| 2136 | + - CE_INVALID_ARGUMENT ・ The user passed a 0-length buffer into the function. | |
| 2137 | + - CE_BADCACHEREAD ・ A directory entry could not be cached. | |
| 2138 | + - CE_BAD_SECTOR_READ ・ The function could not determine a previous directory | |
| 2139 | + of the current working directory. | |
| 2140 | + FSmkdir - | |
| 2141 | + - CE_GOOD ・ No Error | |
| 2142 | + - CE_WRITE_PROTECTED ・ The device write-protect check function indicated | |
| 2143 | + that the device has been write-protected. | |
| 2144 | + - CE_INVALID_ARGUMENT ・ The path string was mis-formed. | |
| 2145 | + - CE_BADCACHEREAD ・ Could not successfully change to a recently created | |
| 2146 | + directory to store its dir entry information, or | |
| 2147 | + could not cache directory entry information. | |
| 2148 | + - CE_INVALID_FILENAME ・ One or more of the directory names has an invalid | |
| 2149 | + format. | |
| 2150 | + - CE_WRITE_ERROR ・ The existing data in the data buffer could not be | |
| 2151 | + written to the device or the dot/dotdot entries could | |
| 2152 | + not be written to a newly created directory. | |
| 2153 | + - CE_DIR_FULL ・ There are no available dir entries in the CWD. | |
| 2154 | + - CE_DISK_FULL ・ There are no available clusters in the data region of | |
| 2155 | + the device. | |
| 2156 | + FSrmdir - | |
| 2157 | + - CE_GOOD ・ No Error | |
| 2158 | + - CE_DIR_NOT_FOUND ・ The directory specified could not be found or the | |
| 2159 | + function could not change to a subdirectory within | |
| 2160 | + the directory to be deleted (when recursive delete is | |
| 2161 | + enabled). | |
| 2162 | + - CE_INVALID_ARGUMENT ・ The user tried to remove the CWD or root directory. | |
| 2163 | + - CE_BADCACHEREAD ・ A directory entry could not be cached. | |
| 2164 | + - CE_DIR_NOT_EMPTY ・ The directory to be deleted was not empty and | |
| 2165 | + recursive subdirectory removal was disabled. | |
| 2166 | + - CE_ERASE_FAIL ・ The directory or one of the directories or files | |
| 2167 | + within it could not be deleted. | |
| 2168 | + - CE_BAD_SECTOR_READ ・ The function could not determine a previous directory | |
| 2169 | + of the CWD. | |
| 2170 | + SetClockVars - | |
| 2171 | + - CE_GOOD ・ No Error | |
| 2172 | + - CE_INVALID_ARGUMENT ・ The time values passed into the function were | |
| 2173 | + invalid. | |
| 2174 | + FindFirst - | |
| 2175 | + - CE_GOOD ・ No Error | |
| 2176 | + - CE_INVALID_FILENAME ・ The specified filename was invalid. | |
| 2177 | + - CE_FILE_NOT_FOUND ・ No file matching the specified criteria was found. | |
| 2178 | + - CE_BADCACHEREAD ・ The file information for the file that was found | |
| 2179 | + could not be cached. | |
| 2180 | + FindNext - | |
| 2181 | + - CE_GOOD ・ No Error | |
| 2182 | + - CE_NOT_INIT ・ The SearchRec object was not initialized by a call to | |
| 2183 | + FindFirst. | |
| 2184 | + - CE_INVALID_ARGUMENT ・ The SearchRec object was initialized in a different | |
| 2185 | + directory from the CWD. | |
| 2186 | + - CE_INVALID_FILENAME ・ The filename is invalid. | |
| 2187 | + - CE_FILE_NOT_FOUND ・ No file matching the specified criteria was found. | |
| 2188 | + FSfprintf - | |
| 2189 | + - CE_GOOD ・ No Error | |
| 2190 | + - CE_WRITE_ERROR ・ Characters could not be written to the file. | |
| 2191 | + Description: | |
| 2192 | + The FSerror function will return the FSerrno variable. This global | |
| 2193 | + variable will have been set to an error value during the last call of a | |
| 2194 | + library function. | |
| 2195 | + Remarks: | |
| 2196 | + None | |
| 2197 | + **************************************************************************/ | |
| 2198 | + | |
| 2199 | +int FSerror (void); | |
| 2200 | + | |
| 2201 | + | |
| 2202 | +/********************************************************************************* | |
| 2203 | + Function: | |
| 2204 | + int FSCreateMBR (unsigned long firstSector, unsigned long numSectors) | |
| 2205 | + Summary: | |
| 2206 | + Creates a master boot record | |
| 2207 | + Conditions: | |
| 2208 | + The I/O pins for the device have been initialized by the InitIO function. | |
| 2209 | + Input: | |
| 2210 | + firstSector - The first sector of the partition on the device (cannot | |
| 2211 | + be 0; that's the MBR) | |
| 2212 | + numSectors - The number of sectors available in memory (including the | |
| 2213 | + MBR) | |
| 2214 | + Return Values: | |
| 2215 | + 0 - MBR was created successfully | |
| 2216 | + EOF - MBR could not be created | |
| 2217 | + Side Effects: | |
| 2218 | + None | |
| 2219 | + Description: | |
| 2220 | + This function can be used to create a master boot record for a device. Note | |
| 2221 | + that this function should not be used on a device that is already formatted | |
| 2222 | + with a master boot record (i.e. most SD cards, CF cards, USB keys). This | |
| 2223 | + function will fill the global data buffer with appropriate partition information | |
| 2224 | + for a FAT partition with a type determined by the number of sectors available | |
| 2225 | + to the partition. It will then write the MBR information to the first sector | |
| 2226 | + on the device. This function should be followed by a call to FSformat, which | |
| 2227 | + will create a boot sector, root dir, and FAT appropriate the the information | |
| 2228 | + contained in the new master boot record. Note that FSformat only supports | |
| 2229 | + FAT12 and FAT16 formatting at this time, and so cannot be used to format a | |
| 2230 | + device with more than 0x3FFD5F sectors. | |
| 2231 | + Remarks: | |
| 2232 | + This function can damage the device being used, and should not be called | |
| 2233 | + unless the user is sure about the size of the device and the first sector value. | |
| 2234 | + *********************************************************************************/ | |
| 2235 | + | |
| 2236 | +int FSCreateMBR (unsigned long firstSector, unsigned long numSectors); | |
| 2237 | + | |
| 2238 | + | |
| 2239 | +#ifdef ALLOW_GET_DISK_PROPERTIES | |
| 2240 | +/********************************************************************************* | |
| 2241 | + Function: | |
| 2242 | + void FSGetDiskProperties(FS_DISK_PROPERTIES* properties) | |
| 2243 | + Summary: | |
| 2244 | + Allows user to get the disk properties (size of disk, free space, etc) | |
| 2245 | + Conditions: | |
| 2246 | + 1) ALLOW_GET_DISK_PROPERTIES must be defined in FSconfig.h | |
| 2247 | + 2) a FS_DISK_PROPERTIES object must be created before the function is called | |
| 2248 | + 3) the new_request member of the FS_DISK_PROPERTIES object must be set before | |
| 2249 | + calling the function for the first time. This will start a new search. | |
| 2250 | + 4) this function should not be called while there is a file open. Close all | |
| 2251 | + files before calling this function. | |
| 2252 | + Input: | |
| 2253 | + properties - a pointer to a FS_DISK_PROPERTIES object where the results should | |
| 2254 | + be stored. | |
| 2255 | + Return Values: | |
| 2256 | + This function returns void. The properties_status of the previous call of | |
| 2257 | + this function is located in the properties.status field. This field has | |
| 2258 | + the following possible values: | |
| 2259 | + | |
| 2260 | + FS_GET_PROPERTIES_NO_ERRORS - operation completed without error. Results | |
| 2261 | + are in the properties object passed into the function. | |
| 2262 | + FS_GET_PROPERTIES_DISK_NOT_MOUNTED - there is no mounted disk. Results in | |
| 2263 | + properties object is not valid | |
| 2264 | + FS_GET_PROPERTIES_CLUSTER_FAILURE - there was a failure trying to read a | |
| 2265 | + cluster from the drive. The results in the properties object is a partial | |
| 2266 | + result up until the point of the failure. | |
| 2267 | + FS_GET_PROPERTIES_STILL_WORKING - the search for free sectors is still in | |
| 2268 | + process. Continue calling this function with the same properties pointer | |
| 2269 | + until either the function completes or until the partial results meets the | |
| 2270 | + application needs. The properties object contains the partial results of | |
| 2271 | + the search and can be used by the application. | |
| 2272 | + Side Effects: | |
| 2273 | + Can cause errors if called when files are open. Close all files before | |
| 2274 | + calling this function. | |
| 2275 | + | |
| 2276 | + Calling this function without setting the new_request member on the first | |
| 2277 | + call can result in undefined behavior and results. | |
| 2278 | + | |
| 2279 | + Calling this function after a result is returned other than | |
| 2280 | + FS_GET_PROPERTIES_STILL_WORKING can result in undefined behavior and results. | |
| 2281 | + Description: | |
| 2282 | + This function returns the information about the mounted drive. The results | |
| 2283 | + member of the properties object passed into the function is populated with | |
| 2284 | + the information about the drive. | |
| 2285 | + | |
| 2286 | + Before starting a new request, the new_request member of the properties | |
| 2287 | + input parameter should be set to TRUE. This will initiate a new search | |
| 2288 | + request. | |
| 2289 | + | |
| 2290 | + This function will return before the search is complete with partial results. | |
| 2291 | + All of the results except the free_clusters will be correct after the first | |
| 2292 | + call. The free_clusters will contain the number of free clusters found up | |
| 2293 | + until that point, thus the free_clusters result will continue to grow until | |
| 2294 | + the entire drive is searched. If an application only needs to know that a | |
| 2295 | + certain number of bytes is available and doesn't need to know the total free | |
| 2296 | + size, then this function can be called until the required free size is | |
| 2297 | + verified. To continue a search, pass a pointer to the same FS_DISK_PROPERTIES | |
| 2298 | + object that was passed in to create the search. | |
| 2299 | + | |
| 2300 | + A new search request sould be made once this function has returned a value | |
| 2301 | + other than FS_GET_PROPERTIES_STILL_WORKING. Continuing a completed search | |
| 2302 | + can result in undefined behavior or results. | |
| 2303 | + | |
| 2304 | + Typical Usage: | |
| 2305 | + <code> | |
| 2306 | + FS_DISK_PROPERTIES disk_properties; | |
| 2307 | + | |
| 2308 | + disk_properties.new_request = TRUE; | |
| 2309 | + | |
| 2310 | + do | |
| 2311 | + { | |
| 2312 | + FSGetDiskProperties(&disk_properties); | |
| 2313 | + } while (disk_properties.properties_status == FS_GET_PROPERTIES_STILL_WORKING); | |
| 2314 | + </code> | |
| 2315 | + | |
| 2316 | + results.disk_format - contains the format of the drive. Valid results are | |
| 2317 | + FAT12(1), FAT16(2), or FAT32(3). | |
| 2318 | + | |
| 2319 | + results.sector_size - the sector size of the mounted drive. Valid values are | |
| 2320 | + 512, 1024, 2048, and 4096. | |
| 2321 | + | |
| 2322 | + results.sectors_per_cluster - the number sectors per cluster. | |
| 2323 | + | |
| 2324 | + results.total_clusters - the number of total clusters on the drive. This | |
| 2325 | + can be used to calculate the total disk size (total_clusters * | |
| 2326 | + sectors_per_cluster * sector_size = total size of drive in bytes) | |
| 2327 | + | |
| 2328 | + results.free_clusters - the number of free (unallocated) clusters on the drive. | |
| 2329 | + This can be used to calculate the total free disk size (free_clusters * | |
| 2330 | + sectors_per_cluster * sector_size = total size of drive in bytes) | |
| 2331 | + | |
| 2332 | + Remarks: | |
| 2333 | + PIC24F size estimates: | |
| 2334 | + Flash - 400 bytes (-Os setting) | |
| 2335 | + | |
| 2336 | + PIC24F speed estimates: | |
| 2337 | + Search takes approximately 7 seconds per Gigabyte of drive space. Speed | |
| 2338 | + will vary based on the number of sectors per cluster and the sector size. | |
| 2339 | + *********************************************************************************/ | |
| 2340 | +void FSGetDiskProperties(FS_DISK_PROPERTIES* properties); | |
| 2341 | +#endif | |
| 2342 | + | |
| 2343 | + | |
| 2344 | +#endif |