BASIC compiler/interpreter for PIC32MX/MZ-80K (suspended)
Revisão | 268 (tree) |
---|---|
Hora | 2018-08-04 05:12:38 |
Autor | kmorimatsu |
Megalopa trunk
@@ -0,0 +1,140 @@ | ||
1 | +// lib_video_megalopa.h | |
2 | +// テキスト+グラフィックビデオ出力 PIC32MX370F512H用ヘッダーファイル by K.Tanaka | |
3 | + | |
4 | +#define X_RES 288 // Graphic横方向解像度 | |
5 | +#define X_RESW 384 // Graphic横方向解像度(ワイド時) | |
6 | +#define X_RESZ 256 // Graphic横方向解像度(type Z互換時) | |
7 | +#define Y_RES 216 // Graphic縦方向解像度 | |
8 | +#define Y_RESZ 224 // Graphic縦方向解像度(type Z互換時) | |
9 | +#define WIDTH_X 36 // 横方向文字数 | |
10 | +#define WIDTH_Y 27 // 縦方向文字数 | |
11 | +#define WIDTH_XW 48 // 横方向文字数(ワイド時) | |
12 | +#define WIDTH_XW2 64 // 横方向文字数(ワイド、6ドットフォント時) | |
13 | +#define WIDTH_XBW 80 // 横方向文字数(モノクロ時) | |
14 | +#define WIDTH_30 30 // 横方向文字数(互換モード8ドットフォント時) | |
15 | +#define WIDTH_40 40 // 横方向文字数(互換モード6ドットフォント時) | |
16 | +#define ATTROFFSET (WIDTH_X*WIDTH_Y) // TVRAM上のカラーパレット格納位置(標準時) | |
17 | +#define ATTROFFSETW (WIDTH_XW*WIDTH_Y) // TVRAM上のカラーパレット格納位置(ワイド時) | |
18 | +#define ATTROFFSETW2 (WIDTH_XW2*WIDTH_Y) // TVRAM上のカラーパレット格納位置(ワイド、6ドットフォント時) | |
19 | +#define ATTROFFSETBW (WIDTH_XBW*WIDTH_Y) // TVRAM上のカラーパレット格納位置(モノクロ時) | |
20 | +#define ATTROFFSET30 (WIDTH_30*WIDTH_Y) // TVRAM上のカラーパレット格納位置(互換モード8ドットフォント時) | |
21 | +#define ATTROFFSET40 (WIDTH_40*WIDTH_Y) // TVRAM上のカラーパレット格納位置(互換モード6ドットフォント時) | |
22 | +#define WIDTH_XMAX WIDTH_XBW // 横方向最大文字数 | |
23 | + | |
24 | +// videomode値 | |
25 | +#define VMODE_T30 0 // 標準テキスト30文字互換モード | |
26 | +#define VMODE_STDTEXT 1 // 標準テキスト36文字モード | |
27 | +#define VMODE_T40 2 // 標準テキスト40文字互換モード(6ドットフォント) | |
28 | +#define VMODE_WIDETEXT 3 // ワイドテキスト48文字モード | |
29 | +#define VMODE_WIDETEXT6dot 4 // ワイドテキスト64文字モード(6ドットフォント) | |
30 | +#define VMODE_MONOTEXT 5 // モノクロテキスト80文字モード | |
31 | +#define VMODE_ZOEAGRPH 16 // type Z互換グラフィックモード | |
32 | +#define VMODE_STDGRPH 17 // 標準グラフィック+テキスト36文字モード | |
33 | +#define VMODE_WIDEGRPH 18 // ワイドグラフィック+テキスト48文字モード | |
34 | + | |
35 | +// textomode値 | |
36 | +#define TMODE_T30 0 // 標準テキスト30文字互換モード | |
37 | +#define TMODE_STDTEXT 1 // 標準テキスト36文字モード | |
38 | +#define TMODE_T40 2 // 標準テキスト40文字互換モード(6ドットフォント) | |
39 | +#define TMODE_WIDETEXT 3 // ワイドテキスト48文字モード | |
40 | +#define TMODE_WIDETEXT6dot 4 // ワイドテキスト64文字モード(6ドットフォント) | |
41 | +#define TMODE_MONOTEXT 5 // モノクロテキスト80文字モード | |
42 | + | |
43 | +// graphmode値 | |
44 | +#define GMODE_NOGRPH 0 // グラフィック不使用 | |
45 | +#define GMODE_ZOEAGRPH 1 // type Z互換グラフィックモード | |
46 | +#define GMODE_STDGRPH 2 // 標準グラフィック+テキスト36文字モード | |
47 | +#define GMODE_WIDEGRPH 3 // ワイドグラフィック+テキスト48文字モード | |
48 | + | |
49 | +#define KEYPORT PORTD | |
50 | +#define KEYUP 0x0004 | |
51 | +#define KEYDOWN 0x0001 | |
52 | +#define KEYLEFT 0x0002 | |
53 | +#define KEYRIGHT 0x0008 | |
54 | +#define KEYSTART 0x0010 | |
55 | +#define KEYFIRE 0x0020 | |
56 | + | |
57 | +extern volatile char drawing; // 表示期間中は-1 | |
58 | +extern volatile unsigned short drawcount; // 1画面表示終了ごとに1足す。アプリ側で0にする。 | |
59 | + // 最低1回は画面表示したことのチェックと、アプリの処理が何画面期間必要かの確認に利用。 | |
60 | +extern unsigned char *GVRAM; // Graphicビデオメモリ | |
61 | +extern unsigned char TVRAM[]; // Characterビデオメモリ | |
62 | +extern const unsigned char FontData[]; //フォントパターン(初期化時にここからfontdata[]にコピー) | |
63 | +extern const unsigned char FontData2[]; //フォントパターン6ドットフォント | |
64 | +extern unsigned char videomode,textmode,graphmode; //画面モード | |
65 | +extern int twidth,twidthy; //テキスト文字数(横)および(縦 | |
66 | +extern int attroffset; // TVRAMのカラー情報エリア位置 | |
67 | +extern int gwidth,gwidthy; // グラフィックX方向解像度 | |
68 | +extern unsigned char fontdata[]; //固定フォント領域、初期化時にFontData[]からコピー | |
69 | +extern unsigned char *Fontp; //現在のフォントパターンの先頭アドレス | |
70 | + | |
71 | +void start_composite(void); //カラーコンポジット出力開始 | |
72 | +void stop_composite(void); //カラーコンポジット出力停止 | |
73 | +void init_composite(void); //カラーコンポジット出力初期化 | |
74 | +void init_palette(void); //カラーパレット初期化 | |
75 | +void g_clearscreen(void); //Graphic画面クリア | |
76 | +void clearscreen(void); //Character画面クリア | |
77 | +void set_palette(unsigned char n,unsigned char b,unsigned char r,unsigned char g); //カラーパレット設定 | |
78 | +void set_bgcolor(unsigned char b,unsigned char r,unsigned char g); // バックグラウンドカラー設定 | |
79 | +void set_videomode(unsigned char m, unsigned char *gvram); //ビデオモードの切り替え | |
80 | + | |
81 | +// 以下は text_graph_library.c ライブラリを使用するための宣言 | |
82 | + | |
83 | +// グラフィック画面関連 | |
84 | +void g_pset(int x,int y,unsigned int c); | |
85 | + // (x,y)の位置にカラーcで点を描画 | |
86 | +void g_putbmpmn(int x,int y,char m,char n,const unsigned char bmp[]); | |
87 | + // 横m*縦nドットのキャラクターを座標x,yに表示 | |
88 | + // unsigned char bmp[m*n]配列に、単純にカラー番号を並べる | |
89 | + // カラー番号が0の部分は透明色として扱う | |
90 | +void g_clrbmpmn(int x,int y,char m,char n); | |
91 | + // 縦m*横nドットのキャラクター消去 | |
92 | + // カラー0で塗りつぶし | |
93 | +void g_gline(int x1,int y1,int x2,int y2,unsigned int c); | |
94 | + // (x1,y1)-(x2,y2)にカラーcで線分を描画 | |
95 | +void g_hline(int x1,int x2,int y,unsigned int c); | |
96 | + // (x1,y)-(x2,y)の水平ラインをカラーcで高速描画 | |
97 | +void g_boxfill(int x1,int y1,int x2,int y2,unsigned int c); | |
98 | + //座標(x1,y1),(x2,y2)を対角線とするカラーcで塗られた長方形を描画 | |
99 | + // (x1,y1),(x2,y2)を対角線とするカラーcで塗られた長方形を描画 | |
100 | +void g_circle(int x0,int y0,unsigned int r,unsigned int c); | |
101 | + // (x0,y0)を中心に、半径r、カラーcの円を描画 | |
102 | +void g_circlefill(int x0,int y0,unsigned int r,unsigned int c); | |
103 | + // (x0,y0)を中心に、半径r、カラーcで塗られた円を描画 | |
104 | +void g_putfont(int x,int y,unsigned int c,int bc,unsigned char n); | |
105 | + //8*8ドットのアルファベットフォント表示 | |
106 | + //座標(x,y)、カラー番号c | |
107 | + //bc:バックグランドカラー、負数の場合無視 | |
108 | + //n:文字番号 | |
109 | +void g_printstr(int x,int y,unsigned int c,int bc,unsigned char *s); | |
110 | + //座標(x,y)からカラー番号cで文字列sを表示、bc:バックグランドカラー | |
111 | +void g_printnum(int x,int y,unsigned char c,int bc,unsigned int n); | |
112 | + //座標(x,y)にカラー番号cで数値nを表示、bc:バックグランドカラー | |
113 | +void g_printnum2(int x,int y,unsigned char c,int bc,unsigned int n,unsigned char e); | |
114 | + //座標(x,y)にカラー番号cで数値nを表示、bc:バックグランドカラー、e桁で表示 | |
115 | +unsigned int g_color(int x,int y); | |
116 | +//座標(x,y)のVRAM上の現在のパレット番号を返す、画面外は0を返す | |
117 | + | |
118 | +//テキスト画面関連 | |
119 | +extern unsigned char *cursor; | |
120 | +extern unsigned char cursorcolor; | |
121 | +void vramscroll(void); | |
122 | + //1行スクロール | |
123 | +void setcursor(unsigned char x,unsigned char y,unsigned char c); | |
124 | + //カーソル位置とカラーを設定 | |
125 | +void setcursorcolor(unsigned char c); | |
126 | + //カーソル位置そのままでカラー番号をcに設定 | |
127 | +void printchar(unsigned char n); | |
128 | + //カーソル位置にテキストコードnを1文字表示し、カーソルを1文字進める | |
129 | +void printstr(unsigned char *s); | |
130 | + //カーソル位置に文字列sを表示 | |
131 | +void printnum(unsigned int n); | |
132 | + //カーソル位置に符号なし整数nを10進数表示 | |
133 | +void printnum2(unsigned int n,unsigned char e); | |
134 | + //カーソル位置に符号なし整数nをe桁の10進数表示(前の空き桁部分はスペースで埋める) | |
135 | +void cls(void); | |
136 | + //テキスト画面を0でクリアし、カーソルを画面先頭に移動 | |
137 | +void startPCG(unsigned char *p,int a); | |
138 | + // RAMフォント(PCG)の利用開始、pがフォント格納場所、aが0以外でシステムフォントをコピー | |
139 | +void stopPCG(void); | |
140 | + // RAMフォント(PCG)の利用停止 |
@@ -0,0 +1,360 @@ | ||
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 Megalopa | |
10 | +// KM-BASIC 統合開発実行環境 for PIC32MX370F512H by K.Tanaka | |
11 | + | |
12 | +// 利用システム | |
13 | +// ps2keyboard370f.X.a : PS/2キーボード入力システムライブラリ | |
14 | +// lib_videoout_megalopa.X.a : カラービデオ信号出力システムライブラリ | |
15 | +// sdfsio370fLib.a : SDカードアクセス用ライブラリ | |
16 | + | |
17 | + | |
18 | +/* | |
19 | + PIC32MX ペリフェラル使用状況 | |
20 | + | |
21 | + 割り込み | |
22 | + NTSC, Timer2, vector 8, priority 5 | |
23 | + NTSC, OC5, vector 22, priority 5 | |
24 | + NTSC, OC2, vector 10, priority 5 | |
25 | + NTSC, OC1, vector 6, priority 5 | |
26 | + PS/2, CNF, vector 33, priority 6 | |
27 | + PS/2, Timer5, vector 20, priority 4 | |
28 | + MUSIC, CS0, vector 1, priority 2 | |
29 | + SERIAL, UART, vector 31, priority 3 | |
30 | + | |
31 | + タイマー | |
32 | + Timer1 未使用 | |
33 | + Timer2 NTSC | |
34 | + Timer3 MUSIC/PWM | |
35 | + Timer4 MUSIC | |
36 | + Timer5 PS/2 | |
37 | + | |
38 | + DMA | |
39 | + DMA0 未使用 | |
40 | + DMA1 MUSIC | |
41 | + DMA2 MUSIC | |
42 | + DMA3 PS/2 | |
43 | + | |
44 | + Output compair | |
45 | + OC1 NTSC | |
46 | + OC2 NTSC | |
47 | + OC3 MUSIC/PWM | |
48 | + OC4 MUSIC/PWM | |
49 | + OC5 NTSC | |
50 | + | |
51 | + UART | |
52 | + UART1 シリアル通信 | |
53 | + UART2 未使用 | |
54 | + | |
55 | + SPI | |
56 | + SPI1 SPI通信(予定) | |
57 | + SPI2 マルチメディアカード | |
58 | + | |
59 | + I2C | |
60 | + I2C1 I2C通信(予定) | |
61 | + I2C2 未使用 | |
62 | + | |
63 | + ポート使用 | |
64 | + B0 I/O, AN0 | |
65 | + B1 I/O, AN1 | |
66 | + B2 I/O, AN2 | |
67 | + B3 I/O, AN3 | |
68 | + B4 I/O, AN4 | |
69 | + B5 I/O, AN5 | |
70 | + B6 I/O, AN6 | |
71 | + B7 I/O, AN7 | |
72 | + B8 I/O, AN8 | |
73 | + B9 I/O, AN9 | |
74 | + B10 I/O, AN10 | |
75 | + B11 I/O, AN11 | |
76 | + B12 I/O, AN12 | |
77 | + B13 I/O, AN13 | |
78 | + B14 I/O, AN14 | |
79 | + B15 I/O, AN15 | |
80 | + C12 OSC1 (Crystal) | |
81 | + C13 U1TX (UART) | |
82 | + C14 U1RX (UART) | |
83 | + C15 OSC2 (Crystal) | |
84 | + D0 SW_DOWN | |
85 | + D1 SW_LEFT | |
86 | + D2 SW_UP | |
87 | + D3 SW_RIGHT | |
88 | + D4 SW_START | |
89 | + D5 SW_FIRE | |
90 | + D6 | |
91 | + D7 | |
92 | + D8 | |
93 | + D9 SPI1_CS (SPI) | |
94 | + D10 PWM1 | |
95 | + D11 PWM2 | |
96 | + E0 NTSC | |
97 | + E1 NTSC | |
98 | + E2 NTSC | |
99 | + E3 NTSC | |
100 | + E4 NTSC | |
101 | + E5 I/O, AN22 | |
102 | + E6 I/O, AN23 | |
103 | + E7 I/O, AN27 | |
104 | + F0 PS/2 DAT | |
105 | + F1 PS/2 CLK | |
106 | + F2 SDI1 (SPI) | |
107 | + F3 SPI2_CS (MMC) | |
108 | + F4 AUDIO_R | |
109 | + F5 AUDIO_L | |
110 | + F6 SCK1 (SPI) | |
111 | + G2 SCL1 (I2C) | |
112 | + G3 SDA1 (I2C) | |
113 | + G6 SCK2 (MMC) | |
114 | + G7 SDI2 (MMC) | |
115 | + G8 SDO2 (MMC) | |
116 | + G9 SDO1 (SPI) | |
117 | +*/ | |
118 | + | |
119 | +#include <xc.h> | |
120 | +#include "api.h" | |
121 | +#include "compiler.h" | |
122 | +#include "editor.h" | |
123 | +#include "keyinput.h" | |
124 | +#include "main.h" | |
125 | + | |
126 | +//外付けクリスタル with PLL (20/3倍) | |
127 | +//クリスタルは3.579545×4=14.31818MHz | |
128 | +#pragma config FSRSSEL = PRIORITY_7 | |
129 | +#pragma config PMDL1WAY = OFF | |
130 | +#pragma config IOL1WAY = OFF | |
131 | +//#pragma config FUSBIDIO = OFF | |
132 | +//#pragma config FVBUSONIO = OFF | |
133 | +#pragma config FPLLIDIV = DIV_3 | |
134 | +#pragma config FPLLMUL = MUL_20 | |
135 | +//#pragma config UPLLIDIV = DIV_1 | |
136 | +//#pragma config UPLLEN = OFF | |
137 | +#pragma config FPLLODIV = DIV_1 | |
138 | +#pragma config FNOSC = PRIPLL | |
139 | +#pragma config FSOSCEN = OFF | |
140 | +#pragma config IESO = OFF | |
141 | +#pragma config POSCMOD = XT | |
142 | +#pragma config OSCIOFNC = OFF | |
143 | +#pragma config FPBDIV = DIV_1 | |
144 | +#pragma config FCKSM = CSDCMD | |
145 | +#pragma config FWDTEN = OFF | |
146 | +#pragma config DEBUG = OFF | |
147 | +#pragma config PWP = OFF | |
148 | +#pragma config BWP = OFF | |
149 | +#pragma config CP = OFF | |
150 | + | |
151 | +#define mBMXSetRAMKernProgOffset(offset) (BMXDKPBA = (offset)) | |
152 | +#define mBMXSetRAMUserDataOffset(offset) (BMXDUDBA = (offset)) | |
153 | +#define mBMXSetRAMUserProgOffset(offset) (BMXDUPBA = (offset)) | |
154 | + | |
155 | +// INIファイル指定キーワード(8文字以内) | |
156 | +const char InitKeywords[][9]={ | |
157 | + "106KEY","101KEY","NUMLOCK","CAPSLOCK","SCRLLOCK","WIDTH36","WIDTH48","WIDTH80" | |
158 | +}; | |
159 | +unsigned char initialvmode; | |
160 | + | |
161 | +void freadline(char *s,FSFILE *fp){ | |
162 | +// ファイルから1行読み込み、配列sに返す | |
163 | +// 最大8文字まで。9文字以上の場合無効 | |
164 | +// #または0x20以下のコードを見つけた場合、以降は無視 | |
165 | +// s:9バイト以上の配列 | |
166 | +// fp:ファイルポインタ | |
167 | + int n; | |
168 | + char c,*p; | |
169 | + n=0; | |
170 | + p=s; | |
171 | + *p=0; | |
172 | + while(n<=8){ | |
173 | + if(FSfread(p,1,1,fp)==0 || *p=='\n'){ | |
174 | + *p=0; | |
175 | + return; | |
176 | + } | |
177 | + if(*p=='#'){ | |
178 | + *p=0; | |
179 | + break; | |
180 | + } | |
181 | + if(*p<=' '){ | |
182 | + if(n>0){ | |
183 | + *p=0; | |
184 | + break; | |
185 | + } | |
186 | + continue; | |
187 | + } | |
188 | + p++; | |
189 | + n++; | |
190 | + } | |
191 | + if(n>8) *s=0; //9文字以上の文字列の場合は無効 | |
192 | + //以降の文字は無視 | |
193 | + while(FSfread(&c,1,1,fp) && c!='\n') ; | |
194 | +} | |
195 | +int searchinittext(char *s){ | |
196 | +// InitKeywords配列の中から文字列sを探し、位置した場合何番目かを返す | |
197 | +// 見つからなかった場合-1を返す | |
198 | + int i; | |
199 | + char *p1; | |
200 | + const char *p2; | |
201 | + for(i=0;i<sizeof(InitKeywords)/sizeof(InitKeywords[0]);i++){ | |
202 | + p1=s; | |
203 | + p2=InitKeywords[i]; | |
204 | + while(*p1==*p2){ | |
205 | + if(*p1==0) return i; | |
206 | + p1++; | |
207 | + p2++; | |
208 | + } | |
209 | + } | |
210 | + return -1; | |
211 | +} | |
212 | +void readinifile(void){ | |
213 | + FSFILE *fp; | |
214 | + char inittext[9]; | |
215 | + | |
216 | + fp=FSfopen(INIFILE,"r"); | |
217 | + if(fp==NULL) return; | |
218 | + printstr("Initialization File Found\n"); | |
219 | + lockkey=0; //INIファイルが存在する場合、Lock関連キーはINIファイルに従う | |
220 | + while(1){ | |
221 | + if(FSfeof(fp)) break; | |
222 | + freadline(inittext,fp); | |
223 | + switch(searchinittext(inittext)){ | |
224 | + case 0: | |
225 | + keytype=0;//日本語キーボード | |
226 | + break; | |
227 | + case 1: | |
228 | + keytype=1;//英語キーボード | |
229 | + break; | |
230 | + case 2: | |
231 | + lockkey|=2;//Num Lock | |
232 | + break; | |
233 | + case 3: | |
234 | + lockkey|=4;//CAPS Lock | |
235 | + break; | |
236 | + case 4: | |
237 | + lockkey|=1;//Scroll Lock | |
238 | + break; | |
239 | + case 5: | |
240 | + initialvmode=VMODE_STDTEXT; | |
241 | + break; | |
242 | + case 6: | |
243 | + initialvmode=VMODE_WIDETEXT; | |
244 | + break; | |
245 | + case 7: | |
246 | + initialvmode=VMODE_MONOTEXT; | |
247 | + break; | |
248 | + } | |
249 | + } | |
250 | + FSfclose(fp); | |
251 | +} | |
252 | + | |
253 | +void printhex8(unsigned char d){ | |
254 | + printchar("0123456789ABCDEF"[d>>4]); | |
255 | + printchar("0123456789ABCDEF"[d&0x0f]); | |
256 | +} | |
257 | + | |
258 | +void printhex16(unsigned short d){ | |
259 | + printhex8(d>>8); | |
260 | + printhex8(d&0x00ff); | |
261 | +} | |
262 | + | |
263 | +void printhex32(unsigned int d){ | |
264 | + printhex16(d>>16); | |
265 | + printhex16(d&0x0000ffff); | |
266 | +} | |
267 | + | |
268 | +int main(void){ | |
269 | + char *appname,*s; | |
270 | + | |
271 | + /* ポートの初期設定 */ | |
272 | + CNPUB = 0xFFFF; // PORTB全てプルアップ(I/O) | |
273 | + TRISB = 0xFFFF; // PORTB全て入力 | |
274 | + CNPUC = 0x4000; // PORTC14プルアップ(U1RX) | |
275 | + TRISC = 0x4000; // PORTC14以外は出力 | |
276 | + TRISD = KEYSTART | KEYFIRE | KEYUP | KEYDOWN | KEYLEFT | KEYRIGHT;// ボタン接続ポート入力設定 | |
277 | + CNPUE = 0x00E0; // PORTE5-7プルアップ(I/O) | |
278 | + TRISE = 0x00E0; // PORTE0-4出力5-7入力 | |
279 | + CNPUF = 0x0004; // PORTF2プルアップ(SDI1) | |
280 | + TRISF = 0x0004; // PORTF2以外は出力 | |
281 | + TRISG = 0x0080; // PORTG7以外は出力 | |
282 | + | |
283 | + ANSELB = 0x0000; // 全てデジタル | |
284 | + ANSELD = 0x0000; // 全てデジタル | |
285 | + ANSELE = 0x0000; // 全てデジタル | |
286 | + ANSELG = 0x0000; // 全てデジタル | |
287 | + CNPUDSET=KEYSTART | KEYFIRE | KEYUP | KEYDOWN | KEYLEFT | KEYRIGHT;// プルアップ設定 | |
288 | + ODCF = 0x0003; //RF0,RF1はオープンドレイン | |
289 | + | |
290 | + // 周辺機能ピン割り当て | |
291 | + SDI2R = 1; //RPG7にSDI2を割り当て | |
292 | + RPG8R = 6; //RPG8にSDO2を割り当て | |
293 | + | |
294 | + // Make RAM executable. See also "char RAM[RAMSIZE]" in globalvars.c | |
295 | + mBMXSetRAMKernProgOffset(PIC32MX_RAMSIZE-RAMSIZE); | |
296 | + mBMXSetRAMUserDataOffset(PIC32MX_RAMSIZE); | |
297 | + mBMXSetRAMUserProgOffset(PIC32MX_RAMSIZE); | |
298 | + | |
299 | + init_composite(); // ビデオメモリクリア、割り込み初期化、カラービデオ出力開始 | |
300 | + setcursor(0,0,COLOR_NORMALTEXT); | |
301 | + | |
302 | + // Show blue screen if exception before soft reset. | |
303 | + blue_screen(); | |
304 | + | |
305 | + printstr("MachiKania BASIC System\n"); | |
306 | + printstr(" Ver "SYSVER1" "SYSVER2" by KENKEN\n"); | |
307 | + printstr("BASIC Compiler "BASVER"\n"); | |
308 | + printstr(" by Katsumi\n\n"); | |
309 | + //SDカードファイルシステム初期化 | |
310 | + setcursorcolor(COLOR_NORMALTEXT); | |
311 | + printstr("Init File System..."); | |
312 | + // Initialize the File System | |
313 | + if(FSInit()==FALSE){ //ファイルシステム初期化 | |
314 | + //エラーの場合停止 | |
315 | + setcursorcolor(COLOR_ERRORTEXT); | |
316 | + printstr("\nFile System Error\n"); | |
317 | + printstr("Insert Correct Card\n"); | |
318 | + printstr("And Reset\n"); | |
319 | + while(1) asm("wait"); | |
320 | + } | |
321 | + printstr("OK\n"); | |
322 | + | |
323 | + // 音源初期化 | |
324 | + OC4RS=LATFbits.LATF5 ? 0xff:0x00; | |
325 | + OC3RS=LATFbits.LATF4 ? 0xff:0x00; | |
326 | + init_music(); | |
327 | + | |
328 | + initialvmode=VMODE_STDTEXT; // 標準テキストモード(36文字) | |
329 | + lockkey=2; // NumLockキーオン | |
330 | + keytype=0; // 日本語キーボード | |
331 | + readinifile(); //INIファイル読み込み | |
332 | + printstr("Init PS/2..."); | |
333 | + wait60thsec(30); //0.5秒待ち | |
334 | + if(ps2init()){ //PS/2初期化 | |
335 | + //キーボードが見つからない場合 | |
336 | + printstr("Keyboard Not Found\n"); | |
337 | + } | |
338 | + else printstr("OK\n"); | |
339 | + | |
340 | + wait60thsec(60); //1秒待ち | |
341 | + | |
342 | + set_videomode(initialvmode,0); //ビデオモード切替 | |
343 | + | |
344 | + // 実行中HEXファイル名がHEXFILEと一致した場合はエディタ起動 | |
345 | + appname=(char*)FILENAME_FLASH_ADDRESS; | |
346 | + s=HEXFILE; | |
347 | + while(*s++==*appname++) if(*s==0) texteditor(); //テキストエディター呼び出し | |
348 | + | |
349 | + // 実行中HEXファイル名の「.HEX」を「.BAS」に置き換えてBASファイルを実行 | |
350 | + appname=(char*)FILENAME_FLASH_ADDRESS; | |
351 | + s=tempfile; | |
352 | + while(*appname!='.') *s++=*appname++; | |
353 | + appname=".BAS"; | |
354 | + while(*appname!=0) *s++=*appname++; | |
355 | + *s=0; | |
356 | + // buttonmode(); //ボタン有効化 | |
357 | + g_disable_break=1; // Breakキー無効化 | |
358 | + runbasic(tempfile,0); | |
359 | + while(1) asm(WAIT); | |
360 | +} |
@@ -0,0 +1,651 @@ | ||
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 "compiler.h" | |
10 | + | |
11 | +/* | |
12 | + Library functions follow | |
13 | +*/ | |
14 | +static short* g_serial_buff=0; | |
15 | +static int g_serial_buff_read_pos,g_serial_buff_write_pos; | |
16 | +static int g_serial_buff_size; | |
17 | +void lib_serial(int baud, int parity, int bsize){ | |
18 | + // SERIAL x[,y[,z]] | |
19 | + // where x is baud rate. If zero, stop using it. | |
20 | + // y (0 is default) is parity setting; 0: 8 bit no parity, | |
21 | + // 1: 8 bit even parity, 2: 8 bit odd parity, 3: 9 bit no parity | |
22 | + // z is input buffer size. If z=0 (default), the size will be calculated automatically. | |
23 | + // Calculation is: z=BAUD/10/60/2*3 (z=BAUD/400), which is 1.5 times more size required for 1/60 sec. | |
24 | + /* | |
25 | + RC13 U1TX RC14 U1RX | |
26 | + U1MODE=0x0000 | (parity<<1) | |
27 | + U1MODEbits.ON=0; | |
28 | + U1MODEbits.FRZ=0; Continue operation when CPU is in Debug Exception mode; | |
29 | + U1MODEbits.SIDL=0; Continue operation in Idle mode | |
30 | + U1MODEbits.IREN=0; IrDA is disabled; | |
31 | + U1MODEbits.RTSMD=0; UxRTS pin is in Flow Control mode | |
32 | + U1MODEbits.UEN=0; Only UxTX and UxRX pins are enabled and used; | |
33 | + U1MODEbits.WAKE=0; Wake-up disabled | |
34 | + U1MODEbits.LPBACK=0; Loopback mode is disabled | |
35 | + U1MODEbits.ABAUD=0; Baud rate measurement disabled or completed | |
36 | + U1MODEbits.RXINV=0; UxRX Idle state is ‘1’ | |
37 | + U1MODEbits.BRGH=0; Standard Speed mode ? 16x baud clock enabled | |
38 | + U1MODEbits.PDSEL=0-3; | |
39 | + U1MODEbits.STSEL=0; 1 Stop bit | |
40 | + U1STA=0x00001400; | |
41 | + U1STAbits.ADM_EN=0; Automatic Address Detect mode is disabled | |
42 | + U1STAbits.ADDR=0; Don't care | |
43 | + U1STAbits.UTXISEL=0; Don't care. Don't use TX interrupt | |
44 | + U1STAbits.UTXINV=0; UxTX Idle state is ‘1’ | |
45 | + U1STAbits.URXEN=1; UARTx receiver is enabled. UxRX pin is controlled by UARTx (if ON = 1) | |
46 | + U1STAbits.UTXBRK=0; Break transmission is disabled or completed | |
47 | + U1STAbits.UTXEN=1; UARTx transmitter is enabled. UxTX pin is controlled by UARTx (if ON = 1) | |
48 | + U1STAbits.URXISEL=0; Interrupt flag bit is set when a character is received | |
49 | + U1STAbits.ADDEN=0; Address Detect mode is disabled | |
50 | + U1STAbits.OERR=0; Receive buffer has not overflowed | |
51 | + U1BRG=FPB/16/baud - 1 | |
52 | + */ | |
53 | + if (baud==0) { | |
54 | + // Disable UART | |
55 | + U1MODE=0x0000; | |
56 | + U1STA=0x00000000; | |
57 | + IEC1bits.U1TXIE=0; | |
58 | + IEC1bits.U1RXIE=0; | |
59 | + // Free buffer area | |
60 | + if (g_serial_buff) free_temp_str((char*)g_serial_buff); | |
61 | + g_serial_buff=0; | |
62 | + } else { | |
63 | + // Prepare buffer for SERIALIN | |
64 | + if (bsize==0) bsize=baud/400; // Area corresponds to ~1/40 sec (> 1/60 sec) | |
65 | + g_serial_buff_size=bsize; | |
66 | + if (g_serial_buff) free_temp_str((char*)g_serial_buff); | |
67 | + g_serial_buff=(short*)alloc_memory((bsize+1)/2,get_permanent_var_num()); | |
68 | + g_serial_buff_read_pos=g_serial_buff_write_pos=0; | |
69 | + // Initialize I/O ports | |
70 | + TRISCSET=1<<14; // Input from RC14 | |
71 | + ANSELCCLR=1<<14; // Digital for RC14 | |
72 | + U1RXR=7; // Use RC14 for U1RX | |
73 | + TRISCCLR=1<<13; // Output to RC13 | |
74 | + RPC13R=3; // Use RC13 for U1TX | |
75 | + // Initialize UART | |
76 | + U1MODE=0x0000 | ((parity&3)<<1); | |
77 | + U1STA=0x00001400; | |
78 | + U1BRG=95454533/16/baud -1; | |
79 | + // Interrupt settings. Use only RX interrupt. | |
80 | + IEC1bits.U1TXIE=0; | |
81 | + IFS1bits.U1RXIF=0; | |
82 | + IEC1bits.U1RXIE=1; | |
83 | + IPC7bits.U1IP=3; | |
84 | + IPC7bits.U1IS=0; | |
85 | + // Start UART | |
86 | + U1MODEbits.ON=1; | |
87 | + } | |
88 | +} | |
89 | +#pragma interrupt uartint IPL3SOFT vector 31 | |
90 | +void uartint(){ | |
91 | + int err; | |
92 | + IFS1bits.U1RXIF=0; | |
93 | + while(U1STAbits.URXDA){ | |
94 | + // Fill into the buffer while RX data is available | |
95 | + err=0; | |
96 | + if (U1STAbits.PERR) { | |
97 | + if (U1MODEbits.PDSEL==1 || U1MODEbits.PDSEL==2) { | |
98 | + // Parity error | |
99 | + err=0x100; | |
100 | + } | |
101 | + } | |
102 | + g_serial_buff[g_serial_buff_write_pos]=err|U1RXREG; | |
103 | + g_serial_buff_write_pos++; | |
104 | + if (g_serial_buff_size<=g_serial_buff_write_pos) g_serial_buff_write_pos=0; | |
105 | + } | |
106 | +} | |
107 | + | |
108 | +void lib_serialout(int data){ | |
109 | + // SERIALOUT x | |
110 | + // where x is 8 bit data. If FIFO buffer is full, wait until ready. | |
111 | + if (U1MODEbits.PDSEL==3) { | |
112 | + // 9 bit | |
113 | + data&=0x1ff; | |
114 | + } else { | |
115 | + data&=0xff; | |
116 | + } | |
117 | + // Wait while buffer is full | |
118 | + while(U1STAbits.UTXBF){ | |
119 | + asm("nop"); | |
120 | + } | |
121 | + // Send data. | |
122 | + U1TXREG=data; | |
123 | +} | |
124 | +int lib_serialin(int mode){ | |
125 | + int i; | |
126 | + // SERIALIN([x]) | |
127 | + // x=0 (default): return data. If no data remaining, return -1. | |
128 | + // x=1: If data exist(s) return 1, if not, return 0. | |
129 | + switch(mode){ | |
130 | + case 1: | |
131 | + // Return # of data in buffer | |
132 | + i=g_serial_buff_write_pos-g_serial_buff_read_pos; | |
133 | + if (i<0) i+=g_serial_buff_size; | |
134 | + return i; | |
135 | + case 0: | |
136 | + default: | |
137 | + if (g_serial_buff_write_pos==g_serial_buff_read_pos) return -1; | |
138 | + i=g_serial_buff[g_serial_buff_read_pos]; | |
139 | + g_serial_buff_read_pos++; | |
140 | + if (g_serial_buff_size<=g_serial_buff_read_pos) g_serial_buff_read_pos=0; | |
141 | + return i; | |
142 | + } | |
143 | +} | |
144 | + | |
145 | +void lib_pwm(int duty, int freq, int num){ | |
146 | + /* | |
147 | + OCxCON=0x000D; | |
148 | + OCxCONbits.ON=0; | |
149 | + OCxCONbits.SIDL=0; // Continue operation in Idle mode | |
150 | + OCxCONbits.OC32=0; // OCxR<15:0> and OCxRS<15:0> are used for comparisons to the 16-bit timer source | |
151 | + OCxCONbits.OCFLT; // Not used | |
152 | + OCxCONbits.OCTSEL=1; // Timer3 is the clock source for this Output Compare module | |
153 | + OCxCONbits.OCM=5; // Initialize OCx pin low; generate continuous output pulses on OCx pin | |
154 | + | |
155 | + Signal will be L when TMR3 reaches OCxRS, and H when TMR3 reaches OCxR | |
156 | + | |
157 | + Timer3 prescaler: 1, 2, 4, 8, 16, 32, 64, 256 | |
158 | + For slowest Timer3 (PR3=65535), in Hz: 1456.5, 728.3, 364.1, 182.1, 91.0, 45.5, 22.8, 5.69 | |
159 | + For fastest Timer3 (PR3=1000), in Hz: 95455, 47727, 23864, 11932, 5966, 2983, 1492, 373 | |
160 | + Therefore, for freq value, | |
161 | + 6-22: 1/256 prescaler | |
162 | + 23-45: 1/64 | |
163 | + 46-91: 1/32 | |
164 | + 92-182: 1/16 | |
165 | + 183-364: 1/8 | |
166 | + 365-728: 1/4 | |
167 | + 729-1456: 1/2 | |
168 | + 1457-95455: 1/1 | |
169 | + | |
170 | + */ | |
171 | + static int prevfreq=0, prevPR3=0; | |
172 | + if (num==0) { | |
173 | + // Reset PWM | |
174 | + prevfreq=prevPR3=0; | |
175 | + return; | |
176 | + } | |
177 | + if (duty==0) { | |
178 | + // Continuous output of L signal | |
179 | + switch(num){ | |
180 | + case 1: | |
181 | + // Use RD10 for digital output | |
182 | + LATDCLR=1<<10; | |
183 | + RPD10R=0; | |
184 | + TRISDCLR=1<<10; | |
185 | + return; | |
186 | + case 2: | |
187 | + // Use RD11 for digital output | |
188 | + LATDCLR=1<<11; | |
189 | + RPD11R=0; | |
190 | + TRISDCLR=1<<11; | |
191 | + return; | |
192 | + default: | |
193 | + err_invalid_param(); | |
194 | + } | |
195 | + } else if (duty==1000) { | |
196 | + // Continuous output of H signal | |
197 | + switch(num){ | |
198 | + case 1: | |
199 | + // Use RD10 for digital output | |
200 | + LATDSET=1<<10; | |
201 | + RPD10R=0; | |
202 | + TRISDCLR=1<<10; | |
203 | + return; | |
204 | + case 2: | |
205 | + // Use RD11 for digital output | |
206 | + LATDSET=1<<11; | |
207 | + RPD11R=0; | |
208 | + TRISDCLR=1<<11; | |
209 | + return; | |
210 | + default: | |
211 | + err_invalid_param(); | |
212 | + } | |
213 | + } | |
214 | + // PWM mode | |
215 | + if (freq!=prevfreq || PR3!=prevPR3) { | |
216 | + // Initialize PWM system | |
217 | + OC3CON=0x0000; | |
218 | + OC4CON=0x0000; | |
219 | + IEC0bits.OC3IE=0; | |
220 | + IEC0bits.OC4IE=0; | |
221 | + // Stop music | |
222 | + stop_music(); | |
223 | + // Initialize timer 3 | |
224 | + IEC0bits.T3IE=0; | |
225 | + if (freq<6) { | |
226 | + err_invalid_param(); | |
227 | + } else if (freq<23) { | |
228 | + // 1/256 prescaler | |
229 | + T3CON=0x0070; | |
230 | + prevPR3=(int)((95454533/256)/freq)-1; | |
231 | + } else if (freq<46) { | |
232 | + // 1/64 prescaler | |
233 | + T3CON=0x0060; | |
234 | + prevPR3=(int)((95454533/64)/freq)-1; | |
235 | + } else if (freq<92) { | |
236 | + // 1/32 prescaler | |
237 | + T3CON=0x0050; | |
238 | + prevPR3=(int)((95454533/32)/freq)-1; | |
239 | + } else if (freq<183) { | |
240 | + // 1/16 prescaler | |
241 | + T3CON=0x0040; | |
242 | + prevPR3=(int)((95454533/16)/freq)-1; | |
243 | + } else if (freq<365) { | |
244 | + // 1/8 prescaler | |
245 | + T3CON=0x0030; | |
246 | + prevPR3=(int)((95454533/8)/freq)-1; | |
247 | + } else if (freq<729) { | |
248 | + // 1/4 prescaler | |
249 | + T3CON=0x0020; | |
250 | + prevPR3=(int)((95454533/4)/freq)-1; | |
251 | + } else if (freq<1457) { | |
252 | + // 1/2 prescaler | |
253 | + T3CON=0x0010; | |
254 | + prevPR3=(int)((95454533/2)/freq)-1; | |
255 | + } else if (freq<95455) { | |
256 | + // 1/1 prescaler | |
257 | + T3CON=0x0000; | |
258 | + prevPR3=(int)(95454533/freq)-1; | |
259 | + } else { | |
260 | + err_invalid_param(); | |
261 | + } | |
262 | + TMR3=0; | |
263 | + PR3=prevPR3; | |
264 | + prevfreq=freq; | |
265 | + } | |
266 | + // Wait until Timer3 will reset | |
267 | + if (T3CONbits.ON) { | |
268 | + IFS0bits.T3IF=0; | |
269 | + while (IFS0bits.T3IF==0); | |
270 | + }; | |
271 | + // Stop and reset timer | |
272 | + T3CONCLR=0x8000; | |
273 | + TMR3=PR3; | |
274 | + // New PWM setting follows | |
275 | + switch(num){ | |
276 | + case 1: | |
277 | + // Use OC3/RD10 | |
278 | + RPD10R=11; | |
279 | + TRISDCLR=1<<10; | |
280 | + // Disable OC3 first | |
281 | + OC3CON=0x0000; | |
282 | + // OC3 settings | |
283 | + OC3CON=0x000D; | |
284 | + OC3R=0; | |
285 | + OC3RS=(((int)PR3+1)*duty) / 1000; | |
286 | + // Start OC3 and timer | |
287 | + OC3CONSET=0x8000; | |
288 | + T3CONSET=0x8000; | |
289 | + break; | |
290 | + case 2: | |
291 | + // Use OC4/RD11 | |
292 | + RPD11R=11; | |
293 | + TRISDCLR=1<<11; | |
294 | + // Disable OC4 first | |
295 | + OC4CON=0x0000; | |
296 | + // OC4 settings | |
297 | + OC4CON=0x000D; | |
298 | + OC4R=0; | |
299 | + OC4RS=(((int)PR3+1)*duty) / 1000; | |
300 | + // Wait until Timer3 will reset | |
301 | + if (T3CONbits.ON) { | |
302 | + IFS0bits.T3IF=0; | |
303 | + while (IFS0bits.T3IF==0); | |
304 | + }; | |
305 | + // Start OC4 and timer | |
306 | + OC4CONSET=0x8000; | |
307 | + T3CONSET=0x8000; | |
308 | + break; | |
309 | + default: | |
310 | + err_invalid_param(); | |
311 | + } | |
312 | +} | |
313 | + | |
314 | +void lib_out(int pos, int val){ | |
315 | + // pos must be between 0 and 15 or 16 and 18 | |
316 | + if (0<=pos && pos<=15) { | |
317 | + // PORTB0-15 | |
318 | + // Set output vale | |
319 | + if (val) { | |
320 | + LATBSET=1<<pos; | |
321 | + } else { | |
322 | + LATBCLR=1<<pos; | |
323 | + } | |
324 | + // Enable output | |
325 | + TRISBCLR=1<<pos; | |
326 | + // Disable pulldown | |
327 | + CNPUBCLR=1<<pos; | |
328 | + } else if (16<=pos && pos<=18) { | |
329 | + // PORTE5-7, open drain | |
330 | + pos=pos-16+5; | |
331 | + // Set output vale (L) | |
332 | + LATECLR=1<<pos; | |
333 | + // Output for L and input for H | |
334 | + if (val) { | |
335 | + // Disable output | |
336 | + TRISESET=1<<pos; | |
337 | + } else { | |
338 | + // Enable output | |
339 | + TRISECLR=1<<pos; | |
340 | + } | |
341 | + } else { | |
342 | + return; | |
343 | + } | |
344 | +} | |
345 | + | |
346 | +void lib_out8h(int val){ | |
347 | + // Set output vale | |
348 | + LATB=(LATB&0x00FF)|((val&0xff)<<8); | |
349 | + // Enable output | |
350 | + TRISBCLR=0xFF00; | |
351 | + // Disable pulldown | |
352 | + CNPUBCLR=0xFF00; | |
353 | +} | |
354 | + | |
355 | +void lib_out8l(int val){ | |
356 | + // Set output vale | |
357 | + LATB=(LATB&0xFF00)|(val&0xff); | |
358 | + // Enable output | |
359 | + TRISBCLR=0x00FF; | |
360 | + // Disable pulldown | |
361 | + CNPUBCLR=0x00FF; | |
362 | +} | |
363 | + | |
364 | +int lib_out16(int val){ | |
365 | + // Set output vale | |
366 | + LATB=(val&0xFFFF); | |
367 | + // Enable output | |
368 | + TRISBCLR=0xFFFF; | |
369 | + // Disable pulldown | |
370 | + CNPUBCLR=0xFFFF; | |
371 | +} | |
372 | + | |
373 | +int lib_in(int pos){ | |
374 | + // pos must be between 0 and 15 or 16 and 18 | |
375 | + if (0<=pos && pos<=15) { | |
376 | + // PORTB0-15 | |
377 | + // Enable pulldown | |
378 | + CNPUBSET=1<<pos; | |
379 | + // Enable input | |
380 | + TRISBSET=1<<pos; | |
381 | + ANSELBCLR=1<<pos; | |
382 | + // Read value and return | |
383 | + return (PORTB&(1<<pos)) ? 1:0; | |
384 | + } else if (16<=pos && pos<=18) { | |
385 | + // PORTE5-7 | |
386 | + pos=pos-16+5; | |
387 | + // Enable pulldown | |
388 | + CNPUESET=1<<pos; | |
389 | + // Enable input | |
390 | + TRISESET=1<<pos; | |
391 | + ANSELECLR=1<<pos; | |
392 | + // Read value and return | |
393 | + return (PORTE&(1<<pos)) ? 1:0; | |
394 | + } else { | |
395 | + return 0; | |
396 | + } | |
397 | +} | |
398 | + | |
399 | +int lib_in8h(){ | |
400 | + // Enable pulldown | |
401 | + CNPUBSET=0xFF00; | |
402 | + // Enable input | |
403 | + TRISBSET=0xFF00; | |
404 | + ANSELBCLR=0xFF00; | |
405 | + // Read value and return | |
406 | + return (PORTB&0xFF00)>>8; | |
407 | +} | |
408 | + | |
409 | +int lib_in8l(){ | |
410 | + // Enable pulldown | |
411 | + CNPUBSET=0x00FF; | |
412 | + // Enable input | |
413 | + TRISBSET=0x00FF; | |
414 | + ANSELBCLR=0x00FF; | |
415 | + // Read value and return | |
416 | + return PORTB&0x00FF; | |
417 | +} | |
418 | + | |
419 | +int lib_in16(){ | |
420 | + // Enable pulldown | |
421 | + CNPUBSET=0xFFFF; | |
422 | + // Enable input | |
423 | + TRISBSET=0xFFFF; | |
424 | + ANSELBCLR=0xFFFF; | |
425 | + // Read value and return | |
426 | + return PORTB&0xFFFF; | |
427 | +} | |
428 | + | |
429 | +int lib_analog(int pos){ | |
430 | + /* | |
431 | + Analog to 12 bit digital converter function. | |
432 | + AD1CON1=0x00E0; | |
433 | + AD1CON1bits.ON=0; | |
434 | + AD1CON1bits.SIDL=0; // Continue module operation in Idle mode | |
435 | + AD1CON1bits.FORM=0; // Integer 16-bit | |
436 | + AD1CON1bits.SSRC=8; // Internal counter ends sampling and starts conversion (auto convert) | |
437 | + AD1CON1bits.CLRASAM=0; // Normal operation, buffer contents will be overwritten by the next conversion sequence | |
438 | + AD1CON1bits.ASAM=0; // Sampling begins when SAMP bit is set. | |
439 | + AD1CON1bits.SAMP=0; // The ADC sample/hold amplifier is holding | |
440 | + AD1CON1bits.DONE=0; // Analog-to-digital conversion is not done or has not started | |
441 | + AD1CON2=0; | |
442 | + AD1CON2bits.VCFG=0; // Voltage reference:AVdd-AVss | |
443 | + AD1CON2bits.OFFCAL=0; // Disable Offset Calibration mode | |
444 | + AD1CON2bits.CSCNA=0; // Do not scan inputs | |
445 | + AD1CON2bits.BUFS=0; // Do not care, only valid when BUFM=1 | |
446 | + AD1CON2bits.SMPI=0; // Do not care. Do not use interrupt. | |
447 | + AD1CON2bits.BUFM=0; // Buffer configured as one 16-word buffer ADC1BUFF-ADC1BUF0 | |
448 | + AD1CON2bits.ALTS=0; // Always use Sample A input multiplexer settings | |
449 | + AD1CON3=0x0607; | |
450 | + AD1CON3bits.ADRC=0; // Clock derived from Peripheral Bus Clock (PBCLK) | |
451 | + AD1CON3bits.SAMC=6; // Auto-Sample Time: 6 TAD = 1005.72 ns (> 1000 ns) | |
452 | + AD1CON3bits.ADCS=7; // TAD=TPB*2*8=167.62 ns (> 154 ns) | |
453 | + AD1CHS=(0-27)<<16; | |
454 | + AD1CHSbits.CN0NB=0; // Do not care, only valid when using channel B | |
455 | + AD1CHSbits.CH0SB=0; // Do not care, only valid when using channel B | |
456 | + AD1CHSbits.CH0NA=0; // Channel 0 negative input is VREFL | |
457 | + AD1CHSbits.CH0SA=0-27; // Set input channel here | |
458 | + AD1CSSL; // Do not care, only valid when CSCNA=1; | |
459 | + */ | |
460 | + AD1CON1=0x00E0; | |
461 | + AD1CON2=0x0000; | |
462 | + AD1CON3=0x0607; | |
463 | + // pos must be between 0 and 15 or 16 and 18 | |
464 | + if (0<=pos && pos<=15) { | |
465 | + // RB0-RB15: AN0-AN15 | |
466 | + // Disable pulldown | |
467 | + CNPUBCLR=1<<pos; | |
468 | + // Enable input | |
469 | + TRISBSET=1<<pos; | |
470 | + // Enable analog | |
471 | + ANSELBSET=1<<pos; | |
472 | + // Select input pin | |
473 | + AD1CHS=pos<<16; | |
474 | + } else if (16<=pos && pos<=18) { | |
475 | + // RE5,6,7:AN22,23,27 | |
476 | + pos=pos-16+5; | |
477 | + // Disable pulldown | |
478 | + CNPUECLR=1<<pos; | |
479 | + // Enable input | |
480 | + TRISESET=1<<pos; | |
481 | + // Enable analog | |
482 | + ANSELESET=1<<pos; | |
483 | + // Select input pin | |
484 | + if (pos<=6) { | |
485 | + pos=pos-5+22; | |
486 | + } else { | |
487 | + pos=pos-7+27; | |
488 | + } | |
489 | + AD1CHS=pos<<16; | |
490 | + } else { | |
491 | + err_invalid_param(); | |
492 | + } | |
493 | + // Enable ADC | |
494 | + AD1CON1bits.ON=1; | |
495 | + // Start | |
496 | + AD1CON1bits.SAMP=1; | |
497 | + // Wait until done | |
498 | + while(!AD1CON1bits.DONE){ | |
499 | + asm("nop"); | |
500 | + } | |
501 | + // Disable ADC | |
502 | + AD1CON1bits.ON=0; | |
503 | + // Return value | |
504 | + return ADC1BUF0; | |
505 | +} | |
506 | + | |
507 | +/* | |
508 | + Statements and functions implementations follow | |
509 | +*/ | |
510 | + | |
511 | +// Local prototyping | |
512 | +char* param2_statement(enum libs lib); | |
513 | + | |
514 | +char* out_statement(){ | |
515 | + return param2_statement(LIB_SYSTEM | EXTRA_OUT); | |
516 | +} | |
517 | +char* out8h_statement(){ | |
518 | + char* err; | |
519 | + err=get_value(); | |
520 | + if (err) return err; | |
521 | + call_lib_code(LIB_SYSTEM | EXTRA_OUT8H); | |
522 | + return 0; | |
523 | +} | |
524 | +char* out8l_statement(){ | |
525 | + char* err; | |
526 | + err=get_value(); | |
527 | + if (err) return err; | |
528 | + call_lib_code(LIB_SYSTEM | EXTRA_OUT8L); | |
529 | + return 0; | |
530 | +} | |
531 | +char* out16_statement(){ | |
532 | + char* err; | |
533 | + err=get_value(); | |
534 | + if (err) return err; | |
535 | + call_lib_code(LIB_SYSTEM | EXTRA_OUT16); | |
536 | + return 0; | |
537 | +} | |
538 | +char* pwm_statement(){ | |
539 | + char* err; | |
540 | + // Get 1st parameter | |
541 | + err=get_value(); | |
542 | + if (err) return err; | |
543 | + check_obj_space(2); | |
544 | + g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
545 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
546 | + // Get 2nd parameter | |
547 | + if (g_source[g_srcpos]==',') { | |
548 | + g_srcpos++; | |
549 | + err=get_value(); | |
550 | + if (err) return err; | |
551 | + } else { | |
552 | + check_obj_space(1); | |
553 | + g_object[g_objpos++]=0x340203E8; //ori v0,zero,1000 | |
554 | + } | |
555 | + check_obj_space(1); | |
556 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
557 | + // Get 3rd parameter | |
558 | + if (g_source[g_srcpos]==',') { | |
559 | + g_srcpos++; | |
560 | + err=get_value(); | |
561 | + if (err) return err; | |
562 | + } else { | |
563 | + check_obj_space(1); | |
564 | + g_object[g_objpos++]=0x34020001; //ori v0,zero,1 | |
565 | + } | |
566 | + // Insert calling system code | |
567 | + call_lib_code(LIB_SYSTEM | EXTRA_PWM); | |
568 | + check_obj_space(1); | |
569 | + g_object[g_objpos++]=0x27BD0008; // addiu sp,sp,8 | |
570 | + return 0; | |
571 | +} | |
572 | +char* in_function(){ | |
573 | + char* err; | |
574 | + err=get_value(); | |
575 | + if (err) return err; | |
576 | + call_lib_code(LIB_SYSTEM | EXTRA_IN); | |
577 | + return 0; | |
578 | +} | |
579 | +char* in8h_function(){ | |
580 | + call_lib_code(LIB_SYSTEM | EXTRA_IN8H); | |
581 | + return 0; | |
582 | +} | |
583 | +char* in8l_function(){ | |
584 | + call_lib_code(LIB_SYSTEM | EXTRA_IN8L); | |
585 | + return 0; | |
586 | +} | |
587 | +char* in16_function(){ | |
588 | + call_lib_code(LIB_SYSTEM | EXTRA_IN16); | |
589 | + return 0; | |
590 | +} | |
591 | +char* analog_function(){ | |
592 | + char* err; | |
593 | + err=get_value(); | |
594 | + if (err) return err; | |
595 | + call_lib_code(LIB_SYSTEM | EXTRA_ANALOG); | |
596 | + return 0; | |
597 | +} | |
598 | +char* serial_statement(){ | |
599 | + char* err; | |
600 | + // Get 1st parameter | |
601 | + err=get_value(); | |
602 | + if (err) return err; | |
603 | + check_obj_space(2); | |
604 | + g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
605 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
606 | + // Get 2nd parameter | |
607 | + if (g_source[g_srcpos]==',') { | |
608 | + g_srcpos++; | |
609 | + err=get_value(); | |
610 | + if (err) return err; | |
611 | + } else { | |
612 | + check_obj_space(1); | |
613 | + g_object[g_objpos++]=0x34020000; //ori v0,zero,0000 | |
614 | + } | |
615 | + check_obj_space(1); | |
616 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
617 | + // Get 3rd parameter | |
618 | + if (g_source[g_srcpos]==',') { | |
619 | + g_srcpos++; | |
620 | + err=get_value(); | |
621 | + if (err) return err; | |
622 | + } else { | |
623 | + check_obj_space(1); | |
624 | + g_object[g_objpos++]=0x34020000; //ori v0,zero,0 | |
625 | + } | |
626 | + // Insert calling system code | |
627 | + call_lib_code(LIB_SYSTEM | EXTRA_SERIAL); | |
628 | + check_obj_space(1); | |
629 | + g_object[g_objpos++]=0x27BD0008; // addiu sp,sp,8 | |
630 | + return 0; | |
631 | +} | |
632 | +char* serialout_statement(){ | |
633 | + char* err; | |
634 | + err=get_value(); | |
635 | + if (err) return err; | |
636 | + call_lib_code(LIB_SYSTEM | EXTRA_SERIALOUT); | |
637 | + return 0; | |
638 | +} | |
639 | +char* serialin_function(){ | |
640 | + char* err; | |
641 | + next_position(); | |
642 | + if (g_source[g_srcpos]==')') { | |
643 | + check_obj_space(1); | |
644 | + g_object[g_objpos++]=0x34020000; //ori v0,zero,0000 | |
645 | + } else { | |
646 | + err=get_value(); | |
647 | + if (err) return err; | |
648 | + } | |
649 | + call_lib_code(LIB_SYSTEM | EXTRA_SERIALIN); | |
650 | + return 0; | |
651 | +} |
@@ -0,0 +1,22 @@ | ||
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 MEGALOPA | |
9 | +#define SYSVER1 "Megalopa" | |
10 | +#define SYSVER2 "1.0" | |
11 | +#define BASVER "KM-1300" | |
12 | + | |
13 | +#define INIFILE "MACHIKAM.INI" // 初期設定ファイル | |
14 | +#define HEXFILE "MACHIKAM.HEX" // 実行中HEXファイル名がこれと一致した場合はエディタ起動 | |
15 | + | |
16 | +#define FILENAME_FLASH_ADDRESS 0x9D07EFF0 | |
17 | +#define PIC32MX_RAMSIZE 0x20000 | |
18 | +#define PIC32MX_FLASHSIZE 0x80000 | |
19 | + | |
20 | +void printhex8(unsigned char d); | |
21 | +void printhex16(unsigned short d); | |
22 | +void printhex32(unsigned int d); |
@@ -0,0 +1,902 @@ | ||
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 | + Tone data for 15700 Hz sampling frequency, | |
14 | + supporting 3.4 Hz - 440 Hz - 31400 Hz, | |
15 | + are 2147483647 - 16777216 (2^24) - 235095, respectively. | |
16 | + The counter for DMA is working 470189 times more than the actual clock. | |
17 | + Therefore, 440 Hz correspond to 16777216 (= 470189 * 15700/440) counts of this timer. | |
18 | + | |
19 | + Example: | |
20 | + When producing 440 Hz signal, the timer (initially set to 16777216) will be decreased | |
21 | + by 470189 at 15700 Hz frequency. When the timer will be equal to or less than half of | |
22 | + 16777216 (8388608), toggle output. When the timer will be zero or negative, toggle | |
23 | + output and add 16777216 to timer. | |
24 | +*/ | |
25 | + | |
26 | +/* | |
27 | + c 14107904 | |
28 | + B 14946809 | |
29 | + A# 15835575 | |
30 | + A 16777216 | |
31 | + G# 17774828 | |
32 | + G 18831809 | |
33 | + F# 19951607 | |
34 | + F 21137982 | |
35 | + E 22394866 | |
36 | + D# 23726565 | |
37 | + D 25137402 | |
38 | + C# 26632135 | |
39 | + C 28215755 | |
40 | + Cb 29893558 | |
41 | +*/ | |
42 | + | |
43 | +const static int g_keys[]={ | |
44 | + 15835575,14107904,26632135,23726565,21137982,19951607,17774828,// 0 7# C# A#m | |
45 | + 15835575,14946809,26632135,23726565,21137982,19951607,17774828,// 7 6# F# D#m | |
46 | + 15835575,14946809,26632135,23726565,22394866,19951607,17774828,// 14 5# B G#m | |
47 | + 16777216,14946809,26632135,23726565,22394866,19951607,17774828,// 21 4# E C#m | |
48 | + 16777216,14946809,26632135,25137402,22394866,19951607,17774828,// 28 3# A F#m | |
49 | + 16777216,14946809,26632135,25137402,22394866,19951607,18831809,// 35 2# D Bm | |
50 | + 16777216,14946809,28215755,25137402,22394866,19951607,18831809,// 42 1# G Em | |
51 | + 16777216,14946809,28215755,25137402,22394866,21137982,18831809,// 49 0 C Am | |
52 | + 16777216,15835575,28215755,25137402,22394866,21137982,18831809,// 56 1b F Dm | |
53 | + 16777216,15835575,28215755,25137402,23726565,21137982,18831809,// 63 2b Bb Gm | |
54 | + 17774828,15835575,28215755,25137402,23726565,21137982,18831809,// 70 3b Eb Cm | |
55 | + 17774828,15835575,28215755,26632135,23726565,21137982,18831809,// 77 4b Ab Fm | |
56 | + 17774828,15835575,28215755,26632135,23726565,21137982,19951607,// 84 5b Db Bbm | |
57 | + 17774828,15835575,29893558,26632135,23726565,21137982,19951607,// 91 6b Gb Ebm | |
58 | + 17774828,15835575,29893558,26632135,23726565,22394866,19951607,// 98 7b Cb Abm | |
59 | +}; | |
60 | + | |
61 | +/* | |
62 | + 2^(1/12) ~= 1+1/16-1/256 | |
63 | + 1/(2^(1/12)) ~= 1-1/16+1/128-1/512 | |
64 | +*/ | |
65 | + | |
66 | +#define toneFlat(x) ((x)+((x)>>4)-((x)>>8)) | |
67 | +#define toneSharp(x) ((x)-((x)>>4)+((x)>>7)-((x)>>9)) | |
68 | + | |
69 | +/* local global vars */ | |
70 | +static int* g_tones; | |
71 | +static int g_qvalue; | |
72 | +static int g_lvalue; | |
73 | +static int g_mpoint; | |
74 | +static char* g_mstr; | |
75 | +static int g_mspos; | |
76 | +static int g_musicL[32]; | |
77 | +static int g_soundL[32]; | |
78 | +static unsigned short g_musiclenL[32]; | |
79 | +static unsigned char g_soundlenL[32]; | |
80 | +static int g_musicstartL; | |
81 | +static int g_musicendL; | |
82 | +static int g_musicwaitL; | |
83 | +static int g_soundstartL; | |
84 | +static int g_soundendL; | |
85 | +static int g_soundwaitL; | |
86 | +static int g_soundrepeatL; | |
87 | +static int g_musicR[32]; | |
88 | +static int g_soundR[32]; | |
89 | +static unsigned short g_musiclenR[32]; | |
90 | +static unsigned char g_soundlenR[32]; | |
91 | +static int g_musicstartR; | |
92 | +static int g_musicendR; | |
93 | +static int g_musicwaitR; | |
94 | +static int g_soundstartR; | |
95 | +static int g_soundendR; | |
96 | +static int g_soundwaitR; | |
97 | +static int g_soundrepeatR; | |
98 | + | |
99 | +#define MFLAG_L 2 | |
100 | +#define MFLAG_R 1 | |
101 | + | |
102 | +static char g_sound_mode=0; | |
103 | +static FSFILE* g_fhandle=0; | |
104 | +static unsigned char* wavtable=0; | |
105 | +static int wave_stereo; | |
106 | +#define wave_sector_size (wave_stereo ? 524 : 262) | |
107 | + | |
108 | +#define SOUND_MODE_NONE 0 | |
109 | +#define SOUND_MODE_MUSIC 1 | |
110 | +#define SOUND_MODE_WAVE 2 | |
111 | + | |
112 | +#define start_wavedma() T4CONSET=0x8000; DCH1CONSET=DCH2CONSET=0x00000080 | |
113 | +#define stop_wavedma() T4CONCLR=0x8000; DCH1CONCLR=DCH2CONCLR=0x00000080; g_sound_mode=SOUND_MODE_NONE | |
114 | + | |
115 | +void init_wave_dma(); | |
116 | + | |
117 | +int musicRemaining(int flagsLR){ | |
118 | + int l, r; | |
119 | + l=(g_musicendL-g_musicstartL)&31; | |
120 | + r=(g_musicendL-g_musicstartL)&31; | |
121 | + if (flagsLR & MFLAG_L) return l; | |
122 | + if (flagsLR & MFLAG_R) return r; | |
123 | + return (l>r) ? l:r; | |
124 | +} | |
125 | + | |
126 | +int waveRemaining(int mode){ | |
127 | + int ret; | |
128 | + if (!g_fhandle) return 0; | |
129 | + switch(mode){ | |
130 | + case 1: // current position (header excluded) | |
131 | + ret=g_fhandle->seek-0x2c; | |
132 | + break; | |
133 | + case 2: // file size (header excluded) | |
134 | + ret=g_fhandle->size-0x2c; | |
135 | + break; | |
136 | + case 0: // remaining | |
137 | + default: | |
138 | + ret=g_fhandle->size-g_fhandle->seek; | |
139 | + break; | |
140 | + } | |
141 | + if (wave_stereo) ret=ret>>1; | |
142 | + return ret; | |
143 | +} | |
144 | + | |
145 | +#pragma interrupt musicint IPL2SOFT vector 1 | |
146 | +void musicint(){ | |
147 | + static unsigned short wavtable_pos; | |
148 | + static int music_freq_L=0; | |
149 | + static int music_timer_L=0; | |
150 | + static int music_freq_R=0; | |
151 | + static int music_timer_R=0; | |
152 | + unsigned int i,j; | |
153 | + // This function is called every 1/60 sec. | |
154 | + IFS0bits.CS0IF=0; | |
155 | + switch(g_sound_mode){ | |
156 | + case SOUND_MODE_WAVE: | |
157 | + // Initialize parameters | |
158 | + if (!T4CONbits.ON){ | |
159 | + wavtable_pos=0; | |
160 | + music_timer_L=music_timer_R=0; | |
161 | + start_wavedma(); | |
162 | + } | |
163 | + wavtable_pos=wave_sector_size-wavtable_pos; | |
164 | + // Read from file | |
165 | + if (0 == FSfread((void*)&wavtable[wavtable_pos],1,wave_sector_size,g_fhandle)) { | |
166 | + // End of file. | |
167 | + stop_wavedma(); | |
168 | + FSfclose(g_fhandle); | |
169 | + g_fhandle=0; | |
170 | + g_sound_mode=SOUND_MODE_NONE; | |
171 | + stop_music(); | |
172 | + break; | |
173 | + } | |
174 | + // Continue to MUSIC sound mode | |
175 | + case SOUND_MODE_MUSIC: | |
176 | + // Left sound/music | |
177 | + if (g_soundstartL!=g_soundendL){ | |
178 | + // Start timer | |
179 | + music_freq_L=g_soundL[g_soundstartL]; | |
180 | + if ((--g_soundwaitL)<=0) { | |
181 | + g_soundstartL++; | |
182 | + if (g_soundstartL==g_soundendL || 31<g_soundstartL) { | |
183 | + g_soundstartL=0; | |
184 | + g_soundrepeatL--; | |
185 | + if (0<g_soundrepeatL) { | |
186 | + g_soundwaitL=g_soundlenL[g_soundstartL]; | |
187 | + } else { | |
188 | + g_soundendL=g_soundrepeatL=g_soundwaitL=0; | |
189 | + } | |
190 | + } else { | |
191 | + g_soundwaitL=g_soundlenL[g_soundstartL]; | |
192 | + } | |
193 | + } | |
194 | + // Shift music data even though without output. | |
195 | + if (g_musicstartL!=g_musicendL) { | |
196 | + if ((--g_musicwaitL)<=0) { | |
197 | + g_musicstartL++; | |
198 | + g_musicstartL&=31; | |
199 | + g_musicwaitL=g_musiclenL[g_musicstartL]; | |
200 | + } | |
201 | + } | |
202 | + } else if (g_musicstartL!=g_musicendL) { | |
203 | + // Start timer | |
204 | + music_freq_L=g_musicL[g_musicstartL]; | |
205 | + if ((--g_musicwaitL)<=0) { | |
206 | + g_musicstartL++; | |
207 | + g_musicstartL&=31; | |
208 | + g_musicwaitL=g_musiclenL[g_musicstartL]; | |
209 | + } | |
210 | + } else { | |
211 | + music_freq_L=0; | |
212 | + } | |
213 | + // Right sound/music | |
214 | + if (g_soundstartR!=g_soundendR){ | |
215 | + // Start timer | |
216 | + music_freq_R=g_soundR[g_soundstartR]; | |
217 | + if ((--g_soundwaitR)<=0) { | |
218 | + g_soundstartR++; | |
219 | + if (g_soundstartR==g_soundendR || 31<g_soundstartR) { | |
220 | + g_soundstartR=0; | |
221 | + g_soundrepeatR--; | |
222 | + if (0<g_soundrepeatR) { | |
223 | + g_soundwaitR=g_soundlenR[g_soundstartR]; | |
224 | + } else { | |
225 | + g_soundendR=g_soundrepeatR=g_soundwaitR=0; | |
226 | + } | |
227 | + } else { | |
228 | + g_soundwaitR=g_soundlenR[g_soundstartR]; | |
229 | + } | |
230 | + } | |
231 | + // Shift music data even though without output. | |
232 | + if (g_musicstartR!=g_musicendR) { | |
233 | + if ((--g_musicwaitR)<=0) { | |
234 | + g_musicstartR++; | |
235 | + g_musicstartR&=31; | |
236 | + g_musicwaitR=g_musiclenR[g_musicstartR]; | |
237 | + } | |
238 | + } | |
239 | + } else if (g_musicstartR!=g_musicendR) { | |
240 | + // Start timer | |
241 | + music_freq_R=g_musicR[g_musicstartR]; | |
242 | + if ((--g_musicwaitR)<=0) { | |
243 | + g_musicstartR++; | |
244 | + g_musicstartR&=31; | |
245 | + g_musicwaitR=g_musiclenR[g_musicstartR]; | |
246 | + } | |
247 | + } else { | |
248 | + music_freq_R=0; | |
249 | + } | |
250 | + // music_freq_L/R is controlling music/sound. | |
251 | + // If this value is valid, make sound with this frequency | |
252 | + if (g_sound_mode!=SOUND_MODE_WAVE) { | |
253 | + if (!T4CONbits.ON){ | |
254 | + // Initialize parameters | |
255 | + wavtable_pos=0; | |
256 | + music_timer_L=music_timer_R=0; | |
257 | + start_wavedma(); | |
258 | + // Silent in the first sector | |
259 | + for(i=0;i<wave_sector_size;i++) wavtable[i]=0x80; | |
260 | + } | |
261 | + wavtable_pos=wave_sector_size-wavtable_pos; | |
262 | + } | |
263 | + // Modify WAVE table (SOUND_MODE_WAVE) or construct WAVE table (SOUND_MODE_MUSIC) | |
264 | + if (g_sound_mode==SOUND_MODE_WAVE && music_freq_L==0 && music_freq_R==0) { | |
265 | + // Modification is not needed | |
266 | + break; | |
267 | + } | |
268 | + for(i=0;i<wave_sector_size;i++){ | |
269 | + if (music_freq_L) { | |
270 | + music_timer_L-=470189; | |
271 | + if (music_timer_L<=0) { | |
272 | + music_timer_L+=music_freq_L; | |
273 | + j=0xc0; | |
274 | + } else if (music_timer_L<=(music_freq_L>>1)) { | |
275 | + j=0x40; | |
276 | + } else { | |
277 | + j=0xc0; | |
278 | + } | |
279 | + } else { | |
280 | + j=0x80; | |
281 | + } | |
282 | + if (g_sound_mode==SOUND_MODE_WAVE) { | |
283 | + // In WAVE mode, MUSIC/SOUND data is added to WAVE data | |
284 | + j-=0x80; | |
285 | + j+=wavtable[wavtable_pos+i]; | |
286 | + if (j<0x00) j=0; | |
287 | + else if (0xff<j) j=0xff; | |
288 | + wavtable[wavtable_pos+i]=j; | |
289 | + } else { | |
290 | + // In MUSIC mode, MUSIC/SOUND data is newly created | |
291 | + wavtable[wavtable_pos+i]=j; | |
292 | + } | |
293 | + if (music_freq_R) { | |
294 | + music_timer_R-=470189; | |
295 | + if (music_timer_R<=0) { | |
296 | + music_timer_R+=music_freq_R; | |
297 | + j=0xc0; | |
298 | + } else if (music_timer_R<=(music_freq_R>>1)) { | |
299 | + j=0x40; | |
300 | + } else { | |
301 | + j=0xc0; | |
302 | + } | |
303 | + } else { | |
304 | + j=0x80; | |
305 | + } | |
306 | + if (wave_stereo) { | |
307 | + if (g_sound_mode==SOUND_MODE_WAVE) { | |
308 | + // In WAVE mode, MUSIC/SOUND data is added to WAVE data | |
309 | + j-=0x80; | |
310 | + j+=wavtable[wavtable_pos+i+1]; | |
311 | + if (j<0x00) j=0; | |
312 | + else if (0xff<j) j=0xff; | |
313 | + wavtable[wavtable_pos+i+1]=j; | |
314 | + } else { | |
315 | + wavtable[wavtable_pos+i+1]=j; | |
316 | + // In MUSIC mode, MUSIC/SOUND data is newly created | |
317 | + } | |
318 | + // Increment i here and in if statement (total addition 2 for stereo mode) | |
319 | + i++; | |
320 | + } | |
321 | + } | |
322 | + break; | |
323 | + case SOUND_MODE_NONE: | |
324 | + music_freq_L=0; | |
325 | + music_timer_L=0; | |
326 | + music_freq_R=0; | |
327 | + music_timer_R=0; | |
328 | + // Move OC3RS and OC4RS to 0x80 if less or more. | |
329 | + if (OC3RS<0x80) { | |
330 | + OC3RS++; | |
331 | + } else if (0x80<OC3RS) { | |
332 | + OC3RS--; | |
333 | + } | |
334 | + if (OC4RS<0x80) { | |
335 | + OC4RS++; | |
336 | + } else if (0x80<OC4RS) { | |
337 | + OC4RS--; | |
338 | + } | |
339 | + if (OC3RS==0x80 && OC4RS==0x80) { | |
340 | + // Stop interrupt | |
341 | + IEC0bits.CS0IE=0; | |
342 | + } | |
343 | + break; | |
344 | + default: | |
345 | + break; | |
346 | + } | |
347 | +} | |
348 | + | |
349 | +int musicGetNum(){ | |
350 | + int i, ret; | |
351 | + char b; | |
352 | + // Skip non number character | |
353 | + for(i=0;(b=g_mstr[g_mspos+i])<'0' && '9'<g_mstr[g_mspos+i];i++); | |
354 | + // Determine the number | |
355 | + ret=0; | |
356 | + while('0'<=b && b<='9'){ | |
357 | + ret*=10; | |
358 | + ret+=b-'0'; | |
359 | + i++; | |
360 | + b=g_mstr[g_mspos+i]; | |
361 | + } | |
362 | + g_mspos+=i; | |
363 | + return ret; | |
364 | +} | |
365 | + | |
366 | +static const unsigned int inv_rf4[1]={0x00000010}; | |
367 | +static const unsigned int inv_rf5[1]={0x00000020}; | |
368 | + | |
369 | +void init_normal_music(){ | |
370 | + // Use Timer3 and DMA2 for left (RF5) | |
371 | + // Use Timer4 and DMA1 for right (RF4) | |
372 | + stop_music(); | |
373 | + | |
374 | + // Alocate 524*2 byte buffer if not assigned | |
375 | + if (g_var_size[ALLOC_WAVE_BLOCK]==0) { | |
376 | + wavtable=(char*)alloc_memory(524*2/4,ALLOC_WAVE_BLOCK); | |
377 | + } | |
378 | + | |
379 | + // Set music mode | |
380 | + g_sound_mode=SOUND_MODE_MUSIC; | |
381 | + wave_stereo=1; | |
382 | + | |
383 | + // DMA setting | |
384 | + init_wave_dma(); | |
385 | + | |
386 | + // Software interrupt every 1/60 sec (triggered by Timer2) | |
387 | + IFS0bits.CS0IF=0; | |
388 | + IEC0bits.CS0IE=1; | |
389 | +} | |
390 | + | |
391 | +void init_music(){ | |
392 | + // Currently this function is called in main.c and run.c | |
393 | + stop_music(); | |
394 | + | |
395 | + // Initializations for music/sound. | |
396 | + g_qvalue=160; // Q: 1/4=90 | |
397 | + g_lvalue=20; // L: 1/8 | |
398 | + g_tones=(int*)&(g_keys[49]); // C major | |
399 | + g_musicstartL=g_musicendL=g_musicwaitL=g_soundstartL=g_soundendL=g_soundwaitL=g_soundrepeatL=0; | |
400 | + g_musicstartR=g_musicendR=g_musicwaitR=g_soundstartR=g_soundendR=g_soundwaitR=g_soundrepeatR=0; | |
401 | + | |
402 | + // Timer3 for PWM | |
403 | + T3CON=0x0000; | |
404 | + PR3=0x100; | |
405 | + TMR3=0; | |
406 | + | |
407 | + // OC4 setting | |
408 | + RPF5R = 0x0b; //Use RPF5 for OC4 | |
409 | + if (OC4RS&0xff00) OC4RS=0x00; | |
410 | + OC4CON=0x000e; | |
411 | + OC4CONSET=0x8000; | |
412 | + // OC3 setting | |
413 | + RPF4R = 0x0b; //Use RPF4 for OC3 | |
414 | + if (OC3RS&0xff00) OC3RS=0x00; | |
415 | + OC3CON=0x000e; | |
416 | + OC3CONSET=0x8000; | |
417 | + | |
418 | + // Start timer3 | |
419 | + T3CON=0x8000; | |
420 | + | |
421 | + // Move OC4RS and OC3 RS from 0x00 to 0x80 | |
422 | + g_sound_mode=SOUND_MODE_NONE; | |
423 | + // Enable interrupt | |
424 | + IPC0bits.CS0IP=2; | |
425 | + IPC0bits.CS0IS=0; | |
426 | + IFS0bits.CS0IF=0; | |
427 | + IEC0bits.CS0IE=1; | |
428 | +} | |
429 | + | |
430 | +void musicSetL(){ | |
431 | + // Set length of a character. | |
432 | + // Syntax: L:n/m, where n and m are numbers. | |
433 | + int n,m; | |
434 | + n=musicGetNum(); | |
435 | + g_mspos++; | |
436 | + m=musicGetNum(); | |
437 | + g_lvalue=g_qvalue*n/m; | |
438 | +} | |
439 | + | |
440 | +void musicSetQ(){ | |
441 | + int i; | |
442 | + // Syntax: Q:1/4=n, where n is number. | |
443 | + // Skip "1/4=" | |
444 | + for(i=0;g_mstr[g_mspos+i]!='=';i++); | |
445 | + g_mspos+=i+1; | |
446 | + i=musicGetNum(); | |
447 | + if (i<48) { g_qvalue=320; /* 1/4=45 */ } | |
448 | + else if (i<53) { g_qvalue=288; /* 1/4=50 */ } | |
449 | + else if (i<60) { g_qvalue=256; /* 1/4=56 */ } | |
450 | + else if (i<70) { g_qvalue=224; /* 1/4=64 */ } | |
451 | + else if (i<83) { g_qvalue=192; /* 1/4=75 */ } | |
452 | + else if (i<102) { g_qvalue=160; /* 1/4=90 */ } | |
453 | + else if (i<132) { g_qvalue=128; /* 1/4=113 */ } | |
454 | + else if (i<188) { g_qvalue=96; /* 1/4=150 */ } | |
455 | + else { g_qvalue=64; /* 1/4=225 */ } | |
456 | + g_lvalue=g_qvalue>>3; | |
457 | +} | |
458 | + | |
459 | +void musicSetK(){ | |
460 | + // Syntax: K:xxx | |
461 | + if (!strncmp((char*)&(g_mstr[g_mspos]),"A#m",3)) { | |
462 | + g_mspos+=3; | |
463 | + g_tones=(int*)&(g_keys[0]); | |
464 | + return; | |
465 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"D#m",3)) { | |
466 | + g_mspos+=3; | |
467 | + g_tones=(int*)&(g_keys[7]); | |
468 | + return; | |
469 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"G#m",3)) { | |
470 | + g_mspos+=3; | |
471 | + g_tones=(int*)&(g_keys[14]); | |
472 | + return; | |
473 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"C#m",3)) { | |
474 | + g_mspos+=3; | |
475 | + g_tones=(int*)&(g_keys[21]); | |
476 | + return; | |
477 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"F#m",3)) { | |
478 | + g_mspos+=3; | |
479 | + g_tones=(int*)&(g_keys[28]); | |
480 | + return; | |
481 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Bbm",3)) { | |
482 | + g_mspos+=3; | |
483 | + g_tones=(int*)&(g_keys[84]); | |
484 | + return; | |
485 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Ebm",3)) { | |
486 | + g_mspos+=3; | |
487 | + g_tones=(int*)&(g_keys[91]); | |
488 | + return; | |
489 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Abm",3)) { | |
490 | + g_mspos+=3; | |
491 | + g_tones=(int*)&(g_keys[98]); | |
492 | + return; | |
493 | + } | |
494 | + if (!strncmp((char*)&(g_mstr[g_mspos]),"C#",2)) { | |
495 | + g_mspos+=2; | |
496 | + g_tones=(int*)&(g_keys[0]); | |
497 | + return; | |
498 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"F#",2)) { | |
499 | + g_mspos+=2; | |
500 | + g_tones=(int*)&(g_keys[7]); | |
501 | + return; | |
502 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Bm",2)) { | |
503 | + g_mspos+=2; | |
504 | + g_tones=(int*)&(g_keys[35]); | |
505 | + return; | |
506 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Em",2)) { | |
507 | + g_mspos+=2; | |
508 | + g_tones=(int*)&(g_keys[42]); | |
509 | + return; | |
510 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Am",2)) { | |
511 | + g_mspos+=2; | |
512 | + g_tones=(int*)&(g_keys[49]); | |
513 | + return; | |
514 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Dm",2)) { | |
515 | + g_mspos+=2; | |
516 | + g_tones=(int*)&(g_keys[56]); | |
517 | + return; | |
518 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Gm",2) || !strncmp((char*)&(g_mstr[g_mspos]),"Bb",2)) { | |
519 | + g_mspos+=2; | |
520 | + g_tones=(int*)&(g_keys[63]); | |
521 | + return; | |
522 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Cm",2) || !strncmp((char*)&(g_mstr[g_mspos]),"Eb",2)) { | |
523 | + g_mspos+=2; | |
524 | + g_tones=(int*)&(g_keys[70]); | |
525 | + return; | |
526 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Fm",2) || !strncmp((char*)&(g_mstr[g_mspos]),"Ab",2)) { | |
527 | + g_mspos+=2; | |
528 | + g_tones=(int*)&(g_keys[77]); | |
529 | + return; | |
530 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Db",2)) { | |
531 | + g_mspos+=2; | |
532 | + g_tones=(int*)&(g_keys[84]); | |
533 | + return; | |
534 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Gb",2)) { | |
535 | + g_mspos+=2; | |
536 | + g_tones=(int*)&(g_keys[91]); | |
537 | + return; | |
538 | + } else if (!strncmp((char*)&(g_mstr[g_mspos]),"Cb",2)) { | |
539 | + g_mspos+=2; | |
540 | + g_tones=(int*)&(g_keys[98]); | |
541 | + return; | |
542 | + } | |
543 | + switch(g_mstr[g_mspos]){ | |
544 | + case 'B': | |
545 | + g_mspos++; | |
546 | + g_tones=(int*)&(g_keys[14]); | |
547 | + return; | |
548 | + case 'E': | |
549 | + g_mspos++; | |
550 | + g_tones=(int*)&(g_keys[21]); | |
551 | + return; | |
552 | + case 'A': | |
553 | + g_mspos++; | |
554 | + g_tones=(int*)&(g_keys[28]); | |
555 | + return; | |
556 | + case 'D': | |
557 | + g_mspos++; | |
558 | + g_tones=(int*)&(g_keys[35]); | |
559 | + return; | |
560 | + case 'G': | |
561 | + g_mspos++; | |
562 | + g_tones=(int*)&(g_keys[42]); | |
563 | + return; | |
564 | + case 'C': | |
565 | + g_mspos++; | |
566 | + g_tones=(int*)&(g_keys[49]); | |
567 | + return; | |
568 | + case 'F': | |
569 | + g_mspos++; | |
570 | + g_tones=(int*)&(g_keys[56]); | |
571 | + return; | |
572 | + default: | |
573 | + err_music(g_mstr); | |
574 | + break; | |
575 | + } | |
576 | +} | |
577 | +void musicSetM(){ | |
578 | + // Currently do nothing | |
579 | + musicGetNum(); | |
580 | + musicGetNum(); | |
581 | +} | |
582 | + | |
583 | +void set_sound(unsigned long* data, int flagsLR){ | |
584 | + int sound; | |
585 | + int len; | |
586 | + int pos; | |
587 | + int datalen; | |
588 | + if (g_sound_mode==SOUND_MODE_NONE) { | |
589 | + // Start normal music mode | |
590 | + init_normal_music(); | |
591 | + } | |
592 | + IEC0bits.CS0IE=0; // Stop interruption, first. | |
593 | + // Initialize | |
594 | + if (flagsLR & MFLAG_L) g_soundrepeatL=g_soundstartL=g_soundendL=0; | |
595 | + if (flagsLR & MFLAG_R) g_soundrepeatR=g_soundstartR=g_soundendR=0; | |
596 | + pos=0; | |
597 | + do { | |
598 | + while(data[1]!=0x00000020) data++; // Seek DATA statement | |
599 | + datalen=(data[0]&0x00007FFF)-1; // Use bgezal statement containing data length. | |
600 | + data+=2; | |
601 | + while(0<datalen){ | |
602 | + datalen--; | |
603 | + len=data[0]>>16; | |
604 | + sound=data[0]&0x0000FFFF; | |
605 | + data++; | |
606 | + if (len) { | |
607 | + // Shift tone for 2048 <--> ~440 Hz. | |
608 | + // 2048 = 2^11 | |
609 | + // 16777216 = 2^24 | |
610 | + sound=sound<<13; | |
611 | + if (flagsLR & MFLAG_L) g_soundL[pos]=sound; | |
612 | + if (flagsLR & MFLAG_R) g_soundR[pos]=sound; | |
613 | + if (flagsLR & MFLAG_L) g_soundlenL[pos]=len; | |
614 | + if (flagsLR & MFLAG_R) g_soundlenR[pos]=len; | |
615 | + pos++; | |
616 | + if (32<pos) { | |
617 | + err_music("Sound data too long."); | |
618 | + return; | |
619 | + } | |
620 | + } else { | |
621 | + if (flagsLR & MFLAG_L) g_soundrepeatL=sound; | |
622 | + if (flagsLR & MFLAG_R) g_soundrepeatR=sound; | |
623 | + break; | |
624 | + } | |
625 | + } | |
626 | + } while(len); | |
627 | + if (flagsLR & MFLAG_L) g_soundendL=pos; | |
628 | + if (flagsLR & MFLAG_R) g_soundendR=pos; | |
629 | + if (flagsLR & MFLAG_L) g_soundwaitL=g_soundlenL[0]; | |
630 | + if (flagsLR & MFLAG_R) g_soundwaitR=g_soundlenR[0]; | |
631 | + IEC0bits.CS0IE=1; // Restart interrupt. | |
632 | +} | |
633 | + | |
634 | +void set_music(char* str, int flagsLR){ | |
635 | + char b; | |
636 | + unsigned long tone,tonenatural; | |
637 | + int len; | |
638 | + if (g_sound_mode==SOUND_MODE_NONE) { | |
639 | + // Start normal music mode | |
640 | + init_normal_music(); | |
641 | + } | |
642 | + g_mstr=str; | |
643 | + g_mspos=0; | |
644 | + while(0<(b=g_mstr[g_mspos])){ | |
645 | + if (g_mstr[g_mspos+1]==':') { | |
646 | + // Set property | |
647 | + g_mspos+=2; | |
648 | + switch(b){ | |
649 | + case 'L': | |
650 | + musicSetL(); | |
651 | + break; | |
652 | + case 'Q': | |
653 | + musicSetQ(); | |
654 | + break; | |
655 | + case 'K': | |
656 | + musicSetK(); | |
657 | + break; | |
658 | + case 'M': | |
659 | + musicSetM(); | |
660 | + break; | |
661 | + default: | |
662 | + err_music(str); | |
663 | + break; | |
664 | + } | |
665 | + } else if ('A'<=b && b<='G' || 'a'<=b && b<='g' || b=='z') { | |
666 | + g_mspos++; | |
667 | + if (b=='z') { | |
668 | + tone=0; | |
669 | + } else if (b<='G') { | |
670 | + tone=g_tones[b-'A']; | |
671 | + tonenatural=g_keys[b-'A'+49]; | |
672 | + } else { | |
673 | + tone=g_tones[b-'a']>>1; | |
674 | + tonenatural=g_keys[b-'a'+49]>>1; | |
675 | + } | |
676 | + // Check "'"s | |
677 | + while(g_mstr[g_mspos]=='\''){ | |
678 | + g_mspos++; | |
679 | + tone>>=1; | |
680 | + } | |
681 | + // Check ","s | |
682 | + while(g_mstr[g_mspos]==','){ | |
683 | + g_mspos++; | |
684 | + tone<<=1; | |
685 | + tonenatural<<=1; | |
686 | + } | |
687 | + // Check "^","=","_" | |
688 | + switch(g_mstr[g_mspos]){ | |
689 | + case '^': | |
690 | + g_mspos++; | |
691 | + tone=toneSharp(tone); | |
692 | + break; | |
693 | + case '_': | |
694 | + g_mspos++; | |
695 | + tone=toneFlat(tone); | |
696 | + break; | |
697 | + case '=': | |
698 | + g_mspos++; | |
699 | + tone=tonenatural; | |
700 | + break; | |
701 | + default: | |
702 | + break; | |
703 | + } | |
704 | + // Check number for length | |
705 | + b=g_mstr[g_mspos]; | |
706 | + if ('0'<=b && b<='9') { | |
707 | + len=g_lvalue*musicGetNum(); | |
708 | + } else { | |
709 | + len=g_lvalue; | |
710 | + } | |
711 | + if (g_mstr[g_mspos]=='/') { | |
712 | + g_mspos++; | |
713 | + len=len/musicGetNum(); | |
714 | + } | |
715 | + // Update music value array | |
716 | + IEC0bits.CS0IE=0; // Stop interruption, first. | |
717 | + // Update left music | |
718 | + if (flagsLR & MFLAG_L) { | |
719 | + if (g_musicstartL==g_musicendL) { | |
720 | + g_musicwaitL=len; | |
721 | + } | |
722 | + g_musicL[g_musicendL]=tone; | |
723 | + g_musiclenL[g_musicendL]=len; | |
724 | + g_musicendL++; | |
725 | + g_musicendL&=31; | |
726 | + } | |
727 | + // Update right music | |
728 | + if (flagsLR & MFLAG_R) { | |
729 | + if (g_musicstartR==g_musicendR) { | |
730 | + g_musicwaitR=len; | |
731 | + } | |
732 | + g_musicR[g_musicendR]=tone; | |
733 | + g_musiclenR[g_musicendR]=len; | |
734 | + g_musicendR++; | |
735 | + g_musicendR&=31; | |
736 | + } | |
737 | + IEC0bits.CS0IE=1; // Restart interruption. | |
738 | + } else { | |
739 | + err_music(str); | |
740 | + } | |
741 | + // Go to next character | |
742 | + while(0<g_mstr[g_mspos] && g_mstr[g_mspos]<=0x20 || g_mstr[g_mspos]=='|') g_mspos++; | |
743 | + } | |
744 | +} | |
745 | + | |
746 | +/* | |
747 | + In WAVE mode (for both stereo and monaural): | |
748 | + DMA2/OC4 is used for left | |
749 | + DMA1/OC3 is used for right | |
750 | + Timer 3 is used for PWM for both L/R | |
751 | + Timer 4 is used for both DMA1/DMA2 | |
752 | +*/ | |
753 | + | |
754 | +int checkChars(char* str1, char* str2, int num){ | |
755 | + int i; | |
756 | + for(i=0;i<num;i++){ | |
757 | + if (str1[i]!=str2[i]) return 1; | |
758 | + } | |
759 | + return 0; | |
760 | +} | |
761 | + | |
762 | +FSFILE* openWave(char* file){ | |
763 | + FSFILE *fp; | |
764 | + int i; | |
765 | + | |
766 | + // Open Wave file | |
767 | + fp=FSfopen(file,"r"); | |
768 | + if(fp==NULL) err_file(); | |
769 | + | |
770 | + // Read the header | |
771 | + if (0x2c != FSfread((void*)&wavtable[0],1,0x2c,fp)) { | |
772 | + err_wave(); | |
773 | + } | |
774 | + i=0; | |
775 | + i+=checkChars((char*)&wavtable[0],"RIFF",4); // Check RIFF | |
776 | + i+=checkChars((char*)&wavtable[8],"WAVEfmt ",8); // Check WAVE and fmt | |
777 | + i+=checkChars((char*)&wavtable[16],"\x10\x00\x00\x00\x01\x00",6); // Check if liear PCM | |
778 | + if (!checkChars((char*)&wavtable[22],"\x02\x00\x80\x3e\x00\x00\x00\x7d\x00\x00\x02\x00",12)) { | |
779 | + // Stereo 16000 Hz | |
780 | + wave_stereo=1; | |
781 | + } else if (!checkChars((char*)&wavtable[22],"\x01\x00\x80\x3e\x00\x00\x80\x3e\x00\x00\x01\x00",12)) { | |
782 | + // Monaural 16000 Hz | |
783 | + wave_stereo=0; | |
784 | + } else if (!checkChars((char*)&wavtable[22],"\x02\x00\x54\x3d\x00\x00\xa8\x7a\x00\x00\x02\x00",12)) { | |
785 | + // Stereo 15700 Hz | |
786 | + wave_stereo=1; | |
787 | + } else if (!checkChars((char*)&wavtable[22],"\x01\x00\x54\x3d\x00\x00\x54\x3d\x00\x00\x01\x00",12)) { | |
788 | + // Monaural 15700 Hz | |
789 | + wave_stereo=0; | |
790 | + } else { | |
791 | + i=1; | |
792 | + } | |
793 | + i+=checkChars((char*)&wavtable[34],"\x08\x00\x64\x61\x74\x61",6); // Check bit # and data | |
794 | + if (i) { | |
795 | + err_wave(); | |
796 | + } | |
797 | + return fp; | |
798 | +} | |
799 | + | |
800 | +void init_wave_dma(){ | |
801 | + // Timer4 for 15700 Hz | |
802 | + TMR4=0; | |
803 | + PR4=6080-1; | |
804 | + TMR4=PR4-1; | |
805 | + T4CON=0x0000; // Not start yet | |
806 | + | |
807 | + if (wave_stereo) { | |
808 | + //DMA2 settings for OC4 for left | |
809 | + DMACONSET=0x8000; | |
810 | + DCH2CON=0x00000012; // CHBUSY=0, CHCHNS=0, CHEN=0, CHAED=0, CHCHN=0, CHAEN=1, CHEDET=0, CHPRI=b10 | |
811 | + DCH2ECON=0x1310; // CHAIRQ=0, CHSIRQ=19, CFORCE=0, CABRT=0, PATEN=0, SIRQEN=1, AIRQEN=0 | |
812 | + // CHSIRQ=19: Timer4 interrupt | |
813 | + DCH2SSA=((unsigned int)&(wavtable[-1]))&0x1fffffff; | |
814 | + DCH2DSA=0x1F803620-1; // OC4RS | |
815 | + DCH2SSIZ=524*2; | |
816 | + DCH2DSIZ=2; | |
817 | + DCH2CSIZ=2; | |
818 | + DCH2INTCLR=0x00FF00FF; | |
819 | + DCH2CONSET=0x00000080; | |
820 | + | |
821 | + //DMA1 settings for OC3 for rifht | |
822 | + DMACONSET=0x8000; | |
823 | + DCH1CON=0x00000012; // CHBUSY=0, CHCHNS=0, CHEN=0, CHAED=0, CHCHN=0, CHAEN=1, CHEDET=0, CHPRI=b10 | |
824 | + DCH1ECON=0x1310; // CHAIRQ=0, CHSIRQ=19, CFORCE=0, CABRT=0, PATEN=0, SIRQEN=1, AIRQEN=0 | |
825 | + // CHSIRQ=19: Timer4 interrupt | |
826 | + DCH1SSA=((unsigned int)&(wavtable[0]))&0x1fffffff; | |
827 | + DCH1DSA=0x1F803420-1; // OC3RS | |
828 | + DCH1SSIZ=524*2; | |
829 | + DCH1DSIZ=2; | |
830 | + DCH1CSIZ=2; | |
831 | + DCH1INTCLR=0x00FF00FF; | |
832 | + DCH1CONSET=0x00000080; | |
833 | + } else { | |
834 | + //DMA2 settings for OC4 for left | |
835 | + DMACONSET=0x8000; | |
836 | + DCH2CON=0x00000012; // CHBUSY=0, CHCHNS=0, CHEN=0, CHAED=0, CHCHN=0, CHAEN=1, CHEDET=0, CHPRI=b10 | |
837 | + DCH2ECON=0x1310; // CHAIRQ=0, CHSIRQ=19, CFORCE=0, CABRT=0, PATEN=0, SIRQEN=1, AIRQEN=0 | |
838 | + // CHSIRQ=19: Timer4 interrupt | |
839 | + DCH2SSA=((unsigned int)&(wavtable[0]))&0x1fffffff; | |
840 | + DCH2DSA=0x1F803620; // OC4RS | |
841 | + DCH2SSIZ=524; | |
842 | + DCH2DSIZ=1; | |
843 | + DCH2CSIZ=1; | |
844 | + DCH2INTCLR=0x00FF00FF; | |
845 | + DCH2CONSET=0x00000080; | |
846 | + | |
847 | + //DMA1 settings for OC3 for rifht | |
848 | + DMACONSET=0x8000; | |
849 | + DCH1CON=0x00000012; // CHBUSY=0, CHCHNS=0, CHEN=0, CHAED=0, CHCHN=0, CHAEN=1, CHEDET=0, CHPRI=b10 | |
850 | + DCH1ECON=0x1310; // CHAIRQ=0, CHSIRQ=19, CFORCE=0, CABRT=0, PATEN=0, SIRQEN=1, AIRQEN=0 | |
851 | + // CHSIRQ=19: Timer4 interrupt | |
852 | + DCH1SSA=((unsigned int)&(wavtable[0]))&0x1fffffff; | |
853 | + DCH1DSA=0x1F803420; // OC3RS | |
854 | + DCH1SSIZ=524; | |
855 | + DCH1DSIZ=1; | |
856 | + DCH1CSIZ=1; | |
857 | + DCH1INTCLR=0x00FF00FF; | |
858 | + DCH1CONSET=0x00000080; | |
859 | + } | |
860 | + | |
861 | +} | |
862 | + | |
863 | +void play_wave(char* filename, int start){ | |
864 | + // First of all, stop music. | |
865 | + stop_music(); | |
866 | + // Exit function if null filename | |
867 | + if (filename[0]==0x00) { | |
868 | + OC3RS=OC4RS=0x80; | |
869 | + return; | |
870 | + } | |
871 | + // Alocate 524*2 byte buffer if not assigned | |
872 | + if (g_var_size[ALLOC_WAVE_BLOCK]==0) { | |
873 | + wavtable=(char*)alloc_memory(524*2/4,ALLOC_WAVE_BLOCK); | |
874 | + } | |
875 | + // Open file | |
876 | + if (g_fhandle) FSfclose(g_fhandle); | |
877 | + g_fhandle=openWave(filename); | |
878 | + // Support defined start position here to skip file pointer here. | |
879 | + if (wave_stereo) start=start<<1; | |
880 | + FSfseek(g_fhandle, start, SEEK_CUR); | |
881 | + // Read first 262/524 words. | |
882 | + if (wave_sector_size != FSfread((void*)&wavtable[0],1,wave_sector_size,g_fhandle)) err_file(); | |
883 | + // Initialize DMA | |
884 | + init_wave_dma(); | |
885 | + g_sound_mode=SOUND_MODE_WAVE; | |
886 | + // Enable intterupt | |
887 | + IFS0bits.CS0IF=0; | |
888 | + IEC0bits.CS0IE=1; | |
889 | +} | |
890 | + | |
891 | +void stop_music(){ | |
892 | + // Set NONE sound mode | |
893 | + g_sound_mode=SOUND_MODE_NONE; | |
894 | + // Stop DMA1 and DMA2 | |
895 | + DCH1CONCLR=0x00000080; | |
896 | + DCH2CONCLR=0x00000080; | |
897 | + // Close WAVE file if open | |
898 | + if (g_fhandle) { | |
899 | + FSfclose(g_fhandle); | |
900 | + g_fhandle=0; | |
901 | + } | |
902 | +} |
@@ -0,0 +1,312 @@ | ||
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 "lib_video_megalopa.h" | |
12 | +#include "ps2keyboard.h" | |
13 | +#include "io.h" | |
14 | + | |
15 | +/* | |
16 | + int readbuttons(); | |
17 | + Read the tact switches. | |
18 | + For Zoea, disable PS/2 keyboard and enable tact switches, then read. | |
19 | +*/ | |
20 | + | |
21 | +int readbuttons(){ | |
22 | + return KEYPORT; | |
23 | +} | |
24 | + | |
25 | +/* | |
26 | + void pre_run(void); | |
27 | + void post_run(void); | |
28 | + Called before after execution of BASIC code. | |
29 | +*/ | |
30 | + | |
31 | +void pre_run(void){ | |
32 | + // Reset PWM | |
33 | + lib_pwm(0,0,0); | |
34 | +} | |
35 | +void post_run(void){ | |
36 | + if (graphmode==GMODE_ZOEAGRPH) { | |
37 | + // Stop graph mode when using Zoea compatible one. | |
38 | + usegraphic(0); | |
39 | + g_use_graphic=0; | |
40 | + } | |
41 | +} | |
42 | + | |
43 | + | |
44 | + | |
45 | +/* | |
46 | + init_env(); | |
47 | + Initialize envionment. | |
48 | +*/ | |
49 | + | |
50 | +void init_env(void){ | |
51 | + // Reset PWM | |
52 | + lib_pwm(0,0,0); | |
53 | +} | |
54 | + | |
55 | +/* | |
56 | + void scroll(int x, int y); | |
57 | + Scroll | |
58 | +*/ | |
59 | + | |
60 | +void scroll(int x,int y){ | |
61 | + int i,j; | |
62 | + int vector=y*twidth+x; | |
63 | + if (vector<0) { | |
64 | + // Copy data from upper address to lower address | |
65 | + for(i=0-vector;i<twidth*WIDTH_Y;i++){ | |
66 | + TVRAM[i+vector]=TVRAM[i]; | |
67 | + TVRAM[twidth*WIDTH_Y+i+vector]=TVRAM[twidth*WIDTH_Y+i]; | |
68 | + } | |
69 | + } else if (0<vector) { | |
70 | + // Copy data from lower address to upper address | |
71 | + for(i=twidth*WIDTH_Y-vector-1;0<=i;i--){ | |
72 | + TVRAM[i+vector]=TVRAM[i]; | |
73 | + TVRAM[twidth*WIDTH_Y+i+vector]=TVRAM[twidth*WIDTH_Y+i]; | |
74 | + } | |
75 | + } else { | |
76 | + return; | |
77 | + } | |
78 | + if (x<0) { | |
79 | + // Fill blanc at right | |
80 | + for(i=x;i<0;i++){ | |
81 | + for(j=twidth+i;j<twidth*WIDTH_Y;j+=twidth){ | |
82 | + TVRAM[j]=0x00; | |
83 | + TVRAM[twidth*WIDTH_Y+j]=cursorcolor; | |
84 | + } | |
85 | + } | |
86 | + } else if (0<x) { | |
87 | + // Fill blanc at left | |
88 | + for(i=0;i<x;i++){ | |
89 | + for(j=i;j<twidth*WIDTH_Y;j+=twidth){ | |
90 | + TVRAM[j]=0x00; | |
91 | + TVRAM[twidth*WIDTH_Y+j]=cursorcolor; | |
92 | + } | |
93 | + } | |
94 | + } | |
95 | + if (y<0) { | |
96 | + // Fill blanc at bottom | |
97 | + for(i=twidth*(WIDTH_Y+y);i<twidth*WIDTH_Y;i++){ | |
98 | + TVRAM[i]=0x00; | |
99 | + TVRAM[twidth*WIDTH_Y+i]=cursorcolor; | |
100 | + } | |
101 | + } else if (0<y) { | |
102 | + // Fill blanc at top | |
103 | + for(i=0;i<twidth*y;i++){ | |
104 | + TVRAM[i]=0x00; | |
105 | + TVRAM[twidth*WIDTH_Y+i]=cursorcolor; | |
106 | + } | |
107 | + } | |
108 | +} | |
109 | + | |
110 | +void allocate_graphic_area(int mode){ | |
111 | + static int prevmode=-1; | |
112 | + if (g_graphic_area) { | |
113 | + if (mode==prevmode) { | |
114 | + // Do nothing | |
115 | + return; | |
116 | + } else { | |
117 | + // Clear previous area here | |
118 | + free_temp_str((char*)g_graphic_area); | |
119 | + g_graphic_area=0; | |
120 | + } | |
121 | + } | |
122 | + switch (mode) { | |
123 | + case 0: | |
124 | + g_graphic_area=alloc_memory(X_RESZ*Y_RESZ/2/4,ALLOC_GRAPHIC_BLOCK); | |
125 | + break; | |
126 | + case 1: | |
127 | + g_graphic_area=alloc_memory(X_RES*Y_RES/4,ALLOC_GRAPHIC_BLOCK); | |
128 | + break; | |
129 | + case 2: | |
130 | + g_graphic_area=alloc_memory(X_RESW*Y_RES/4,ALLOC_GRAPHIC_BLOCK); | |
131 | + break; | |
132 | + default: | |
133 | + err_invalid_param(); | |
134 | + } | |
135 | + // Store current graphic mode | |
136 | + prevmode=mode; | |
137 | +} | |
138 | + | |
139 | +void start_graphic(int mode){ | |
140 | + if (!g_graphic_area) return; | |
141 | + switch (mode) { | |
142 | + case 0: | |
143 | + set_videomode(VMODE_ZOEAGRPH,(unsigned char *)g_graphic_area); | |
144 | + break; | |
145 | + case 1: | |
146 | + set_videomode(VMODE_STDGRPH,(unsigned char *)g_graphic_area); | |
147 | + break; | |
148 | + case 2: | |
149 | + set_videomode(VMODE_WIDEGRPH,(unsigned char *)g_graphic_area); | |
150 | + break; | |
151 | + default: | |
152 | + err_invalid_param(); | |
153 | + } | |
154 | +} | |
155 | + | |
156 | +void usegraphic(int mode){ | |
157 | + if (mode<0 || 11<mode) err_invalid_param(); | |
158 | + switch(mode & 3){ | |
159 | + // Modes; 0: stop GRAPHIC, 1: use GRAPHIC, 2: reset GRAPHIC and use it, 3: allocate GRAPHIC area but not use it | |
160 | + case 0: | |
161 | + if (g_use_graphic){ | |
162 | + // Stop GRAPHIC if used | |
163 | + set_videomode(textmode,0); | |
164 | + g_use_graphic=0; | |
165 | + } else { | |
166 | + // Prepare GRAPHIC area if not used and not allcated. | |
167 | + allocate_graphic_area(mode>>2); | |
168 | + } | |
169 | + break; | |
170 | + case 2: | |
171 | + // Reset GRAPHIC and use it | |
172 | + if (g_graphic_area) { | |
173 | + g_clearscreen(); | |
174 | + init_palette(); | |
175 | + } | |
176 | + // Continue to case 1: | |
177 | + case 1: | |
178 | + case 3: | |
179 | + default: | |
180 | + // Use GRAPHIC | |
181 | + allocate_graphic_area(mode>>2); | |
182 | + // Start showing GRAPHIC with mode 1, but not with mode 3 | |
183 | + if ((mode & 3) !=3 && !g_use_graphic){ | |
184 | + // Change to graphic mode. | |
185 | + start_graphic(mode>>2); | |
186 | + g_use_graphic=1; | |
187 | + } | |
188 | + break; | |
189 | + } | |
190 | +} | |
191 | + | |
192 | +int lib_system(int a0, int a1 ,int v0, int a3, int g_gcolor, int g_prev_x, int g_prev_y){ | |
193 | + switch((enum extra)(a3 & EXTRA_MASK)){ | |
194 | + case EXTRA_SYSTEM: | |
195 | + // SYSTEM statement/function (see below) | |
196 | + break; | |
197 | + case EXTRA_OUT: | |
198 | + lib_out(g_libparams[1],v0); | |
199 | + return v0; | |
200 | + case EXTRA_OUT8H: | |
201 | + lib_out8h(v0); | |
202 | + return v0; | |
203 | + case EXTRA_OUT8L: | |
204 | + lib_out8l(v0); | |
205 | + return v0; | |
206 | + case EXTRA_OUT16: | |
207 | + lib_out16(v0); | |
208 | + return v0; | |
209 | + case EXTRA_IN: | |
210 | + return lib_in(v0); | |
211 | + case EXTRA_IN8H: | |
212 | + return lib_in8h(); | |
213 | + case EXTRA_IN8L: | |
214 | + return lib_in8l(); | |
215 | + case EXTRA_IN16: | |
216 | + return lib_in16(); | |
217 | + case EXTRA_ANALOG: | |
218 | + return lib_analog(v0); | |
219 | + case EXTRA_PWM: | |
220 | + lib_pwm(g_libparams[1],g_libparams[2],v0); | |
221 | + return v0; | |
222 | + case EXTRA_SERIAL: | |
223 | + lib_serial(g_libparams[1],g_libparams[2],v0); | |
224 | + return v0; | |
225 | + case EXTRA_SERIALOUT: | |
226 | + lib_serialout(v0); | |
227 | + return v0; | |
228 | + case EXTRA_SERIALIN: | |
229 | + return lib_serialin(v0); | |
230 | + case EXTRA_SPI: | |
231 | + case EXTRA_SPIOUT: | |
232 | + case EXTRA_SPIIN: | |
233 | + // TODO: Implement IO functions | |
234 | + return v0; | |
235 | + default: | |
236 | + err_unknown(); | |
237 | + return v0; | |
238 | + } | |
239 | + switch(a0){ | |
240 | + // Version info | |
241 | + case 0: return (int)SYSVER1; | |
242 | + case 1: return (int)SYSVER2; | |
243 | + case 2: return (int)BASVER; | |
244 | + case 3: return (int)FILENAME_FLASH_ADDRESS; | |
245 | + // Display info | |
246 | + case 20: return twidth; | |
247 | + case 21: return twidthy; | |
248 | + case 22: return gwidth; | |
249 | + case 23: return gwidthy; | |
250 | + case 24: return cursorcolor; | |
251 | + case 25: return g_gcolor; | |
252 | + case 26: return ((int)(cursor-TVRAM))%twidth; | |
253 | + case 27: return ((int)(cursor-TVRAM))/twidth; | |
254 | + case 28: return g_prev_x; | |
255 | + case 29: return g_prev_y; | |
256 | + // Keyboard info | |
257 | + case 40: return (int)inPS2MODE(); | |
258 | + case 41: return (int)vkey; | |
259 | + case 42: return (int)lockkey; | |
260 | + case 43: return (int)keytype; | |
261 | + // Pointers to gloval variables | |
262 | + case 100: return (int)&g_var_mem[0]; | |
263 | + case 101: return (int)&g_rnd_seed; | |
264 | + case 102: return (int)&TVRAM[0]; | |
265 | + case 103: return (int)&FontData[0]; | |
266 | + case 104: return (int)g_var_mem[ALLOC_PCG_BLOCK]; | |
267 | + case 105: return (int)g_var_mem[ALLOC_GRAPHIC_BLOCK]; | |
268 | + // Change system settings | |
269 | + case 200: | |
270 | + // ON/OFF monitor | |
271 | + if (v0) { | |
272 | + start_composite(); | |
273 | + } else { | |
274 | + stop_composite(); | |
275 | + } | |
276 | + break; | |
277 | + default: | |
278 | + break; | |
279 | + } | |
280 | + return 0; | |
281 | +} | |
282 | + | |
283 | +void videowidth(int width){ | |
284 | + switch(width){ | |
285 | + case 30: | |
286 | + set_videomode(VMODE_T30,0); | |
287 | + break; | |
288 | + case 36: | |
289 | + set_videomode(VMODE_STDTEXT,0); | |
290 | + break; | |
291 | + case 40: | |
292 | + set_videomode(VMODE_T40,0); | |
293 | + break; | |
294 | + case 48: | |
295 | + set_videomode(VMODE_WIDETEXT,0); | |
296 | + break; | |
297 | + case 64: | |
298 | + set_videomode(VMODE_WIDETEXT6dot,0); | |
299 | + break; | |
300 | + case 80: | |
301 | + set_videomode(VMODE_MONOTEXT,0); | |
302 | + break; | |
303 | + default: | |
304 | + // Do nothing | |
305 | + return; | |
306 | + } | |
307 | + g_use_graphic=0; | |
308 | +} | |
309 | + | |
310 | +void set_graphmode(unsigned char m){ | |
311 | + if (m==0) set_videomode(VMODE_T30,0); | |
312 | +} |
@@ -0,0 +1,376 @@ | ||
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 envilonment specific configurations | |
9 | +#include "envspecific.h" | |
10 | + | |
11 | +/* Definitions */ | |
12 | +// Number of variables (including temporary ones) | |
13 | +#define ALLOC_VAR_NUM 36 | |
14 | +// Block # dedicated for PCG | |
15 | +#define ALLOC_PCG_BLOCK 36 | |
16 | +// Block # dedicated for GRAPHIC | |
17 | +#define ALLOC_GRAPHIC_BLOCK 37 | |
18 | +// Block # dedicated for PLAYWAVE | |
19 | +#define ALLOC_WAVE_BLOCK 38 | |
20 | +// Start # for long name variables | |
21 | +#define ALLOC_LNV_BLOCK 39 | |
22 | +// Number of long name variables | |
23 | +#define ALLOC_LNV_NUM 190 | |
24 | +// Start # of permanent blocks | |
25 | +#define ALLOC_PERM_BLOCK 229 | |
26 | +// Number of blocks that can be assigned for memory allocation (including all above) | |
27 | +#define ALLOC_BLOCK_NUM 239 | |
28 | + | |
29 | +// Persistent RAM bytes used for object, heap and exception data | |
30 | +#ifndef PERSISTENT_RAM_SIZE | |
31 | + // This must be defined in envspecific.h | |
32 | + #define PERSISTENT_RAM_SIZE (1024*53) | |
33 | +#endif | |
34 | +// Exception data area bytes | |
35 | +#define EXCEPTION_DATA_SIZE (64) | |
36 | +// RAM size used for object and heap | |
37 | +#define RAMSIZE (PERSISTENT_RAM_SIZE-EXCEPTION_DATA_SIZE) | |
38 | + | |
39 | +/* Enums */ | |
40 | +enum variable{ | |
41 | + VAR_INTEGER, | |
42 | + VAR_FLOAT, | |
43 | + VAR_STRING | |
44 | +}; | |
45 | + | |
46 | +#define OP_MASK 0x001F | |
47 | +enum operator{ | |
48 | + OP_VOID=0, | |
49 | + OP_OR =1, | |
50 | + OP_AND =2, | |
51 | + OP_XOR =3, | |
52 | + OP_EQ =4, | |
53 | + OP_NEQ =5, | |
54 | + OP_LT =6, | |
55 | + OP_LTE =7, | |
56 | + OP_MT =8, | |
57 | + OP_MTE =9, | |
58 | + OP_SHL =10, | |
59 | + OP_SHR =11, | |
60 | + OP_ADD =12, | |
61 | + OP_SUB =13, | |
62 | + OP_MUL =14, | |
63 | + OP_DIV =15, | |
64 | + OP_REM =16 | |
65 | +}; | |
66 | + | |
67 | +#define LIB_MASK 0xFE00 | |
68 | +#define LIB_STEP 0x0200 | |
69 | +enum libs{ | |
70 | + LIB_SOUND =LIB_STEP*0, | |
71 | + LIB_MUSICFUNC =LIB_STEP*1, | |
72 | + LIB_MUSIC =LIB_STEP*2, | |
73 | + LIB_SETDRAWCOUNT =LIB_STEP*3, | |
74 | + LIB_DRAWCOUNT =LIB_STEP*4, | |
75 | + LIB_PALETTE =LIB_STEP*5, | |
76 | + LIB_GPALETTE =LIB_STEP*6, | |
77 | + LIB_BGCOLOR =LIB_STEP*7, | |
78 | + LIB_CURSOR =LIB_STEP*8, | |
79 | + LIB_CLS =LIB_STEP*9, | |
80 | + LIB_GCLS =LIB_STEP*10, | |
81 | + LIB_COLOR =LIB_STEP*11, | |
82 | + LIB_GCOLOR =LIB_STEP*12, | |
83 | + LIB_KEYS =LIB_STEP*13, | |
84 | + LIB_RESTORE =LIB_STEP*14, | |
85 | + LIB_RESTORE2 =LIB_STEP*15, | |
86 | + LIB_READ =LIB_STEP*16, | |
87 | + LIB_MIDSTR =LIB_STEP*17, | |
88 | + LIB_CLEAR =LIB_STEP*18, | |
89 | + LIB_DIV0 =LIB_STEP*19, | |
90 | + LIB_LETSTR =LIB_STEP*20, | |
91 | + LIB_STRNCMP =LIB_STEP*21, | |
92 | + LIB_RND =LIB_STEP*22, | |
93 | + LIB_DEC =LIB_STEP*23, | |
94 | + LIB_HEX =LIB_STEP*24, | |
95 | + LIB_CHR =LIB_STEP*25, | |
96 | + LIB_CONNECT_STRING =LIB_STEP*26, | |
97 | + LIB_STRING =LIB_STEP*27, | |
98 | + LIB_PRINTSTR =LIB_STEP*28, | |
99 | + LIB_LABEL =LIB_STEP*29, | |
100 | + LIB_DIM =LIB_STEP*30, | |
101 | + LIB_VAL =LIB_STEP*31, | |
102 | + LIB_INPUT =LIB_STEP*32, | |
103 | + LIB_INKEY =LIB_STEP*33, | |
104 | + LIB_USEPCG =LIB_STEP*34, | |
105 | + LIB_PCG =LIB_STEP*35, | |
106 | + LIB_SCROLL =LIB_STEP*36, | |
107 | + LIB_WAIT =LIB_STEP*37, | |
108 | + LIB_VAR_PUSH =LIB_STEP*38, | |
109 | + LIB_VAR_POP =LIB_STEP*39, | |
110 | + LIB_SYSTEM =LIB_STEP*40, | |
111 | + LIB_SPRINTF =LIB_STEP*41, | |
112 | + LIB_FLOAT =LIB_STEP*42, | |
113 | + LIB_FLOATFUNCS =LIB_STEP*43, | |
114 | + LIB_CREAD =LIB_STEP*44, | |
115 | + LIB_USEGRAPHIC =LIB_STEP*45, | |
116 | + LIB_GRAPHIC =LIB_STEP*46, | |
117 | + LIB_WIDTH =LIB_STEP*47, | |
118 | + LIB_FILE =LIB_STEP*48, | |
119 | + LIB_PLAYWAVE =LIB_STEP*49, | |
120 | + LIB_PLAYWAVEFUNC =LIB_STEP*50, | |
121 | + LIB_DEBUG =LIB_STEP*127, | |
122 | +}; | |
123 | + | |
124 | +// Note: OP_XXXX and FUNC_XXXX cannot be used simultaneously | |
125 | +#define FUNC_MASK 0x003F | |
126 | +#define FUNC_STEP 0x0001 | |
127 | +enum functions{ | |
128 | + FUNC_FLOAT =FUNC_STEP*0, | |
129 | + FUNC_INT =FUNC_STEP*1, | |
130 | + FUNC_VALSHARP =FUNC_STEP*2, | |
131 | + FUNC_SIN =FUNC_STEP*3, | |
132 | + FUNC_COS =FUNC_STEP*4, | |
133 | + FUNC_TAN =FUNC_STEP*5, | |
134 | + FUNC_ASIN =FUNC_STEP*6, | |
135 | + FUNC_ACOS =FUNC_STEP*7, | |
136 | + FUNC_ATAN =FUNC_STEP*8, | |
137 | + FUNC_ATAN2 =FUNC_STEP*9, | |
138 | + FUNC_SINH =FUNC_STEP*10, | |
139 | + FUNC_COSH =FUNC_STEP*11, | |
140 | + FUNC_TANH =FUNC_STEP*12, | |
141 | + FUNC_EXP =FUNC_STEP*13, | |
142 | + FUNC_LOG =FUNC_STEP*14, | |
143 | + FUNC_LOG10 =FUNC_STEP*15, | |
144 | + FUNC_POW =FUNC_STEP*16, | |
145 | + FUNC_SQRT =FUNC_STEP*17, | |
146 | + FUNC_CEIL =FUNC_STEP*18, | |
147 | + FUNC_FLOOR =FUNC_STEP*19, | |
148 | + FUNC_FABS =FUNC_STEP*20, | |
149 | + FUNC_MODF =FUNC_STEP*21, | |
150 | + FUNC_FMOD =FUNC_STEP*22, | |
151 | + FUNC_PSET =FUNC_STEP*23, | |
152 | + FUNC_LINE =FUNC_STEP*24, | |
153 | + FUNC_BOXFILL =FUNC_STEP*25, | |
154 | + FUNC_CIRCLE =FUNC_STEP*26, | |
155 | + FUNC_CIRCLEFILL =FUNC_STEP*27, | |
156 | + FUNC_GPRINT =FUNC_STEP*28, | |
157 | + FUNC_PUTBMP =FUNC_STEP*29, | |
158 | + FUNC_PUTBMP2 =FUNC_STEP*30, | |
159 | + FUNC_GCOLOR =FUNC_STEP*31, | |
160 | + FUNC_POINT =FUNC_STEP*32, | |
161 | + FUNC_FOPEN =FUNC_STEP*33, | |
162 | + FUNC_FOPENST =FUNC_STEP*34, | |
163 | + FUNC_FILE =FUNC_STEP*35, | |
164 | + FUNC_FCLOSE =FUNC_STEP*36, | |
165 | + FUNC_FINPUT =FUNC_STEP*37, | |
166 | + FUNC_FPRINTSTR =FUNC_STEP*38, | |
167 | + FUNC_FGET =FUNC_STEP*39, | |
168 | + FUNC_FPUT =FUNC_STEP*40, | |
169 | + FUNC_FSEEK =FUNC_STEP*41, | |
170 | + FUNC_FTELL =FUNC_STEP*42, | |
171 | + FUNC_FLEN =FUNC_STEP*43, | |
172 | + FUNC_FSTRING =FUNC_STEP*44, | |
173 | + FUNC_FGETC =FUNC_STEP*45, | |
174 | + FUNC_FPUTC =FUNC_STEP*46, | |
175 | + FUNC_FREMOVE =FUNC_STEP*47, | |
176 | + FUNC_FEOF =FUNC_STEP*48, | |
177 | + FUNC_FINIT =FUNC_STEP*49, | |
178 | + // MAX 63 | |
179 | +}; | |
180 | + | |
181 | +/* Global vars (see globalvers.c) */ | |
182 | +extern int g_intconst; | |
183 | +extern char g_valueisconst; | |
184 | +extern unsigned int g_rnd_seed; | |
185 | +extern unsigned int g_label; | |
186 | +extern int g_sdepth; | |
187 | +extern int g_maxsdepth; | |
188 | +extern enum variable g_lastvar; | |
189 | +extern char* g_source; | |
190 | +extern int g_srcpos; | |
191 | +extern int g_line; | |
192 | +extern int g_fileline; | |
193 | +extern int* g_object; | |
194 | +extern int g_objpos; | |
195 | +extern int* g_objmax; | |
196 | +extern const char* g_err_str[]; | |
197 | +extern const unsigned char g_priority[]; | |
198 | +extern enum operator g_last_op; | |
199 | +extern int g_end_addr; | |
200 | +extern int g_gp; | |
201 | +extern int g_s6; | |
202 | +extern char RAM[RAMSIZE]; | |
203 | +extern unsigned int g_ex_data[EXCEPTION_DATA_SIZE/4]; | |
204 | +extern int g_var_mem[ALLOC_BLOCK_NUM]; | |
205 | +extern unsigned short g_var_pointer[ALLOC_BLOCK_NUM]; | |
206 | +extern unsigned short g_var_size[ALLOC_BLOCK_NUM]; | |
207 | +extern char g_temp_area_used; | |
208 | +extern int* g_heap_mem; | |
209 | +extern int g_max_mem; | |
210 | +extern char g_disable_break; | |
211 | +extern unsigned char* g_pcg_font; | |
212 | +extern char g_use_graphic; | |
213 | +extern unsigned short* g_graphic_area; | |
214 | +extern int* g_libparams; | |
215 | +extern int g_long_name_var_num; | |
216 | +extern int g_temp; | |
217 | + | |
218 | +/* Prototypes */ | |
219 | +int get_gp(void); | |
220 | +int get_fp(void); | |
221 | +void start_program(void* addr, void* memory); | |
222 | +void shift_obj(int* src, int* dst, int len); | |
223 | +char* compile_line(void); | |
224 | +int nextCodeIs(char* str); | |
225 | +int endOfStatement(); | |
226 | + | |
227 | +char* init_file(char* buff,char* appname); | |
228 | +void close_file(); | |
229 | +void read_file(int blocklen); | |
230 | +char* compile_file(); | |
231 | + | |
232 | +void err_break(void); | |
233 | +void err_music(char* str); | |
234 | +void err_data_not_found(void); | |
235 | +void err_str_complex(void); | |
236 | +void err_label_not_found(void); | |
237 | +void err_no_mem(void); | |
238 | +void err_div_zero(void); | |
239 | +void err_unkonwn(void); | |
240 | +void err_unexp_next(void); | |
241 | +void err_no_block(void); | |
242 | +void err_invalid_param(void); | |
243 | +void err_file(void); | |
244 | +void err_wave(void); | |
245 | +char* resolve_label(int s6); | |
246 | + | |
247 | +void set_sound(unsigned long* data, int flagsLR); | |
248 | +int musicRemaining(int flagsLR); | |
249 | +int waveRemaining(int mode); | |
250 | +void set_music(char* str, int flagsLR); | |
251 | +void stop_music(void); | |
252 | +void init_music(void); | |
253 | +void play_wave(char* filename, int start); | |
254 | + | |
255 | +char* statement(void); | |
256 | +char* gosub_statement(); | |
257 | +char* graphic_statement(enum functions func); | |
258 | +char* fopen_statement_main(enum functions func); | |
259 | +char* fget_statement(); | |
260 | +char* fput_statement(); | |
261 | +char* fputc_statement(); | |
262 | +char* fremove_statement(); | |
263 | + | |
264 | +char* function(void); | |
265 | +char* str_function(void); | |
266 | +char* float_function(void); | |
267 | + | |
268 | +void call_library(void); | |
269 | +void reset_dataread(); | |
270 | + | |
271 | +void free_temp_str(char* str); | |
272 | +void* alloc_memory(int size, int var_num); | |
273 | +void* calloc_memory(int size, int var_num); | |
274 | +void move_to_perm_block(int var_num); | |
275 | +void move_from_perm_block(int var_num); | |
276 | +int get_permanent_var_num(void); | |
277 | + | |
278 | +char* link(void); | |
279 | +char* get_label(void); | |
280 | +void* search_label(unsigned int label); | |
281 | + | |
282 | +char* get_string(); | |
283 | +char* simple_string(void); | |
284 | + | |
285 | +char* get_operator(void); | |
286 | +char* get_floatOperator(void); | |
287 | +char* calculation(enum operator op); | |
288 | +char* calculation_float(enum operator op); | |
289 | +int lib_float(int ia0,int iv0, enum operator a1); | |
290 | + | |
291 | +int lib_file(enum functions func, int a0, int a1, int v0); | |
292 | + | |
293 | +char* get_dim_value(int i); | |
294 | +char* get_simple_value(void); | |
295 | +char* get_value(); | |
296 | +char* get_floatOrValue(); | |
297 | +char* get_stringFloatOrValue(); | |
298 | + | |
299 | +void blue_screen(void); | |
300 | + | |
301 | +char* get_float(); | |
302 | + | |
303 | +void cmpdata_init(); | |
304 | +char* cmpdata_insert(unsigned char type, short data16, int* data, unsigned char num); | |
305 | +void cmpdata_reset(); | |
306 | +int* cmpdata_find(unsigned char type); | |
307 | +int* cmpdata_findfirst(unsigned char type); | |
308 | + | |
309 | +int check_var_name(); | |
310 | +int get_var_number(); | |
311 | +int search_var_name(int nameint); | |
312 | +char* register_var_name(int nameint); | |
313 | + | |
314 | + | |
315 | +/* Error messages */ | |
316 | +#define ERR_SYNTAX (char*)(g_err_str[0]) | |
317 | +#define ERR_NE_BINARY (char*)(g_err_str[1]) | |
318 | +#define ERR_NE_MEMORY (char*)(g_err_str[2]) | |
319 | +#define ERR_DIV_0 (char*)(g_err_str[3]) | |
320 | +#define ERR_NY_I (char*)(g_err_str[4]) | |
321 | +#define ERR_LABEL_NF (char*)(g_err_str[5]) | |
322 | +#define ERR_LABEL_LONG (char*)(g_err_str[6]) | |
323 | +#define ERR_STR_COMPLEX (char*)(g_err_str[7]) | |
324 | +#define ERR_DATA_NF (char*)(g_err_str[8]) | |
325 | +#define ERR_UNKNOWN (char*)(g_err_str[9]) | |
326 | +#define ERR_MUSIC (char*)(g_err_str[10]) | |
327 | +#define ERR_MULTIPLE_LABEL (char*)(g_err_str[11]) | |
328 | +#define ERR_BREAK (char*)(g_err_str[12]) | |
329 | +#define ERR_UNEXP_NEXT (char*)(g_err_str[13]) | |
330 | +#define ERR_NO_BLOCK (char*)(g_err_str[14]) | |
331 | +#define ERR_GOSUB_ASH (char*)(g_err_str[15]) | |
332 | +#define ERR_INVALID_BREAK (char*)(g_err_str[16]) | |
333 | +#define ERR_INVALID_ELSEIF (char*)(g_err_str[17]) | |
334 | +#define ERR_INVALID_PARAM (char*)(g_err_str[18]) | |
335 | +#define ERR_FILE (char*)(g_err_str[19]) | |
336 | +#define ERR_INVALID_VAR_NAME (char*)(g_err_str[20]) | |
337 | +#define ERR_WAVE (char*)(g_err_str[21]) | |
338 | + | |
339 | +/* comple data type numbers */ | |
340 | +#define CMPDATA_RESERVED 0 | |
341 | +#define CMPDATA_USEVAR 1 | |
342 | + | |
343 | +/* Macros */ | |
344 | + | |
345 | +// Skip blanc(s) in source code | |
346 | +#define next_position() while(g_source[g_srcpos]==' ') {g_srcpos++;} | |
347 | + | |
348 | +// Check if object area is not full. | |
349 | +#define check_obj_space(x) if (g_objmax<g_object+g_objpos+(x)) return ERR_NE_BINARY | |
350 | + | |
351 | +// Returns priority of operator | |
352 | +#define priority(x) (int)g_priority[(int)(x)] | |
353 | + | |
354 | +// Insert code for calling library | |
355 | +//02E0F809 jalr ra,s7 | |
356 | +//24070000 addiu a3,zero,0000 | |
357 | +#define call_lib_code(x) \ | |
358 | + check_obj_space(2);\ | |
359 | + g_object[g_objpos++]=0x02E0F809;\ | |
360 | + g_object[g_objpos++]=0x24070000|((x)&0x0000FFFF) | |
361 | + | |
362 | +// Division macro for unsigned long | |
363 | +// Valid for 31 bits for all cases and 32 bits for some cases | |
364 | +#define div32(x,y,z) ((((unsigned long long)((unsigned long)(x)))*((unsigned long long)((unsigned long)(y))))>>(z)) | |
365 | + | |
366 | +// Divide by 9 (valid for 32 bits) | |
367 | +#define div9_32(x) div32(x,0xe38e38e4,35) | |
368 | +#define rem9_32(x) ((x)-9*div9_32(x)) | |
369 | + | |
370 | +// Divide by 10 (valid for 32 bits) | |
371 | +#define div10_32(x) div32(x,0xcccccccd,35) | |
372 | +#define rem10_32(x) ((x)-10*div10_32(x)) | |
373 | + | |
374 | +// Divide by 36 (valid for 32 bits) | |
375 | +#define div36_32(x) div32(x,0xe38e38e4,37) | |
376 | +#define rem36_32(x) (x-36*div36_32(x)) |
@@ -0,0 +1,588 @@ | ||
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 | + char* err; | |
13 | + next_position(); | |
14 | + if (g_source[g_srcpos]==')') { | |
15 | + check_obj_space(1); | |
16 | + g_object[g_objpos++]=0x34020003; //ori v0,zero,0x03 | |
17 | + } else { | |
18 | + err=get_value(); | |
19 | + if (err) return err; | |
20 | + } | |
21 | + call_lib_code(LIB_MUSICFUNC); | |
22 | + return 0; | |
23 | +} | |
24 | + | |
25 | +char* read_function(){ | |
26 | + call_lib_code(LIB_READ); | |
27 | + return 0; | |
28 | +} | |
29 | + | |
30 | +char* cread_function(){ | |
31 | + call_lib_code(LIB_CREAD); | |
32 | + return 0; | |
33 | +} | |
34 | + | |
35 | +char* gosub_function(){ | |
36 | + // Check if garbage collection has been done. | |
37 | + // This check is required because the used temporary area would be changed | |
38 | + // in sub routine. | |
39 | + if (g_temp_area_used) return ERR_GOSUB_ASH; | |
40 | + return gosub_statement(); | |
41 | +} | |
42 | +char* strncmp_function(){ | |
43 | + char* err; | |
44 | + err=get_string(); | |
45 | + if (err) return err; | |
46 | + check_obj_space(2); | |
47 | + g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
48 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
49 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
50 | + g_srcpos++; | |
51 | + err=get_string(); | |
52 | + if (err) return err; | |
53 | + check_obj_space(1); | |
54 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
55 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
56 | + g_srcpos++; | |
57 | + err=get_value(); | |
58 | + if (err) return err; | |
59 | + call_lib_code(LIB_STRNCMP); | |
60 | + check_obj_space(1); | |
61 | + g_object[g_objpos++]=0x27BD0008; // addiu sp,sp,8 | |
62 | + return 0; | |
63 | +} | |
64 | +char* len_function(){ | |
65 | + char* err; | |
66 | + err=get_string(); | |
67 | + if (err) return err; | |
68 | + check_obj_space(5); | |
69 | + g_object[g_objpos++]=0x2443FFFF; // addiu v1,v0,-1 | |
70 | + // loop: | |
71 | + g_object[g_objpos++]=0x80640001; // lb a0,1(v1) | |
72 | + g_object[g_objpos++]=0x1480FFFE; // bne a0,zero,loop | |
73 | + g_object[g_objpos++]=0x24630001; // addiu v1,v1,1 | |
74 | + g_object[g_objpos++]=0x00621023; // subu v0,v1,v0 | |
75 | + return 0; | |
76 | +} | |
77 | + | |
78 | +char* asc_function(){ | |
79 | + char* err; | |
80 | + err=get_string(); | |
81 | + if (err) return err; | |
82 | + check_obj_space(1); | |
83 | + g_object[g_objpos++]=0x90420000; // lbu v0,0(v0) | |
84 | + return 0; | |
85 | +} | |
86 | + | |
87 | +char* val_function(){ | |
88 | + char* err; | |
89 | + err=get_string(); | |
90 | + if (err) return err; | |
91 | + call_lib_code(LIB_VAL); | |
92 | + return 0; | |
93 | +} | |
94 | + | |
95 | +char* peek_function(){ | |
96 | + char* err; | |
97 | + err=get_value(); | |
98 | + if (err) return err; | |
99 | + check_obj_space(1); | |
100 | + g_object[g_objpos++]=0x90420000; // lbu v0,0(v0) | |
101 | + return 0; | |
102 | +} | |
103 | + | |
104 | +char* sgn_function(){ | |
105 | + char* err; | |
106 | + err=get_value(); | |
107 | + if (err) return err; | |
108 | + check_obj_space(5); | |
109 | + g_object[g_objpos++]=0x10400004; // beq v0,zero,end | |
110 | + g_object[g_objpos++]=0x24030001; // addiu v1,zero,1 | |
111 | + g_object[g_objpos++]=0x1C400002; // bgtz v0,end | |
112 | + g_object[g_objpos++]=0x00601021; // addu v0,v1,zero | |
113 | + g_object[g_objpos++]=0x00031023; // subu v0,zero,v1 | |
114 | + // end: | |
115 | + return 0; | |
116 | +} | |
117 | + | |
118 | +char* abs_function(){ | |
119 | + char* err; | |
120 | + err=get_value(); | |
121 | + if (err) return err; | |
122 | + check_obj_space(3); | |
123 | + g_object[g_objpos++]=0x00021FC3; //sra v1,v0,0x1f | |
124 | + g_object[g_objpos++]=0x00621026; //xor v0,v1,v0 | |
125 | + g_object[g_objpos++]=0x00431023; //subu v0,v0,v1 | |
126 | + return 0; | |
127 | +} | |
128 | + | |
129 | +char* not_function(){ | |
130 | + char* err; | |
131 | + err=get_value(); | |
132 | + if (err) return err; | |
133 | + check_obj_space(1); | |
134 | + g_object[g_objpos++]=0x2C420001; //sltiu v0,v0,1 | |
135 | + return 0; | |
136 | +} | |
137 | + | |
138 | +char* rnd_function(){ | |
139 | + call_lib_code(LIB_RND); | |
140 | + return 0; | |
141 | +} | |
142 | + | |
143 | + | |
144 | +char* chr_function(void){ | |
145 | + char* err; | |
146 | + err=get_value(); | |
147 | + if (err) return err; | |
148 | + call_lib_code(LIB_CHR); | |
149 | + return 0; | |
150 | +} | |
151 | +char* hex_function(void){ | |
152 | + char* err; | |
153 | + err=get_value(); | |
154 | + if (err) return err; | |
155 | + if (g_source[g_srcpos]==',') { | |
156 | + // Second argument found. | |
157 | + // Get is as $a0. | |
158 | + g_srcpos++; | |
159 | + check_obj_space(2); | |
160 | + g_object[g_objpos++]=0x27BDFFFC; //addiu sp,sp,-4 | |
161 | + g_object[g_objpos++]=0xAFA20004; //sw v0,4(sp) | |
162 | + err=get_value(); | |
163 | + if (err) return err; | |
164 | + check_obj_space(3); | |
165 | + g_object[g_objpos++]=0x00022021; //a0,zero,v0 | |
166 | + g_object[g_objpos++]=0x8FA20004; //lw v0,4(sp) | |
167 | + g_object[g_objpos++]=0x27BD0004; //addiu sp,sp,4 | |
168 | + } else { | |
169 | + // Second argument not found. | |
170 | + // Set $a0 to 0. | |
171 | + check_obj_space(1); | |
172 | + g_object[g_objpos++]=0x24040000; //addiu a0,zero,0 | |
173 | + } | |
174 | + call_lib_code(LIB_HEX); | |
175 | + return 0; | |
176 | +} | |
177 | + | |
178 | +char* dec_function(void){ | |
179 | + char* err; | |
180 | + err=get_value(); | |
181 | + if (err) return err; | |
182 | + call_lib_code(LIB_DEC); | |
183 | + return 0; | |
184 | +} | |
185 | + | |
186 | +char* keys_function(void){ | |
187 | + char* err; | |
188 | + next_position(); | |
189 | + if (g_source[g_srcpos]==')') { | |
190 | + check_obj_space(1); | |
191 | + g_object[g_objpos++]=0x3402003F; //ori v0,zero,0x3f | |
192 | + } else { | |
193 | + err=get_value(); | |
194 | + if (err) return err; | |
195 | + } | |
196 | + call_lib_code(LIB_KEYS); | |
197 | + return 0; | |
198 | +} | |
199 | + | |
200 | +char* tvram_function(void){ | |
201 | + char* err; | |
202 | + int i; | |
203 | + next_position(); | |
204 | + if (g_source[g_srcpos]==')') { | |
205 | + i=(int)(&TVRAM[0]); | |
206 | + i-=g_gp; | |
207 | + check_obj_space(1); | |
208 | + g_object[g_objpos++]=0x27820000|(i&0x0000FFFF); // addiu v0,gp,xxxx | |
209 | + } else { | |
210 | + err=get_value(); | |
211 | + if (err) return err; | |
212 | + i=(int)(&TVRAM[0]); | |
213 | + i-=g_gp; | |
214 | + check_obj_space(3); | |
215 | + g_object[g_objpos++]=0x27830000|(i&0x0000FFFF); // addiu v1,gp,xxxx | |
216 | + g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
217 | + g_object[g_objpos++]=0x90620000; // lbu v0,0(v1) | |
218 | + } | |
219 | + return 0; | |
220 | +} | |
221 | + | |
222 | +char* drawcount_function(void){ | |
223 | + call_lib_code(LIB_DRAWCOUNT); | |
224 | + return 0; | |
225 | +} | |
226 | + | |
227 | +char* input_function(void){ | |
228 | + call_lib_code(LIB_INPUT); | |
229 | + return 0; | |
230 | +} | |
231 | + | |
232 | +char* inkey_function(void){ | |
233 | + char* err; | |
234 | + next_position(); | |
235 | + if (g_source[g_srcpos]==')') { | |
236 | + check_obj_space(1); | |
237 | + g_object[g_objpos++]=0x34020000; //ori v0,zero,0x00 | |
238 | + } else { | |
239 | + err=get_value(); | |
240 | + if (err) return err; | |
241 | + } | |
242 | + call_lib_code(LIB_INKEY); | |
243 | + return 0; | |
244 | +} | |
245 | + | |
246 | +char* args_function(void){ | |
247 | + char* err; | |
248 | + int i; | |
249 | + err=get_value(); | |
250 | + if (err) return err; | |
251 | + i=g_object[g_objpos-1]; | |
252 | + if ((i>>16)==0x3402) { | |
253 | + // Previous object is "ori v0,zero,xxxx". | |
254 | + i&=0xffff; | |
255 | + i=(i+1)<<2; | |
256 | + g_object[g_objpos-1]=0x8EA20000|i; // lw v0,xx(s5) | |
257 | + } else { | |
258 | + check_obj_space(3); | |
259 | + g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
260 | + g_object[g_objpos++]=0x02A21021; // addu v0,s5,v0 | |
261 | + g_object[g_objpos++]=0x8C420004; // lw v0,4(v0) | |
262 | + } | |
263 | + return 0; | |
264 | +} | |
265 | + | |
266 | +char* system_function(void){ | |
267 | + char* err; | |
268 | + err=get_value(); | |
269 | + if (err) return err; | |
270 | + g_object[g_objpos++]=0x00402021; // addu a0,v0,zero | |
271 | + call_lib_code(LIB_SYSTEM); | |
272 | + return 0; | |
273 | +} | |
274 | + | |
275 | +char* sprintf_function(void){ | |
276 | + char* err; | |
277 | + err=get_string(); | |
278 | + if (err) return err; | |
279 | + next_position(); | |
280 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
281 | + g_srcpos++; | |
282 | + check_obj_space(2); | |
283 | + g_object[g_objpos++]=0x27BDFFFC; //addiu sp,sp,-4 | |
284 | + g_object[g_objpos++]=0xAFA20004; //sw v0,4(sp) | |
285 | + err=get_float(); | |
286 | + if (err) return err; | |
287 | + check_obj_space(3); | |
288 | + g_object[g_objpos++]=0x00022021; //addu a0,zero,v0 | |
289 | + g_object[g_objpos++]=0x8FA20004; //lw v0,4(sp) | |
290 | + g_object[g_objpos++]=0x27BD0004; //addiu sp,sp,4 | |
291 | + call_lib_code(LIB_SPRINTF); | |
292 | + return 0; | |
293 | +} | |
294 | + | |
295 | +char* floatstr_function(void){ | |
296 | + char* err; | |
297 | + err=get_float(); | |
298 | + if (err) return err; | |
299 | + check_obj_space(2); | |
300 | + g_object[g_objpos++]=0x00022021; //addu a0,zero,v0 | |
301 | + g_object[g_objpos++]=0x34020000; //ori v0,zero,0x0000 | |
302 | + call_lib_code(LIB_SPRINTF); | |
303 | + return 0; | |
304 | +} | |
305 | + | |
306 | +char* floatsharp_function(void){ | |
307 | + char* err; | |
308 | + err=get_value(); | |
309 | + if (err) return err; | |
310 | + call_lib_code(LIB_FLOATFUNCS | FUNC_FLOAT); | |
311 | + return 0; | |
312 | +} | |
313 | + | |
314 | +char* valsharp_function(void){ | |
315 | + char* err; | |
316 | + err=get_string(); | |
317 | + if (err) return err; | |
318 | + call_lib_code(LIB_FLOATFUNCS | FUNC_VALSHARP); | |
319 | + return 0; | |
320 | +} | |
321 | + | |
322 | +char* int_function(void){ | |
323 | + char* err; | |
324 | + err=get_float(); | |
325 | + if (err) return err; | |
326 | + call_lib_code(LIB_FLOATFUNCS | FUNC_INT); | |
327 | + return 0; | |
328 | +} | |
329 | + | |
330 | +char* fseek_function(){ | |
331 | + call_lib_code(LIB_FILE | FUNC_FTELL); | |
332 | + return 0; | |
333 | +} | |
334 | + | |
335 | +char* flen_function(){ | |
336 | + call_lib_code(LIB_FILE | FUNC_FLEN); | |
337 | + return 0; | |
338 | +} | |
339 | + | |
340 | +char* fgetc_function(){ | |
341 | + call_lib_code(LIB_FILE | FUNC_FGETC); | |
342 | + return 0; | |
343 | +} | |
344 | + | |
345 | +char* finput_function(){ | |
346 | + char* err; | |
347 | + next_position(); | |
348 | + if (g_source[g_srcpos]!=')') { | |
349 | + err=get_value(); | |
350 | + if (err) return err; | |
351 | + } else { | |
352 | + // Parameter will be zero if not defined | |
353 | + check_obj_space(1); | |
354 | + g_object[g_objpos++]=0x34020000; // ori v0,zero,0 | |
355 | + } | |
356 | + call_lib_code(LIB_FILE | FUNC_FINPUT); | |
357 | + return 0; | |
358 | +} | |
359 | + | |
360 | +char* feof_function(){ | |
361 | + call_lib_code(LIB_FILE | FUNC_FEOF); | |
362 | + return 0; | |
363 | +} | |
364 | + | |
365 | +char* playwave_function(){ | |
366 | + char* err; | |
367 | + next_position(); | |
368 | + if (g_source[g_srcpos]!=')') { | |
369 | + // Get param | |
370 | + err=get_value(); | |
371 | + if (err) return err; | |
372 | + } else { | |
373 | + // If parameter is omitted, use 0. | |
374 | + check_obj_space(1); | |
375 | + g_object[g_objpos++]=0x24020000; // addiu v0,zero,0 | |
376 | + } | |
377 | + call_lib_code(LIB_PLAYWAVEFUNC); | |
378 | + return 0; | |
379 | +} | |
380 | + | |
381 | +char* float_constant(float val){ | |
382 | + volatile int i; | |
383 | + ((float*)(&i))[0]=val; | |
384 | + if (i&0xFFFF0000) { | |
385 | + // 32 bit | |
386 | + check_obj_space(2); | |
387 | + g_object[g_objpos++]=0x3C020000|((i>>16)&0x0000FFFF); // lui v0,xxxx | |
388 | + g_object[g_objpos++]=0x34420000|(i&0x0000FFFF); // ori v0,v0,xxxx | |
389 | + } else { | |
390 | + // 16 bit | |
391 | + check_obj_space(1); | |
392 | + g_object[g_objpos++]=0x34020000|(i&0x0000FFFF); // ori v0,zero,xxxx | |
393 | + } | |
394 | + return 0; | |
395 | +} | |
396 | + | |
397 | +char* float_1param_function(enum functions func){ | |
398 | + char* err; | |
399 | + err=get_float(); | |
400 | + if (err) return err; | |
401 | + call_lib_code(LIB_FLOATFUNCS | func); | |
402 | + return 0; | |
403 | +} | |
404 | + | |
405 | +char* float_2param_function(enum functions func){ | |
406 | + char* err; | |
407 | + err=get_float(); | |
408 | + if (err) return err; | |
409 | + next_position(); | |
410 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
411 | + g_srcpos++; | |
412 | + check_obj_space(2); | |
413 | + g_object[g_objpos++]=0x27BDFFFC; //addiu sp,sp,-4 | |
414 | + g_object[g_objpos++]=0xAFA20004; //sw v0,4(sp) | |
415 | + err=get_float(); | |
416 | + if (err) return err; | |
417 | + check_obj_space(3); | |
418 | + g_object[g_objpos++]=0x00022021; //addu a0,zero,v0 | |
419 | + g_object[g_objpos++]=0x8FA20004; //lw v0,4(sp) | |
420 | + g_object[g_objpos++]=0x27BD0004; //addiu sp,sp,4 | |
421 | + call_lib_code(LIB_FLOATFUNCS | func); | |
422 | + return 0; | |
423 | +} | |
424 | + | |
425 | +char* float_function(void){ | |
426 | + char* err; | |
427 | + if (nextCodeIs("FLOAT#(")) { | |
428 | + err=floatsharp_function(); | |
429 | + } else if (nextCodeIs("VAL#(")) { | |
430 | + err=valsharp_function(); | |
431 | + } else if (nextCodeIs("SIN#(")) { | |
432 | + err=float_1param_function(FUNC_SIN); | |
433 | + } else if (nextCodeIs("COS#(")) { | |
434 | + err=float_1param_function(FUNC_COS); | |
435 | + } else if (nextCodeIs("TAN#(")) { | |
436 | + err=float_1param_function(FUNC_TAN); | |
437 | + } else if (nextCodeIs("ASIN#(")) { | |
438 | + err=float_1param_function(FUNC_ASIN); | |
439 | + } else if (nextCodeIs("ACOS#(")) { | |
440 | + err=float_1param_function(FUNC_ACOS); | |
441 | + } else if (nextCodeIs("ATAN#(")) { | |
442 | + err=float_1param_function(FUNC_ATAN); | |
443 | + } else if (nextCodeIs("ATAN2#(")) { | |
444 | + err=float_2param_function(FUNC_ATAN2); | |
445 | + } else if (nextCodeIs("SINH#(")) { | |
446 | + err=float_1param_function(FUNC_SINH); | |
447 | + } else if (nextCodeIs("COSH#(")) { | |
448 | + err=float_1param_function(FUNC_COSH); | |
449 | + } else if (nextCodeIs("TANH#(")) { | |
450 | + err=float_1param_function(FUNC_TANH); | |
451 | + } else if (nextCodeIs("EXP#(")) { | |
452 | + err=float_1param_function(FUNC_EXP); | |
453 | + } else if (nextCodeIs("LOG#(")) { | |
454 | + err=float_1param_function(FUNC_LOG); | |
455 | + } else if (nextCodeIs("LOG10#(")) { | |
456 | + err=float_1param_function(FUNC_LOG10); | |
457 | + } else if (nextCodeIs("POW#(")) { | |
458 | + err=float_2param_function(FUNC_POW); | |
459 | + } else if (nextCodeIs("SQRT#(")) { | |
460 | + err=float_1param_function(FUNC_SQRT); | |
461 | + } else if (nextCodeIs("CEIL#(")) { | |
462 | + err=float_1param_function(FUNC_CEIL); | |
463 | + } else if (nextCodeIs("FLOOR#(")) { | |
464 | + err=float_1param_function(FUNC_FLOOR); | |
465 | + } else if (nextCodeIs("FABS#(")) { | |
466 | + err=float_1param_function(FUNC_FABS); | |
467 | + } else if (nextCodeIs("MODF#(")) { | |
468 | + err=float_1param_function(FUNC_MODF); | |
469 | + } else if (nextCodeIs("FMOD#(")) { | |
470 | + err=float_2param_function(FUNC_FMOD); | |
471 | + } else if (nextCodeIs("GOSUB#(")) { | |
472 | + err=gosub_function(); | |
473 | + } else if (nextCodeIs("ARGS#(")) { | |
474 | + err=args_function(); | |
475 | + } else if (nextCodeIs("PI#")) { | |
476 | + return float_constant(3.141593); | |
477 | + } else { | |
478 | + return ERR_SYNTAX; | |
479 | + } | |
480 | + if (err) return err; | |
481 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
482 | + g_srcpos++; | |
483 | + return 0; | |
484 | +} | |
485 | + | |
486 | +static const void* str_func_list[]={ | |
487 | + "CHR$(",chr_function, | |
488 | + "HEX$(",hex_function, | |
489 | + "DEC$(",dec_function, | |
490 | + "INPUT$(",input_function, | |
491 | + "GOSUB$(",gosub_function, | |
492 | + "ARGS$(",args_function, | |
493 | + "READ$(",read_function, | |
494 | + "SPRINTF$(",sprintf_function, | |
495 | + "FLOAT$(",floatstr_function, | |
496 | + "SYSTEM$(",system_function, | |
497 | + "FINPUT$(",finput_function, | |
498 | + // Additional functions follow | |
499 | + ADDITIONAL_STR_FUNCTIONS | |
500 | +}; | |
501 | + | |
502 | +char* str_function(void){ | |
503 | + char* err; | |
504 | + int i; | |
505 | + char* (*f)(); | |
506 | + // Seek the function | |
507 | + for (i=0;i<sizeof(str_func_list)/sizeof(str_func_list[0]);i+=2){ | |
508 | + if (nextCodeIs((char*)str_func_list[i])) break; | |
509 | + } | |
510 | + if (i<sizeof(str_func_list)/sizeof(str_func_list[0])) { | |
511 | + // Function found. Call it. | |
512 | + f=str_func_list[i+1]; | |
513 | + err=f(); | |
514 | + } else { | |
515 | + return ERR_SYNTAX; | |
516 | + } | |
517 | + if (err) return err; | |
518 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
519 | + g_srcpos++; | |
520 | + return 0; | |
521 | +} | |
522 | + | |
523 | +// Aliases follow | |
524 | + | |
525 | +char* gcolor_function(){ | |
526 | + return graphic_statement(FUNC_GCOLOR); | |
527 | +} | |
528 | + | |
529 | +char* fopen_function(){ | |
530 | + return fopen_statement_main(FUNC_FOPEN); | |
531 | +} | |
532 | + | |
533 | +static const void* int_func_list[]={ | |
534 | + "NOT(",not_function, | |
535 | + "DRAWCOUNT(",drawcount_function, | |
536 | + "MUSIC(",music_function, | |
537 | + "TVRAM(",tvram_function, | |
538 | + "KEYS(",keys_function, | |
539 | + "READ(",read_function, | |
540 | + "CREAD(",cread_function, | |
541 | + "GOSUB(",gosub_function, | |
542 | + "STRNCMP(",strncmp_function, | |
543 | + "PEEK(",peek_function, | |
544 | + "LEN(",len_function, | |
545 | + "ASC(",asc_function, | |
546 | + "SGN(",sgn_function, | |
547 | + "ABS(",abs_function, | |
548 | + "RND(",rnd_function, | |
549 | + "VAL(",val_function, | |
550 | + "INKEY(",inkey_function, | |
551 | + "ARGS(",args_function, | |
552 | + "SYSTEM(",system_function, | |
553 | + "INT(",int_function, | |
554 | + "GCOLOR(",gcolor_function, | |
555 | + "FOPEN(",fopen_function, | |
556 | + "FSEEK(",fseek_function, | |
557 | + "FLEN(",flen_function, | |
558 | + "FGET(",fget_statement, | |
559 | + "FPUT(",fput_statement, | |
560 | + "FGETC(",fgetc_function, | |
561 | + "FPUTC(",fputc_statement, | |
562 | + "FREMOVE(",fremove_statement, | |
563 | + "FEOF(",feof_function, | |
564 | + "PLAYWAVE(",playwave_function, | |
565 | + // Additional functions follow | |
566 | + ADDITIONAL_INT_FUNCTIONS | |
567 | +}; | |
568 | + | |
569 | +char* function(void){ | |
570 | + char* err; | |
571 | + int i; | |
572 | + char* (*f)(); | |
573 | + // Seek the function | |
574 | + for (i=0;i<sizeof(int_func_list)/sizeof(int_func_list[0]);i+=2){ | |
575 | + if (nextCodeIs((char*)int_func_list[i])) break; | |
576 | + } | |
577 | + if (i<sizeof(int_func_list)/sizeof(int_func_list[0])) { | |
578 | + // Function found. Call it. | |
579 | + f=int_func_list[i+1]; | |
580 | + err=f(); | |
581 | + } else { | |
582 | + return ERR_SYNTAX; | |
583 | + } | |
584 | + if (err) return err; | |
585 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
586 | + g_srcpos++; | |
587 | + return 0; | |
588 | +} |
@@ -0,0 +1,1085 @@ | ||
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 | + continue; | |
68 | + } | |
69 | + // DATA region found. | |
70 | + in_data=(code&0x0000FFFF)-1; | |
71 | + pos=i+2; | |
72 | + skip=code2&0x03; | |
73 | + break; | |
74 | + } | |
75 | + if (g_objpos<=i) { | |
76 | + err_data_not_found(); | |
77 | + return 0; | |
78 | + } | |
79 | + } | |
80 | + if (label) { | |
81 | + // RESTORE function. Return pointer. | |
82 | + return ((int)&g_object[pos])+skip; | |
83 | + } else { | |
84 | + switch(mode){ | |
85 | + case 0: | |
86 | + // READ() function | |
87 | + in_data--; | |
88 | + return g_object[pos++]; | |
89 | + case 1: | |
90 | + default: | |
91 | + // CREAD() function | |
92 | + i=g_object[pos]; | |
93 | + i>>=skip*8; | |
94 | + i&=0xff; | |
95 | + if ((++skip)==4) { | |
96 | + skip=0; | |
97 | + in_data--; | |
98 | + pos++; | |
99 | + } | |
100 | + return i; | |
101 | + } | |
102 | + } | |
103 | +} | |
104 | + | |
105 | +void reset_dataread(){ | |
106 | + lib_read(2,1); | |
107 | +} | |
108 | + | |
109 | +char* lib_midstr(int var_num, int pos, int len){ | |
110 | + int i; | |
111 | + char* str; | |
112 | + char* ret; | |
113 | + if (0<=pos) { | |
114 | + // String after "pos" position. | |
115 | + str=(char*)(g_var_mem[var_num]+pos); | |
116 | + } else { | |
117 | + // String right "pos" characters. | |
118 | + // Determine length | |
119 | + str=(char*)g_var_mem[var_num]; | |
120 | + for(i=0;str[i];i++); | |
121 | + if (0<=(i+pos)) { | |
122 | + str=(char*)(g_var_mem[var_num]+i+pos); | |
123 | + } | |
124 | + } | |
125 | + if (len<0) { | |
126 | + // Length is not specified. | |
127 | + // Return the string to the end. | |
128 | + return str; | |
129 | + } | |
130 | + // Length is specified. | |
131 | + // Construct temporary string containing specified number of characters. | |
132 | + ret=alloc_memory((len+1+3)/4,-1); | |
133 | + // Copy string. | |
134 | + for(i=0;(ret[i]=str[i])&&(i<len);i++); | |
135 | + ret[len]=0x00; | |
136 | + return ret; | |
137 | +} | |
138 | + | |
139 | +void lib_clear(void){ | |
140 | + int i; | |
141 | + // All variables (including temporary and permanent ones) will be integer 0 | |
142 | + for(i=0;i<ALLOC_BLOCK_NUM;i++){ | |
143 | + g_var_mem[i]=0; | |
144 | + } | |
145 | + // Clear memory allocation area | |
146 | + for(i=0;i<ALLOC_BLOCK_NUM;i++){ | |
147 | + g_var_size[i]=0; | |
148 | + } | |
149 | + // Cancel PCG | |
150 | + stopPCG(); | |
151 | + g_pcg_font=0; | |
152 | + // Stop using graphic | |
153 | + g_use_graphic=1; // Force set_graphmode(0) (see usegraphic() function) | |
154 | + usegraphic(0); | |
155 | +} | |
156 | + | |
157 | +void lib_let_str(char* str, int var_num){ | |
158 | + int begin,end,size; | |
159 | + // Save pointer | |
160 | + g_var_mem[var_num]=(int)str; | |
161 | + // Determine size | |
162 | + for(size=0;str[size];size++); | |
163 | + // Check if str is in heap area. | |
164 | + begin=(int)str; | |
165 | + end=(int)(&str[size]); | |
166 | + if (begin<(int)(&g_heap_mem[0]) || (int)(&g_heap_mem[g_max_mem])<=end) { | |
167 | + // String is not within allcated block | |
168 | + return; | |
169 | + } | |
170 | + // Str is in heap area. Calculate values stored in heap data dimension | |
171 | + begin-=(int)(&g_heap_mem[0]); | |
172 | + begin>>=2; | |
173 | + end-=(int)(&g_heap_mem[0]); | |
174 | + end>>=2; | |
175 | + size=end-begin+1; | |
176 | + g_var_pointer[var_num]=begin; | |
177 | + g_var_size[var_num]=size; | |
178 | +} | |
179 | + | |
180 | +int lib_rnd(){ | |
181 | + int y; | |
182 | + y=g_rnd_seed; | |
183 | + y = y ^ (y << 13); | |
184 | + y = y ^ (y >> 17); | |
185 | + y = y ^ (y << 5); | |
186 | + g_rnd_seed=y; | |
187 | + return y&0x7fff; | |
188 | +} | |
189 | + | |
190 | +char* lib_chr(int num){ | |
191 | + char* str; | |
192 | + str=alloc_memory(1,-1); | |
193 | + str[0]=num&0x000000FF; | |
194 | + str[1]=0x00; | |
195 | + return str; | |
196 | +} | |
197 | + | |
198 | +char* lib_dec(int num){ | |
199 | + char* str; | |
200 | + int i,j,minus; | |
201 | + char b[12]; | |
202 | + b[11]=0x00; | |
203 | + if (num<0) { | |
204 | + minus=1; | |
205 | + num=0-num; | |
206 | + } else { | |
207 | + minus=0; | |
208 | + } | |
209 | + for (i=10;0<i;i--) { | |
210 | + if (num==0 && i<10) break; | |
211 | + b[i]='0'+rem10_32(num); | |
212 | + num=div10_32(num); | |
213 | + } | |
214 | + if (minus) { | |
215 | + b[i]='-'; | |
216 | + } else { | |
217 | + i++; | |
218 | + } | |
219 | + str=alloc_memory(3,-1); | |
220 | + for(j=0;str[j]=b[i++];j++); | |
221 | + return str; | |
222 | +} | |
223 | + | |
224 | +char* lib_hex(int num, int width){ | |
225 | + char* str; | |
226 | + int i,j,minus; | |
227 | + char b[8]; | |
228 | + str=alloc_memory(3,-1); | |
229 | + for(i=0;i<8;i++){ | |
230 | + b[i]="0123456789ABCDEF"[(num>>(i<<2))&0x0F]; | |
231 | + } | |
232 | + // Width must be between 0 and 8; | |
233 | + if (width<0||8<width) width=8; | |
234 | + if (width==0) { | |
235 | + // Width not asigned. Use minimum width. | |
236 | + for(i=7;0<i;i--){ | |
237 | + if ('0'<b[i]) break; | |
238 | + } | |
239 | + } else { | |
240 | + // Constant width | |
241 | + i=width-1; | |
242 | + } | |
243 | + // Copy string to allocated block. | |
244 | + for(j=0;0<=i;i--){ | |
245 | + str[j++]=b[i]; | |
246 | + } | |
247 | + str[j]=0x00; | |
248 | + return str; | |
249 | +} | |
250 | + | |
251 | +char* lib_connect_string(char* str1, char* str2){ | |
252 | + int i,j; | |
253 | + char b; | |
254 | + char* result; | |
255 | + // Determine total length | |
256 | + for(i=0;str1[i];i++); | |
257 | + for(j=0;str2[j];j++); | |
258 | + // Allocate a block for new string | |
259 | + result=alloc_memory((i+j+1+3)/4,-1); | |
260 | + // Create connected strings | |
261 | + for(i=0;b=str1[i];i++) result[i]=b; | |
262 | + for(j=0;b=str2[j];j++) result[i+j]=b; | |
263 | + result[i+j]=0x00; | |
264 | + free_temp_str(str1); | |
265 | + free_temp_str(str2); | |
266 | + return result; | |
267 | +} | |
268 | + | |
269 | +void lib_string(int mode){ | |
270 | + int i; | |
271 | + switch(mode){ | |
272 | + case 0: | |
273 | + // CR | |
274 | + printchar('\n'); | |
275 | + return; | |
276 | + case 1: | |
277 | + // , | |
278 | + printcomma(); | |
279 | + return; | |
280 | + default: | |
281 | + return; | |
282 | + } | |
283 | +} | |
284 | + | |
285 | +void* lib_label(unsigned int label){ | |
286 | + // This routine is used to jump to address dynamically determined | |
287 | + // in the code; for example: "GOTO 100+I" | |
288 | + unsigned int i,code,search; | |
289 | + void* ret; | |
290 | + if (label&0xFFFF0000) { | |
291 | + // Label is not supported. | |
292 | + // Line number must bs less than 65536. | |
293 | + err_label_not_found(); | |
294 | + } else { | |
295 | + // Line number | |
296 | + ret=search_label(label); | |
297 | + if (ret) return ret; | |
298 | + // Line number not found. | |
299 | + err_label_not_found(); | |
300 | + } | |
301 | +} | |
302 | + | |
303 | +int lib_keys(int mask){ | |
304 | + int keys; | |
305 | + keys=readbuttons(); | |
306 | + keys= | |
307 | + ((keys&KEYUP)? 0:1)| | |
308 | + ((keys&KEYDOWN)? 0:2)| | |
309 | + ((keys&KEYLEFT)? 0:4)| | |
310 | + ((keys&KEYRIGHT)? 0:8)| | |
311 | + ((keys&KEYSTART)? 0:16)| | |
312 | + ((keys&KEYFIRE)? 0:32); | |
313 | + return mask&keys; | |
314 | +} | |
315 | + | |
316 | +int lib_val(char* str){ | |
317 | + int i; | |
318 | + int val=0; | |
319 | + int sign=1; | |
320 | + char b; | |
321 | + // Skip blanc | |
322 | + for(i=0;0<=str[i] && str[i]<0x21;i++); | |
323 | + // Skip '+' | |
324 | + if (str[i]=='+') i++; | |
325 | + // Check '-' | |
326 | + if (str[i]=='-') { | |
327 | + sign=-1; | |
328 | + i++; | |
329 | + } | |
330 | + // Check '0x' or '$' | |
331 | + if (str[i]=='$' || str[i]=='0' && (str[i+1]=='x' || str[i+1]=='X')) { | |
332 | + // Hexadecimal | |
333 | + if (str[i++]=='0') i++; | |
334 | + while(1) { | |
335 | + b=str[i++]; | |
336 | + if ('0'<=b && b<='9') { | |
337 | + val<<=4; | |
338 | + val+=b-'0'; | |
339 | + } else if ('a'<=b && b<='f') { | |
340 | + val<<=4; | |
341 | + val+=b-'a'+10; | |
342 | + } else if ('A'<=b && b<='F') { | |
343 | + val<<=4; | |
344 | + val+=b-'A'+10; | |
345 | + } else { | |
346 | + break; | |
347 | + } | |
348 | + } | |
349 | + } else { | |
350 | + // Decimal | |
351 | + while(1) { | |
352 | + b=str[i++]; | |
353 | + if ('0'<=b && b<='9') { | |
354 | + val*=10; | |
355 | + val+=b-'0'; | |
356 | + } else { | |
357 | + break; | |
358 | + } | |
359 | + } | |
360 | + } | |
361 | + return val*sign; | |
362 | +} | |
363 | + | |
364 | +char* lib_input(){ | |
365 | + // Allocate memory for strings with 63 characters | |
366 | + char *str=calloc_memory((63+1)/4,-1); | |
367 | + // Enable PS/2 keyboard | |
368 | + if (!inPS2MODE()) { | |
369 | + ps2mode(); | |
370 | + ps2init(); | |
371 | + } | |
372 | + // Clear key buffer | |
373 | + do ps2readkey(); | |
374 | + while(vkey!=0); | |
375 | + // Get string as a line | |
376 | + lineinput(str,63); | |
377 | + check_break(); | |
378 | + return str; | |
379 | +} | |
380 | + | |
381 | +unsigned char lib_inkey(int key){ | |
382 | + int i; | |
383 | + // Enable PS/2 keyboard | |
384 | + if (!inPS2MODE()) { | |
385 | + ps2mode(); | |
386 | + ps2init(); | |
387 | + } | |
388 | + if (key) { | |
389 | + return ps2keystatus[key&0xff]; | |
390 | + } else { | |
391 | + for(i=0;i<256;i++){ | |
392 | + if (ps2keystatus[i]) return i; | |
393 | + } | |
394 | + return 0; | |
395 | + } | |
396 | +} | |
397 | + | |
398 | +void lib_usepcg(int mode){ | |
399 | + // Modes; 0: stop PCG, 1: use PCG, 2: reset PCG and use it | |
400 | + switch(mode){ | |
401 | + case 0: | |
402 | + // Stop PCG | |
403 | + stopPCG(); | |
404 | + break; | |
405 | + case 2: | |
406 | + // Reset PCG and use it | |
407 | + if (g_pcg_font) { | |
408 | + free_temp_str(g_pcg_font); | |
409 | + g_pcg_font=0; | |
410 | + } | |
411 | + // Continue to case 1: | |
412 | + case 1: | |
413 | + default: | |
414 | + // Use PCG | |
415 | + if (g_pcg_font) { | |
416 | + startPCG(g_pcg_font,0); | |
417 | + } else { | |
418 | + g_pcg_font=alloc_memory(256*8/4,ALLOC_PCG_BLOCK); | |
419 | + startPCG(g_pcg_font,1); | |
420 | + } | |
421 | + break; | |
422 | + } | |
423 | +} | |
424 | + | |
425 | +void lib_pcg(unsigned int ascii,unsigned int fontdata1,unsigned int fontdata2){ | |
426 | + unsigned int* pcg; | |
427 | + // If USEPCG has not yet executed, do now. | |
428 | + if (!g_pcg_font) lib_usepcg(1); | |
429 | + pcg=(unsigned int*)g_pcg_font; | |
430 | + // 0 <= ascii <= 0xff | |
431 | + ascii&=0xff; | |
432 | + // Update font data | |
433 | + ascii<<=1; | |
434 | + pcg[ascii]=(fontdata1>>24)|((fontdata1&0xff0000)>>8)|((fontdata1&0xff00)<<8)|(fontdata1<<24); | |
435 | + pcg[ascii+1]=(fontdata2>>24)|((fontdata2&0xff0000)>>8)|((fontdata2&0xff00)<<8)|(fontdata2<<24); | |
436 | +} | |
437 | + | |
438 | +void lib_usegraphic(int mode){ | |
439 | + usegraphic(mode); | |
440 | + // Move current point to (0,0) | |
441 | + g_prev_x=g_prev_y=0; | |
442 | +} | |
443 | +void lib_wait(int period){ | |
444 | + int i; | |
445 | + unsigned short dcount; | |
446 | + for(i=0;i<period;i++){ | |
447 | + dcount=drawcount; | |
448 | + while(dcount==drawcount){ | |
449 | + asm (WAIT); | |
450 | + check_break(); | |
451 | + } | |
452 | + } | |
453 | +} | |
454 | + | |
455 | +int lib_graphic(int v0,enum functions func){ | |
456 | + unsigned char b; | |
457 | + int x1=g_libparams[1]; | |
458 | + int y1=g_libparams[2]; | |
459 | + int x2=g_libparams[3]; | |
460 | + int y2=g_libparams[4]; | |
461 | + // Disable if graphic area is not defined. | |
462 | + if (!g_graphic_area) return; | |
463 | + // If C is omitted in parameters, use current color. | |
464 | + if (v0==-1) { | |
465 | + v0=g_gcolor; | |
466 | + } | |
467 | + // If X1 or Y1 is 0x80000000, use the previous values. | |
468 | + if (x1==0x80000000) x1=g_prev_x; | |
469 | + if (y1==0x80000000) y1=g_prev_y; | |
470 | + switch(func){ | |
471 | + case FUNC_POINT:// X1,Y1 | |
472 | + g_prev_x=x1; | |
473 | + g_prev_y=y1; | |
474 | + break; | |
475 | + case FUNC_PSET:// X1,Y1[,C] | |
476 | + g_pset(x1,y1,v0); | |
477 | + g_prev_x=x1; | |
478 | + g_prev_y=y1; | |
479 | + break; | |
480 | + case FUNC_LINE:// X1,Y1,X2,Y2[,C] | |
481 | + if (y1==y2) g_hline(x1,x2,y1,v0); | |
482 | + else g_gline(x1,y1,x2,y2,v0); | |
483 | + g_prev_x=x2; | |
484 | + g_prev_y=y2; | |
485 | + break; | |
486 | + case FUNC_BOXFILL:// X1,Y1,X2,Y2[,C] | |
487 | + g_boxfill(x1,y1,x2,y2,v0); | |
488 | + g_prev_x=x2; | |
489 | + g_prev_y=y2; | |
490 | + break; | |
491 | + case FUNC_CIRCLE:// X1,Y1,R[,C] | |
492 | + g_circle(x1,y1,x2,v0); | |
493 | + g_prev_x=x1; | |
494 | + g_prev_y=y1; | |
495 | + break; | |
496 | + case FUNC_CIRCLEFILL:// X1,Y1,R[,C] | |
497 | + g_circlefill(x1,y1,x2,v0); | |
498 | + g_prev_x=x1; | |
499 | + g_prev_y=y1; | |
500 | + break; | |
501 | + case FUNC_GPRINT:// X1,Y1,C,BC,S$ | |
502 | + g_printstr(x1,y1,x2,y2,(unsigned char*)v0); | |
503 | + // Move current X,Y according to the string | |
504 | + while(b=((unsigned char*)v0)[0]){ | |
505 | + v0++; | |
506 | + if (b==0x0d) { | |
507 | + x1=0; | |
508 | + y1+=8; | |
509 | + } else { | |
510 | + x1+=8; | |
511 | + } | |
512 | + } | |
513 | + g_prev_x=x1; | |
514 | + g_prev_y=y1; | |
515 | + break; | |
516 | + case FUNC_PUTBMP2:// X1,Y1,M,N,BMP(label) | |
517 | + // Search CDATA | |
518 | + // It starts from either 0x00000020,0x00000021,0x00000022, or 0x00000023. | |
519 | + while((((unsigned int*)v0)[0]&0xfffffffc)!=0x00000020) v0+=4; | |
520 | + // CDATA starts from next word. | |
521 | + // MLB 3 bytes show skip byte(s). | |
522 | + v0+=4+(((unsigned int*)v0)[0]&0x03); | |
523 | + // Contunue to FUNC_PUTBMP. | |
524 | + case FUNC_PUTBMP:// X1,Y1,M,N,BMP(pointer) | |
525 | + g_putbmpmn(x1,y1,x2,y2,(const unsigned char*)v0); | |
526 | + g_prev_x=x1; | |
527 | + g_prev_y=y1; | |
528 | + break; | |
529 | + case FUNC_GCOLOR:// (X1,Y1) | |
530 | + v0=g_color(x1,y1); | |
531 | + break; | |
532 | + default: | |
533 | + break; | |
534 | + } | |
535 | + return v0; | |
536 | +} | |
537 | + | |
538 | +void lib_var_push(int a0, int a1, int* sp){ | |
539 | + // Note that sp[1] is used for string return address | |
540 | + // sp[2] can be used to store flags | |
541 | + // sp[3] etc can be used to store variable values | |
542 | + int i,params; | |
543 | + unsigned char varnum; | |
544 | + unsigned int strflags=0; | |
545 | + int stack=3; | |
546 | + for(i=0;i<8;i++){ | |
547 | + // Prepare parameter | |
548 | + switch(i){ | |
549 | + case 0: | |
550 | + params=a0; | |
551 | + break; | |
552 | + case 4: | |
553 | + params=a1; | |
554 | + break; | |
555 | + default: | |
556 | + break; | |
557 | + } | |
558 | + // Get variable number | |
559 | + varnum=params&0xff; | |
560 | + params>>=8; | |
561 | + if (varnum==0) break; // No more variable. End the loop. | |
562 | + varnum--; | |
563 | + sp[stack++]=g_var_mem[varnum]; | |
564 | + if (g_var_size[varnum] && g_var_mem[varnum]==(int)(&g_var_pointer[varnum])) { | |
565 | + // strflags change using varnum | |
566 | + strflags|=1<<i; | |
567 | + // Copy to VAR_BLOCK | |
568 | + move_to_perm_block(varnum); | |
569 | + } | |
570 | + // Clear variable | |
571 | + g_var_mem[varnum]=0; | |
572 | + } | |
573 | + // Store string flags | |
574 | + sp[2]=strflags; | |
575 | +} | |
576 | + | |
577 | +void lib_var_pop(int a0, int a1, int* sp){ | |
578 | + // Note that sp is 4 bytes larger than that in lib_var_push | |
579 | + // sp[1] was used to store flags | |
580 | + // sp[2] etc can be used to store variable values | |
581 | + int i,params; | |
582 | + unsigned char varnum; | |
583 | + int stack=2; | |
584 | + unsigned int strflags=sp[1]; | |
585 | + for(i=0;i<8;i++){ | |
586 | + // Prepare parameter | |
587 | + switch(i){ | |
588 | + case 0: | |
589 | + params=a0; | |
590 | + break; | |
591 | + case 4: | |
592 | + params=a1; | |
593 | + break; | |
594 | + default: | |
595 | + break; | |
596 | + } | |
597 | + // Get variable number | |
598 | + varnum=params&0xff; | |
599 | + params>>=8; | |
600 | + if (varnum==0) break; // No more variable. End the loop. | |
601 | + varnum--; | |
602 | + g_var_mem[varnum]=sp[stack++]; | |
603 | + if (strflags&(1<<i)) { | |
604 | + // Restore from VAR_BLOCK | |
605 | + move_from_perm_block(varnum); | |
606 | + } | |
607 | + } | |
608 | +} | |
609 | + | |
610 | + | |
611 | +char* lib_sprintf(char* format, int data){ | |
612 | + char* str; | |
613 | + int i; | |
614 | + char temp[4]; | |
615 | + if (!format) format="%g"; | |
616 | + i=snprintf((char*)(&temp[0]),4,format,data)+1; | |
617 | + str=alloc_memory((i+3)/4,-1); | |
618 | + snprintf(str,i,format,data); | |
619 | + return str; | |
620 | +} | |
621 | + | |
622 | +int lib_floatfuncs(int ia0,int iv0,enum functions a1){ | |
623 | + volatile float a0,v0; | |
624 | + ((int*)(&a0))[0]=ia0; | |
625 | + ((int*)(&v0))[0]=iv0; | |
626 | + switch(a1){ | |
627 | + case FUNC_FLOAT: | |
628 | + v0=(float)iv0; | |
629 | + break; | |
630 | + case FUNC_INT: | |
631 | + return (int)v0; | |
632 | + case FUNC_VALSHARP: | |
633 | + v0=strtof((const char*)iv0,0); | |
634 | + break; | |
635 | + case FUNC_SIN: | |
636 | + v0=sinf(v0); | |
637 | + break; | |
638 | + case FUNC_COS: | |
639 | + v0=cosf(v0); | |
640 | + break; | |
641 | + case FUNC_TAN: | |
642 | + v0=tanf(v0); | |
643 | + break; | |
644 | + case FUNC_ASIN: | |
645 | + v0=asinf(v0); | |
646 | + break; | |
647 | + case FUNC_ACOS: | |
648 | + v0=acosf(v0); | |
649 | + break; | |
650 | + case FUNC_ATAN: | |
651 | + v0=atanf(v0); | |
652 | + break; | |
653 | + case FUNC_ATAN2: | |
654 | + v0=atan2f(v0,a0); | |
655 | + break; | |
656 | + case FUNC_SINH: | |
657 | + v0=sinhf(v0); | |
658 | + break; | |
659 | + case FUNC_COSH: | |
660 | + v0=coshf(v0); | |
661 | + break; | |
662 | + case FUNC_TANH: | |
663 | + v0=tanhf(v0); | |
664 | + break; | |
665 | + case FUNC_EXP: | |
666 | + v0=expf(v0); | |
667 | + break; | |
668 | + case FUNC_LOG: | |
669 | + v0=logf(v0); | |
670 | + break; | |
671 | + case FUNC_LOG10: | |
672 | + v0=log10f(v0); | |
673 | + break; | |
674 | + case FUNC_POW: | |
675 | + v0=powf(v0,a0); | |
676 | + break; | |
677 | + case FUNC_SQRT: | |
678 | + v0=sqrtf(v0); | |
679 | + break; | |
680 | + case FUNC_CEIL: | |
681 | + v0=ceilf(v0); | |
682 | + break; | |
683 | + case FUNC_FLOOR: | |
684 | + v0=floorf(v0); | |
685 | + break; | |
686 | + case FUNC_FABS: | |
687 | + v0=fabsf(v0); | |
688 | + break; | |
689 | + case FUNC_MODF: | |
690 | + v0=modff(v0,(void*)&a0); | |
691 | + break; | |
692 | + case FUNC_FMOD: | |
693 | + v0=fmodf(v0,a0); | |
694 | + break; | |
695 | + default: | |
696 | + err_unknown(); | |
697 | + break; | |
698 | + } | |
699 | + return ((int*)(&v0))[0]; | |
700 | +}; | |
701 | + | |
702 | +int* lib_dim(int varnum, int argsnum, int* sp){ | |
703 | + int i,j; | |
704 | + static int* heap; | |
705 | + // Calculate total length. | |
706 | + int len=0; // Total length | |
707 | + int size=1; // Size of current block | |
708 | + for(i=1;i<=argsnum;i++){ | |
709 | + size*=sp[i]+1; | |
710 | + len+=size; | |
711 | + } | |
712 | + // Allocate memory | |
713 | + heap=calloc_memory(len,varnum); | |
714 | + // Construct pointers | |
715 | + len=0; | |
716 | + size=1; | |
717 | + for(i=1;i<argsnum;i++){ | |
718 | + size*=sp[i]+1; | |
719 | + for(j=0;j<size;j++){ | |
720 | + heap[len+j]=(int)&heap[len+size+(sp[i+1]+1)*j]; | |
721 | + } | |
722 | + len+=size; | |
723 | + } | |
724 | + return heap; | |
725 | +}; | |
726 | + | |
727 | +int lib_file_textlen(FSFILE* fhandle){ | |
728 | + char buff[128]; | |
729 | + int i,textlen,len,seek; | |
730 | + seek=FSftell(fhandle); | |
731 | + len=FSfread(&buff[0],1,128,fhandle); | |
732 | + textlen=0; | |
733 | + for(i=0;i<len-1;i++){ // Read 127 bytes for supporting CRLF | |
734 | + if (buff[i]==0x0d) { | |
735 | + if (i<len && buff[i+1]==0x0a) i++; | |
736 | + break; | |
737 | + } else if (buff[i]==0x0a) { | |
738 | + break; | |
739 | + } | |
740 | + if (i==len-2) { | |
741 | + // reached the end of buffer. Read next 127 bytes | |
742 | + textlen+=127; | |
743 | + buff[0]=buff[127]; | |
744 | + len=FSfread(&buff[1],1,127,fhandle); | |
745 | + // Continue with i=0 | |
746 | + i=-1; | |
747 | + } | |
748 | + } | |
749 | + // The last return code must be included to caluclate total length. | |
750 | + textlen+=i+1; | |
751 | + // Return to original position | |
752 | + FSfseek(fhandle,seek,SEEK_SET); | |
753 | + return textlen; | |
754 | +} | |
755 | + | |
756 | +int lib_file(enum functions func, int a0, int a1, int v0){ | |
757 | + static FSFILE* s_fhandle[2]={0,0}; | |
758 | + static char activefhandle=0; | |
759 | + static int numinline=0; | |
760 | + FSFILE* fhandle=0; | |
761 | + int i; | |
762 | + int buff[1]; | |
763 | + char* str; | |
764 | + if (activefhandle) fhandle=s_fhandle[activefhandle-1]; | |
765 | + switch(func){ | |
766 | + case FUNC_FINIT: | |
767 | + // This function is not BASIC statement/function but used from | |
768 | + // running routine. | |
769 | + for(i=0;i<2;i++){ | |
770 | + if (s_fhandle[i]) FSfclose(s_fhandle[i]); | |
771 | + s_fhandle[i]=0; | |
772 | + } | |
773 | + activefhandle=0; | |
774 | + numinline=0; | |
775 | + break; | |
776 | + case FUNC_FOPEN: // Return 0 when called as a function. | |
777 | + case FUNC_FOPENST: // Stop with error when called as a statement. | |
778 | + activefhandle=0; | |
779 | + // Check if file handle is free to use, first. | |
780 | + switch(v0){ | |
781 | + case 0: | |
782 | + // File handle was not designated | |
783 | + // Force handle=1 and continue to following cases. | |
784 | + v0=1; | |
785 | + case 1: | |
786 | + case 2: | |
787 | + // File handle was designated | |
788 | + // Check if not used yet. | |
789 | + if (s_fhandle[v0-1]) { | |
790 | + // This file handle has been occupied. | |
791 | + err_file(); | |
792 | + return 0; | |
793 | + } | |
794 | + // OK. This file handle can be asigned for new file opened. | |
795 | + break; | |
796 | + default: | |
797 | + err_invalid_param(); | |
798 | + return 0; | |
799 | + } | |
800 | + // Open a file | |
801 | + fhandle=FSfopen ((const char*) a0, (const char*) a1); | |
802 | + if (!fhandle) { | |
803 | + if (func==FUNC_FOPENST) err_file(); | |
804 | + return 0; | |
805 | + } | |
806 | + // The file is succesfully opened. Asign file handle. | |
807 | + s_fhandle[v0-1]=fhandle; | |
808 | + activefhandle=v0; | |
809 | + return v0; | |
810 | + case FUNC_FILE: | |
811 | + switch(v0){ | |
812 | + case 1: | |
813 | + case 2: | |
814 | + if (s_fhandle[v0]) { | |
815 | + activefhandle=v0; | |
816 | + break; | |
817 | + } | |
818 | + default: | |
819 | + err_invalid_param(); | |
820 | + } | |
821 | + break; | |
822 | + case FUNC_FCLOSE: | |
823 | + switch(v0){ | |
824 | + case 0: | |
825 | + break; | |
826 | + case 1: | |
827 | + case 2: | |
828 | + if (s_fhandle[v0-1]) activefhandle=v0; | |
829 | + if (activefhandle) fhandle=s_fhandle[activefhandle-1]; | |
830 | + break; | |
831 | + default: | |
832 | + err_invalid_param(); | |
833 | + } | |
834 | + if (fhandle) { | |
835 | + FSfclose(fhandle); | |
836 | + s_fhandle[activefhandle-1]=0; | |
837 | + } | |
838 | + activefhandle=0; | |
839 | + break; | |
840 | + case FUNC_FINPUT: | |
841 | + if (fhandle) { | |
842 | + // Determine text length if called without parameter | |
843 | + if (v0==0) v0=lib_file_textlen(fhandle); | |
844 | + // Allocate temporary area for string | |
845 | + str=alloc_memory((v0+1+3)/4,-1); | |
846 | + // Read from SD card | |
847 | + v0=FSfread(str,1,v0,fhandle); | |
848 | + // Null string at the end. | |
849 | + str[v0]=0; | |
850 | + return (int)str; | |
851 | + } else { | |
852 | + err_file(); | |
853 | + return (int)""; | |
854 | + } | |
855 | + case FUNC_FPRINTSTR: | |
856 | + // Like lib_printstr() | |
857 | + for(i=0;((char*)v0)[i];i++); | |
858 | + if (fhandle) { | |
859 | + if (!FSfwrite((char*)v0,1,i,fhandle)) err_file(); | |
860 | + } else err_file(); | |
861 | + numinline+=i; | |
862 | + break; | |
863 | + case FUNC_FSTRING: | |
864 | + // Like lib_string() | |
865 | + switch(v0){ | |
866 | + case 0: | |
867 | + // CR | |
868 | + lib_file(FUNC_FPRINTSTR,a0,a1,(int)"\r\n"); | |
869 | + numinline=0; | |
870 | + break; | |
871 | + case 1: | |
872 | + // , | |
873 | + i=rem10_32(numinline); | |
874 | + lib_file(FUNC_FPRINTSTR,a0,a1,(int)(" "+i)); | |
875 | + break; | |
876 | + default: | |
877 | + break; | |
878 | + } | |
879 | + break; | |
880 | + case FUNC_FGET: | |
881 | + if (fhandle) return FSfread((void*)a0,1,v0,fhandle); | |
882 | + err_file(); | |
883 | + break; | |
884 | + case FUNC_FPUT: | |
885 | + if (fhandle) return FSfwrite((void*)a0,1,v0,fhandle); | |
886 | + err_file(); | |
887 | + break; | |
888 | + case FUNC_FGETC: | |
889 | + if (fhandle) { | |
890 | + // Note: Little endian. | |
891 | + if (FSfread((void*)&buff[0],1,1,fhandle)) return buff[0]&0xff; | |
892 | + else return -1; | |
893 | + } | |
894 | + err_file(); | |
895 | + break; | |
896 | + case FUNC_FPUTC: | |
897 | + if (fhandle) { | |
898 | + // Note: Little endian. | |
899 | + buff[0]=v0; | |
900 | + return FSfwrite((void*)&buff[0],1,1,fhandle); | |
901 | + } | |
902 | + err_file(); | |
903 | + break; | |
904 | + case FUNC_FSEEK: | |
905 | + if (fhandle) return FSfseek(fhandle,v0,SEEK_SET); | |
906 | + err_file(); | |
907 | + break; | |
908 | + case FUNC_FTELL: | |
909 | + if (fhandle) return FSftell(fhandle); | |
910 | + err_file(); | |
911 | + break; | |
912 | + case FUNC_FLEN: | |
913 | + if (fhandle) return fhandle->size; | |
914 | + err_file(); | |
915 | + break; | |
916 | + case FUNC_FEOF: | |
917 | + if (fhandle) return (fhandle->size<=FSftell(fhandle)) ? 1:0; | |
918 | + err_file(); | |
919 | + break; | |
920 | + case FUNC_FREMOVE: | |
921 | + return FSremove((const char *)v0); | |
922 | + default: | |
923 | + err_unknown(); | |
924 | + } | |
925 | + return v0; | |
926 | +} | |
927 | + | |
928 | +int _call_library(int a0,int a1,int a2,enum libs a3); | |
929 | + | |
930 | +void call_library(void){ | |
931 | + // Store s6 in g_s6 | |
932 | + asm volatile("la $a2,%0"::"i"(&g_s6)); | |
933 | + asm volatile("sw $s6,0($a2)"); | |
934 | + // Copy $v0 to $a2 as 3rd argument of function | |
935 | + asm volatile("addu $a2,$v0,$zero"); | |
936 | + // Store sp in g_libparams | |
937 | + asm volatile("la $v0,%0"::"i"(&g_libparams)); | |
938 | + asm volatile("sw $sp,0($v0)"); | |
939 | + // Jump to main routine | |
940 | + asm volatile("j _call_library"); | |
941 | +} | |
942 | + | |
943 | +int _call_library(int a0,int a1,int v0,enum libs a3){ | |
944 | + // usage: call_lib_code(LIB_XXXX); | |
945 | + // Above code takes 2 words. | |
946 | + check_break(); | |
947 | + switch(a3 & LIB_MASK){ | |
948 | + case LIB_FLOAT: | |
949 | + return lib_float(a0,v0,(enum operator)(a3 & OP_MASK)); // see operator.c | |
950 | + case LIB_FLOATFUNCS: | |
951 | + return lib_floatfuncs(a0,v0,(enum functions)(a3 & FUNC_MASK)); | |
952 | + case LIB_STRNCMP: | |
953 | + return strncmp((char*)g_libparams[1],(char*)g_libparams[2],v0); | |
954 | + case LIB_MIDSTR: | |
955 | + return (int)lib_midstr(a1,v0,a0); | |
956 | + case LIB_RND: | |
957 | + return (int)lib_rnd(); | |
958 | + case LIB_DEC: | |
959 | + return (int)lib_dec(v0); | |
960 | + case LIB_HEX: | |
961 | + return (int)lib_hex(v0,a0); | |
962 | + case LIB_CHR: | |
963 | + return (int)lib_chr(v0); | |
964 | + case LIB_VAL: | |
965 | + return lib_val((char*)v0); | |
966 | + case LIB_LETSTR: | |
967 | + lib_let_str((char*)v0,a0); | |
968 | + return; | |
969 | + case LIB_CONNECT_STRING: | |
970 | + return (int)lib_connect_string((char*)a0, (char*)v0); | |
971 | + case LIB_STRING: | |
972 | + lib_string(v0); | |
973 | + return v0; | |
974 | + case LIB_PRINTSTR: | |
975 | + printstr((char*)v0); | |
976 | + return v0; | |
977 | + case LIB_GRAPHIC: | |
978 | + return lib_graphic(v0, (enum functions)(a3 & FUNC_MASK)); | |
979 | + case LIB_SPRINTF: | |
980 | + return (int)lib_sprintf((char*)v0,a0); | |
981 | + case LIB_VAR_PUSH: | |
982 | + lib_var_push(a0,a1,g_libparams); | |
983 | + return v0; | |
984 | + case LIB_VAR_POP: | |
985 | + lib_var_pop(a0,a1,g_libparams); | |
986 | + return v0; | |
987 | + case LIB_SCROLL: | |
988 | + scroll(g_libparams[1],v0); | |
989 | + return v0; | |
990 | + case LIB_FILE: | |
991 | + return lib_file((enum functions)(a3 & FUNC_MASK),g_libparams[1],g_libparams[2],v0); | |
992 | + case LIB_KEYS: | |
993 | + return lib_keys(v0); | |
994 | + case LIB_INKEY: | |
995 | + return (int)lib_inkey(v0); | |
996 | + case LIB_CURSOR: | |
997 | + setcursor(g_libparams[1],v0,cursorcolor); | |
998 | + return v0; | |
999 | + case LIB_SOUND: | |
1000 | + set_sound((unsigned long*)v0,a0); | |
1001 | + return v0; | |
1002 | + case LIB_MUSICFUNC: | |
1003 | + return musicRemaining(a0); | |
1004 | + case LIB_MUSIC: | |
1005 | + set_music((char*)v0,a0); | |
1006 | + return v0; | |
1007 | + case LIB_PLAYWAVE: | |
1008 | + play_wave((char*)g_libparams[1],v0); | |
1009 | + return v0; | |
1010 | + case LIB_PLAYWAVEFUNC: | |
1011 | + return waveRemaining(v0); | |
1012 | + case LIB_SETDRAWCOUNT: | |
1013 | + drawcount=(v0&0x0000FFFF); | |
1014 | + return v0; | |
1015 | + case LIB_DRAWCOUNT: | |
1016 | + return drawcount; | |
1017 | + case LIB_SYSTEM: | |
1018 | + return lib_system(a0, a1 ,v0, a3, g_gcolor, g_prev_x, g_prev_y); | |
1019 | + case LIB_RESTORE: | |
1020 | + return lib_read(0,v0); | |
1021 | + case LIB_RESTORE2: | |
1022 | + return lib_read(1,v0); | |
1023 | + case LIB_READ: | |
1024 | + return lib_read(0,0); | |
1025 | + case LIB_CREAD: | |
1026 | + return lib_read(1,0); | |
1027 | + case LIB_LABEL: | |
1028 | + return (int)lib_label(v0); | |
1029 | + case LIB_INPUT: | |
1030 | + return (int)lib_input(); | |
1031 | + case LIB_USEGRAPHIC: | |
1032 | + lib_usegraphic(v0); | |
1033 | + return v0; | |
1034 | + case LIB_USEPCG: | |
1035 | + lib_usepcg(v0); | |
1036 | + return v0; | |
1037 | + case LIB_PCG: | |
1038 | + lib_pcg(g_libparams[1],g_libparams[2],v0); | |
1039 | + return v0; | |
1040 | + case LIB_BGCOLOR: // BGCOLOR R,G,B | |
1041 | + set_bgcolor(v0,g_libparams[1],g_libparams[2]); //set_bgcolor(b,r,g); | |
1042 | + return v0; | |
1043 | + case LIB_PALETTE: // PALETTE N,R,G,B | |
1044 | + set_palette(g_libparams[1],v0,g_libparams[2],g_libparams[3]); // set_palette(n,b,r,g); | |
1045 | + return v0; | |
1046 | + case LIB_GPALETTE:// GPALETTE N,R,G,B | |
1047 | + if (g_graphic_area) g_set_palette(g_libparams[1],v0,g_libparams[2],g_libparams[3]); // g_set_palette(n,b,r,g); | |
1048 | + return v0; | |
1049 | + case LIB_CLS: | |
1050 | + clearscreen(); | |
1051 | + return v0; | |
1052 | + case LIB_GCLS: | |
1053 | + if (g_graphic_area) g_clearscreen(); | |
1054 | + g_prev_x=g_prev_y=0; | |
1055 | + return v0; | |
1056 | + case LIB_WIDTH: | |
1057 | + videowidth(v0); | |
1058 | + return v0; | |
1059 | + case LIB_COLOR: | |
1060 | + setcursorcolor(v0); | |
1061 | + return v0; | |
1062 | + case LIB_GCOLOR: | |
1063 | + g_gcolor=v0; | |
1064 | + return v0; | |
1065 | + case LIB_WAIT: | |
1066 | + lib_wait(v0); | |
1067 | + return v0; | |
1068 | + case LIB_CLEAR: | |
1069 | + lib_clear(); | |
1070 | + return v0; | |
1071 | + case LIB_DIM: | |
1072 | + return (int)lib_dim(a0,a1,(int*)v0); | |
1073 | +#ifdef __DEBUG | |
1074 | + case LIB_DEBUG: | |
1075 | + asm volatile("nop"); | |
1076 | + return v0; | |
1077 | +#endif | |
1078 | + case LIB_DIV0: | |
1079 | + err_div_zero(); | |
1080 | + return v0; | |
1081 | + default: | |
1082 | + err_unknown(); | |
1083 | + return v0; | |
1084 | + } | |
1085 | +} | |
\ No newline at end of file |
@@ -0,0 +1,1637 @@ | ||
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 | + // 2nd param is optional | |
41 | + next_position(); | |
42 | + if (g_source[g_srcpos]==',') { | |
43 | + g_srcpos++; | |
44 | + check_obj_space(2); | |
45 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
46 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
47 | + err=get_value(); | |
48 | + if (err) return err; | |
49 | + check_obj_space(3); | |
50 | + g_object[g_objpos++]=0x00402021; // addu a0,v0,zero | |
51 | + g_object[g_objpos++]=0x8FA20004; // lw v0,4(sp) | |
52 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
53 | + } else { | |
54 | + // Set 3 if omitted | |
55 | + check_obj_space(1); | |
56 | + g_object[g_objpos++]=0x24040003; // addiu a0,zero,xx | |
57 | + } | |
58 | + call_lib_code(LIB_SOUND); | |
59 | + return 0; | |
60 | +} | |
61 | +char* music_statement(){ | |
62 | + char *err; | |
63 | + err=get_string(); | |
64 | + if (err) return err; | |
65 | + // 2nd param is optional | |
66 | + next_position(); | |
67 | + if (g_source[g_srcpos]==',') { | |
68 | + g_srcpos++; | |
69 | + check_obj_space(2); | |
70 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
71 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
72 | + err=get_value(); | |
73 | + if (err) return err; | |
74 | + check_obj_space(3); | |
75 | + g_object[g_objpos++]=0x00402021; // addu a0,v0,zero | |
76 | + g_object[g_objpos++]=0x8FA20004; // lw v0,4(sp) | |
77 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
78 | + } else { | |
79 | + // Set 3 if omitted | |
80 | + check_obj_space(1); | |
81 | + g_object[g_objpos++]=0x24040003; // addiu a0,zero,xx | |
82 | + } | |
83 | + call_lib_code(LIB_MUSIC); | |
84 | + return 0; | |
85 | +} | |
86 | + | |
87 | +char* exec_statement(){ | |
88 | + char *err; | |
89 | + char b1; | |
90 | + int i,prevpos; | |
91 | + b1=g_source[g_srcpos]; | |
92 | + while('0'<=b1 && b1<='9' || b1=='-' || b1=='$'){ | |
93 | + prevpos=g_objpos; | |
94 | + g_valueisconst=1; | |
95 | + err=get_simple_value(); | |
96 | + if (!g_valueisconst) err=ERR_SYNTAX; | |
97 | + if (err) return err; | |
98 | + check_obj_space(1); | |
99 | + g_objpos=prevpos; | |
100 | + g_object[g_objpos++]=g_intconst; | |
101 | + next_position(); | |
102 | + b1=g_source[g_srcpos]; | |
103 | + if (b1!=',') break; | |
104 | + g_srcpos++; | |
105 | + next_position(); | |
106 | + b1=g_source[g_srcpos]; | |
107 | + if (b1==0x0d || b1==0x0a) { | |
108 | + // Multiline DATA/EXEC statement | |
109 | + g_line++; | |
110 | + g_fileline++; | |
111 | + if (b1==0x0D && g_source[g_srcpos+1]==0x0A) g_srcpos++; | |
112 | + g_srcpos++; | |
113 | + // Maintain at least 256 characters in cache. | |
114 | + if (256<=g_srcpos) read_file(256); | |
115 | + next_position(); | |
116 | + b1=g_source[g_srcpos]; | |
117 | + } | |
118 | + } | |
119 | + return 0; | |
120 | +} | |
121 | + | |
122 | +char* cdata_statement(){ | |
123 | + // 0x00000020, 0x00000021, 0x00000022, and 0x00000023 (add/addu/sub/subu zero,zero,zero) | |
124 | + // are the sign of data region | |
125 | + int beginpos,prevpos; | |
126 | + char* err; | |
127 | + char b1; | |
128 | + char* cpy; | |
129 | + int shift=0; | |
130 | + int i=0; | |
131 | + beginpos=g_objpos; | |
132 | + check_obj_space(2); | |
133 | + g_object[g_objpos++]=0x04110000; // bgezal zero,xxxx | |
134 | + g_object[g_objpos++]=0x00000020; // add zero,zero,zero | |
135 | + next_position(); | |
136 | + b1=g_source[g_srcpos]; | |
137 | + while('0'<=b1 && b1<='9' || b1=='-' || b1=='$'){ | |
138 | + prevpos=g_objpos; | |
139 | + g_valueisconst=1; | |
140 | + err=get_simple_value(); | |
141 | + if (!g_valueisconst) err=ERR_SYNTAX; | |
142 | + if (g_intconst<0x00 || 0xff<g_intconst) err=ERR_SYNTAX; | |
143 | + if (err) return err; | |
144 | + g_objpos=prevpos; | |
145 | + i|=g_intconst<<shift; | |
146 | + shift+=8; | |
147 | + if (32<=shift) { | |
148 | + check_obj_space(1); | |
149 | + g_object[g_objpos++]=i; | |
150 | + shift=0; | |
151 | + i=0; | |
152 | + } | |
153 | + next_position(); | |
154 | + b1=g_source[g_srcpos]; | |
155 | + if (b1!=',') break; | |
156 | + g_srcpos++; | |
157 | + next_position(); | |
158 | + b1=g_source[g_srcpos]; | |
159 | + if (b1==0x0d || b1==0x0a) { | |
160 | + // Multiline CDATA statement | |
161 | + g_line++; | |
162 | + g_fileline++; | |
163 | + if (b1==0x0D && g_source[g_srcpos+1]==0x0A) g_srcpos++; | |
164 | + g_srcpos++; | |
165 | + // Maintain at least 256 characters in cache. | |
166 | + if (256<=g_srcpos) read_file(256); | |
167 | + next_position(); | |
168 | + b1=g_source[g_srcpos]; | |
169 | + } | |
170 | + } | |
171 | + // Write the last 1-3 bytes and shift data if total # is not multipes of 4. | |
172 | + if (0<shift) { | |
173 | + // Convert shift value from bit-shift to data byte-shift. | |
174 | + shift=4-shift/8; | |
175 | + check_obj_space(1); | |
176 | + g_object[g_objpos++]=i; | |
177 | + for(cpy=(char*)&g_object[g_objpos]-1;(char*)&g_object[beginpos+2]<cpy;cpy--){ | |
178 | + cpy[0]=cpy[0-shift]; | |
179 | + } | |
180 | + } | |
181 | + // Determine the size of data | |
182 | + i=g_objpos-beginpos-1; | |
183 | + g_object[beginpos] =0x04110000|i; // bgezal zero,xxxx | |
184 | + g_object[beginpos+1]=0x00000020|shift; // add zero,zero,zero | |
185 | + return 0; | |
186 | +} | |
187 | + | |
188 | +char* data_statement(){ | |
189 | + // 0x00000020, 0x00000021, 0x00000022, and 0x00000023 (add/addu/sub/subu zero,zero,zero) | |
190 | + // are the sign of data region | |
191 | + int i,prevpos; | |
192 | + char* err; | |
193 | + while(1){ | |
194 | + prevpos=g_objpos; | |
195 | + check_obj_space(2); | |
196 | + g_object[g_objpos++]=0x04110000; // bgezal zero,xxxx | |
197 | + g_object[g_objpos++]=0x00000020; // add zero,zero,zero | |
198 | + next_position(); | |
199 | + if (g_source[g_srcpos]=='"') { | |
200 | + // Constant string | |
201 | + // Store pointer to string. This is 3 words bellow of current position | |
202 | + g_object[g_objpos]=(int)(&g_object[g_objpos+3]); | |
203 | + g_objpos++; | |
204 | + g_object[prevpos]=0x04110002; // bgezal zero,xxxx | |
205 | + err=simple_string(); | |
206 | + if (err) return err; | |
207 | + next_position(); | |
208 | + if (g_source[g_srcpos]==',') { | |
209 | + g_srcpos++; | |
210 | + continue; | |
211 | + } | |
212 | + return 0; | |
213 | + } | |
214 | + err=exec_statement(); | |
215 | + if (err) return err; | |
216 | + // Determine the size of data | |
217 | + i=g_objpos-prevpos-1; | |
218 | + g_object[prevpos]=0x04110000|i; // bgezal zero,xxxx | |
219 | + if (g_source[g_srcpos]=='"') { | |
220 | + // Constant string | |
221 | + continue; | |
222 | + } | |
223 | + return 0; | |
224 | + } | |
225 | +} | |
226 | + | |
227 | +char* clear_statement(){ | |
228 | + call_lib_code(LIB_CLEAR); | |
229 | + return 0; | |
230 | +} | |
231 | + | |
232 | +char* poke_statement(){ | |
233 | + char* err; | |
234 | + err=get_value(); | |
235 | + if (err) return err; | |
236 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
237 | + g_srcpos++; | |
238 | + check_obj_space(2); | |
239 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
240 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
241 | + err=get_value(); | |
242 | + if (err) return err; | |
243 | + check_obj_space(3); | |
244 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
245 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
246 | + g_object[g_objpos++]=0xA0620000; // sb v0,0(v1) | |
247 | + return 0; | |
248 | +} | |
249 | + | |
250 | +char* dim_statement(){ | |
251 | + char* err; | |
252 | + char b1; | |
253 | + int i; | |
254 | + int spos; | |
255 | + int stack; | |
256 | + while(1){ | |
257 | + stack=0; | |
258 | + next_position(); | |
259 | + i=get_var_number(); | |
260 | + if (i<0) return ERR_SYNTAX; | |
261 | + if (g_source[g_srcpos]=='#') g_srcpos++; | |
262 | + next_position(); | |
263 | + if (g_source[g_srcpos]!='(') return ERR_SYNTAX; | |
264 | + check_obj_space(1); | |
265 | + spos=g_objpos++; // addiu sp,sp,xxxx | |
266 | + do { | |
267 | + g_srcpos++; | |
268 | + err=get_value(); | |
269 | + if (err) return err; | |
270 | + stack+=4; | |
271 | + check_obj_space(1); | |
272 | + g_object[g_objpos++]=0xAFA20000|stack; // sw v0,8(sp) | |
273 | + } while (g_source[g_srcpos]==','); | |
274 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
275 | + g_srcpos++; | |
276 | + check_obj_space(3); | |
277 | + g_object[g_objpos++]=0x24040000|(i); // addiu a0,zero,xx | |
278 | + g_object[g_objpos++]=0x24050000|(stack/4); // addiu a1,zero,xxxx | |
279 | + g_object[g_objpos++]=0x03A01025; // or v0,sp,zero | |
280 | + call_lib_code(LIB_DIM); | |
281 | + // Stack -/+ | |
282 | + check_obj_space(1); | |
283 | + g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xxxx | |
284 | + stack=(0-stack)&0x0000FFFF; | |
285 | + g_object[spos]=0x27BD0000|stack; // addiu sp,sp,xxxx | |
286 | + next_position(); | |
287 | + if (g_source[g_srcpos]!=',') break; | |
288 | + g_srcpos++; | |
289 | + } | |
290 | + return 0; | |
291 | +} | |
292 | + | |
293 | +char* label_statement(){ | |
294 | + char* err; | |
295 | + char b1; | |
296 | + b1=g_source[g_srcpos]; | |
297 | + if (b1<'A' || 'Z'<b1) return ERR_SYNTAX; // Number is not allowed here. | |
298 | + err=get_label(); | |
299 | + if (err) return err; | |
300 | + // Check existing label with the same name here. | |
301 | + if (search_label(g_label)) { | |
302 | + // Error: duplicate labels | |
303 | + printstr("Label "); | |
304 | + printstr(resolve_label(g_label)); | |
305 | + return ERR_MULTIPLE_LABEL; | |
306 | + } | |
307 | + check_obj_space(2); | |
308 | + g_object[g_objpos++]=0x3C160000|((g_label>>16)&0x0000FFFF); //lui s6,yyyy; | |
309 | + g_object[g_objpos++]=0x36D60000|(g_label&0x0000FFFF); //ori s6,s6,zzzz; | |
310 | + return 0; | |
311 | +} | |
312 | + | |
313 | +char* restore_statement(){ | |
314 | + char* err; | |
315 | + err=get_label(); | |
316 | + if (err) return err; | |
317 | + if (g_label) { | |
318 | + // Constant label/number | |
319 | + // Use 32 bit mode also for values<65536 | |
320 | + // This code will be replaced to code for v0 for pointer in linker. | |
321 | + check_obj_space(2); | |
322 | + g_object[g_objpos++]=0x3C020000|(g_label>>16); // lui v0,xxxx | |
323 | + g_object[g_objpos++]=0x34420000|(g_label&0x0000FFFF); // ori v0,v0,xxxx | |
324 | + } else { | |
325 | + // Dynamic number | |
326 | + err=get_value(); | |
327 | + if (err) return err; | |
328 | + } | |
329 | + call_lib_code(LIB_RESTORE); | |
330 | + return 0; | |
331 | +} | |
332 | + | |
333 | +char* gosub_statement_sub(){ | |
334 | + char* err; | |
335 | + err=get_label(); | |
336 | + if (err) return err; | |
337 | + if (g_label) { | |
338 | + // Label/number is constant. | |
339 | + // Linker will change following codes later. | |
340 | + // Note that 0x0812xxxx and 0x0813xxxx are specific codes for these. | |
341 | + check_obj_space(6); | |
342 | + g_object[g_objpos++]=0x04130003; // bgezall zero,label1 | |
343 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
344 | + g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
345 | + g_object[g_objpos++]=0x08120000|((g_label>>16)&0x0000FFFF); // nop | |
346 | + // label1: | |
347 | + g_object[g_objpos++]=0x08130000|(g_label&0x0000FFFF); // j xxxx | |
348 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
349 | + // label2: | |
350 | + } else { | |
351 | + // Label/number will be dynamically set when executing code. | |
352 | + err=get_value(); | |
353 | + if (err) return err; | |
354 | + call_lib_code(LIB_LABEL); | |
355 | + check_obj_space(6); | |
356 | + g_object[g_objpos++]=0x04130003; // bgezall zero,label1 | |
357 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
358 | + g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
359 | + g_object[g_objpos++]=0x00000000; // nop | |
360 | + // label1: | |
361 | + g_object[g_objpos++]=0x00400008; // jr v0 | |
362 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
363 | + // label2: | |
364 | + } | |
365 | + return 0; | |
366 | +} | |
367 | + | |
368 | +char* gosub_statement(){ | |
369 | + char* err; | |
370 | + int opos,spos,stack; | |
371 | + opos=g_objpos; | |
372 | + spos=g_srcpos; | |
373 | + err=gosub_statement_sub(); | |
374 | + if (err) return err; | |
375 | + next_position(); | |
376 | + // If there is no 2nd argument, return. | |
377 | + if (g_source[g_srcpos]!=',') return 0; | |
378 | + | |
379 | + // There is (at least) 2nd argument. | |
380 | + // Rewind object and construct argument-creating routine. | |
381 | + g_objpos=opos; | |
382 | + stack=4; | |
383 | + g_object[g_objpos++]=0x27BD0000; // addiu sp,sp,-xx | |
384 | + do { | |
385 | + g_srcpos++; | |
386 | + stack+=4; | |
387 | + err=get_stringFloatOrValue(); | |
388 | + if (err) return err; | |
389 | + check_obj_space(1); | |
390 | + g_object[g_objpos++]=0xAFA20000|stack; // sw v0,xx(sp) | |
391 | + next_position(); | |
392 | + } while(g_source[g_srcpos]==','); | |
393 | + check_obj_space(2); | |
394 | + g_object[g_objpos++]=0xAFB50004; // sw s5,4(sp) | |
395 | + g_object[g_objpos++]=0x03A0A821; // addu s5,sp,zero | |
396 | + g_object[opos]|=((0-stack)&0xFFFF); // addiu sp,sp,-xx (See above) | |
397 | + // Rewind source and construct GOSUB routine again. | |
398 | + opos=spos; | |
399 | + spos=g_srcpos; | |
400 | + g_srcpos=opos; | |
401 | + err=gosub_statement_sub(); | |
402 | + if (err) return err; | |
403 | + // Remove stack | |
404 | + check_obj_space(2); | |
405 | + g_object[g_objpos++]=0x8FB50004; // lw s5,4(sp) | |
406 | + g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xx | |
407 | + // All done, go back to wright source position | |
408 | + g_srcpos=spos; | |
409 | + return 0; | |
410 | +} | |
411 | + | |
412 | +char* return_statement(){ | |
413 | + char* err; | |
414 | + char b1; | |
415 | + next_position(); | |
416 | + b1=g_source[g_srcpos]; | |
417 | + if (0x20<b1 && b1!=':') { | |
418 | + // There is a return value. | |
419 | + err=get_stringFloatOrValue(); | |
420 | + if (err) return err; | |
421 | + } | |
422 | + check_obj_space(3); | |
423 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
424 | + g_object[g_objpos++]=0x00600008; // jr v1 | |
425 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
426 | + return 0; | |
427 | +} | |
428 | + | |
429 | +char* goto_statement(){ | |
430 | + char* err; | |
431 | + err=get_label(); | |
432 | + if (err) return err; | |
433 | + if (g_label) { | |
434 | + // Label/number is constant. | |
435 | + // Linker will change following codes later. | |
436 | + // Note that 0x0810xxxx and 0x0811xxxx are specific codes for these. | |
437 | + check_obj_space(2); | |
438 | + g_object[g_objpos++]=0x08100000|((g_label>>16)&0x0000FFFF); // j xxxx | |
439 | + g_object[g_objpos++]=0x08110000|(g_label&0x0000FFFF); // nop | |
440 | + } else { | |
441 | + // Label/number will be dynamically set when executing code. | |
442 | + err=get_value(); | |
443 | + if (err) return err; | |
444 | + call_lib_code(LIB_LABEL); | |
445 | + check_obj_space(2); | |
446 | + g_object[g_objpos++]=0x00400008; // jr v0 | |
447 | + g_object[g_objpos++]=0x00000000; // nop | |
448 | + } | |
449 | + return 0; | |
450 | +} | |
451 | + | |
452 | +char* if_statement(){ | |
453 | + char* err; | |
454 | + int prevpos,bpos; | |
455 | + // Get value. | |
456 | + err=get_floatOrValue(); | |
457 | + if (err) return err; | |
458 | + // Check "THEN" | |
459 | + if (!nextCodeIs("THEN")) return ERR_SYNTAX; | |
460 | + // Check if statement follows after THEN statement | |
461 | + next_position(); | |
462 | + if (nextCodeIs("REM")) { | |
463 | + // If REM statement follows, skip comment words. | |
464 | + rem_statement(); | |
465 | + } | |
466 | + if (g_source[g_srcpos]<0x20) { | |
467 | + // End of line. | |
468 | + // Use IF-THEN-ENDIF mode (multiple line mode) | |
469 | + check_obj_space(3); | |
470 | + g_object[g_objpos++]=0x30000000; // nop (see linker) | |
471 | + g_object[g_objpos++]=0x10400000; // beq v0,zero,xxxx | |
472 | + g_object[g_objpos++]=0x30000000; // nop (see linker) | |
473 | + return 0; | |
474 | + } | |
475 | + // One line mode | |
476 | + // If $v0=0 then skip. | |
477 | + bpos=g_objpos; | |
478 | + check_obj_space(2); | |
479 | + g_object[g_objpos++]=0x10400000; // beq v0,zero,xxxx | |
480 | + g_object[g_objpos++]=0x00000000; // nop | |
481 | + prevpos=g_srcpos; | |
482 | + if (statement()) { | |
483 | + // May be label | |
484 | + g_srcpos=prevpos; | |
485 | + err=goto_statement(); | |
486 | + if (err) return err; | |
487 | + } else { | |
488 | + // Must be statement(s) | |
489 | + while(1) { | |
490 | + if (g_source[g_srcpos]!=':') break; | |
491 | + g_srcpos++; | |
492 | + err=statement(); | |
493 | + if (err) return err; | |
494 | + } | |
495 | + } | |
496 | + // Check if "ELSE" exists. | |
497 | + if (!nextCodeIs("ELSE ")) { | |
498 | + // "ELSE" not found. This is the end of "IF" statement. | |
499 | + // Previous branch command must jump to this position. | |
500 | + g_object[bpos]=0x10400000|(g_objpos-bpos-1); // beq v0,zero,xxxx | |
501 | + return 0; | |
502 | + } | |
503 | + // Skip after ELSE if required. | |
504 | + check_obj_space(2); | |
505 | + g_object[g_objpos++]=0x10000000; // beq zero,zero,xxxx | |
506 | + g_object[g_objpos++]=0x00000000; // nop | |
507 | + // Previous branch command must jump to this position. | |
508 | + g_object[bpos]=0x10400000|(g_objpos-bpos-1); // beq v0,zero,xxxx | |
509 | + bpos=g_objpos-2; | |
510 | + // Next statement is either label or general statement | |
511 | + prevpos=g_srcpos; | |
512 | + if (statement()) { | |
513 | + // May be label | |
514 | + g_srcpos=prevpos; | |
515 | + err=goto_statement(); | |
516 | + if (err) return err; | |
517 | + } else { | |
518 | + // Must be statement(s) | |
519 | + while(1) { | |
520 | + if (g_source[g_srcpos]!=':') break; | |
521 | + g_srcpos++; | |
522 | + err=statement(); | |
523 | + if (err) return err; | |
524 | + } | |
525 | + } | |
526 | + // Previous branch command must jump to this position. | |
527 | + g_object[bpos]=0x10000000|(g_objpos-bpos-1); // beq zero,zero,xxxx | |
528 | + return 0; | |
529 | +} | |
530 | + | |
531 | +char* elseif_statement(void){ | |
532 | + // Multiple line mode | |
533 | + char* err; | |
534 | + g_object[g_objpos++]=0x08160100; // breakif (see linker) | |
535 | + g_object[g_objpos++]=0x30008000; // nop (see linker) | |
536 | + // Get value. | |
537 | + err=get_floatOrValue(); | |
538 | + if (err) return err; | |
539 | + // Check "THEN" | |
540 | + if (!nextCodeIs("THEN")) return ERR_SYNTAX; | |
541 | + // Check if statement follows after THEN statement | |
542 | + if (nextCodeIs("REM")) { | |
543 | + // If REM statement follows, skip comment words. | |
544 | + rem_statement(); | |
545 | + } | |
546 | + if (0x20<=g_source[g_srcpos]) return ERR_SYNTAX; | |
547 | + // Statement didn't follow after THEM statement (that is correct). | |
548 | + g_object[g_objpos++]=0x10400000; // beq v0,zero,xxxx | |
549 | + g_object[g_objpos++]=0x30000000; // nop (see linker) | |
550 | + return 0; | |
551 | + | |
552 | +} | |
553 | + | |
554 | +char* else_statement(void){ | |
555 | + // Multiple line mode | |
556 | + g_object[g_objpos++]=0x08160100; // breakif (see linker) | |
557 | + g_object[g_objpos++]=0x30008000; // nop (see linker) | |
558 | + g_object[g_objpos++]=0x30000000; // nop (see linker) | |
559 | + // Check if statement follows after THEN statement | |
560 | + if (nextCodeIs("REM")) { | |
561 | + // If REM statement follows, skip comment words. | |
562 | + rem_statement(); | |
563 | + } | |
564 | + if (0x20<=g_source[g_srcpos]) return ERR_SYNTAX; | |
565 | + // Statement didn't follow after THEM statement (that is correct). | |
566 | + return 0; | |
567 | +} | |
568 | + | |
569 | +char* endif_statement(void){ | |
570 | + // Multiple line mode | |
571 | + g_object[g_objpos++]=0x30008000; // nop (see linker) | |
572 | + g_object[g_objpos++]=0x30008000; // nop (see linker) | |
573 | + // Check if statement follows after THEN statement | |
574 | + if (nextCodeIs("REM")) { | |
575 | + // If REM statement follows, skip comment words. | |
576 | + rem_statement(); | |
577 | + } | |
578 | + if (0x20<=g_source[g_srcpos]) return ERR_SYNTAX; | |
579 | + // Statement didn't follow after THEM statement (that is correct). | |
580 | + return 0; | |
581 | +} | |
582 | + | |
583 | +char* end_statement(void){ | |
584 | + int i; | |
585 | + i=(int)&g_end_addr; | |
586 | + i-=g_gp; | |
587 | + check_obj_space(3); | |
588 | + g_object[g_objpos++]=0x8F820000|(i&0x0000FFFF); // lw v0,xxxx(gp) | |
589 | + g_object[g_objpos++]=0x00400008; // jr v0 | |
590 | + g_object[g_objpos++]=0x00000000; // nop | |
591 | + return 0; | |
592 | +} | |
593 | + | |
594 | +char* let_dim_sub(int i){ | |
595 | + char* err; | |
596 | + g_srcpos++; | |
597 | + err=get_value(); | |
598 | + if (err) return err; | |
599 | + check_obj_space(4); | |
600 | + g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
601 | + g_object[g_objpos++]=0x8FC30000|(i*4); // lw v1,xx(s8) | |
602 | + g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
603 | + g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp) | |
604 | + while(g_source[g_srcpos]==','){ | |
605 | + g_srcpos++; | |
606 | + err=get_value(); | |
607 | + if (err) return err; | |
608 | + check_obj_space(4); | |
609 | + g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
610 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
611 | + g_object[g_objpos++]=0x8C630000; // lw v1,0(v1) | |
612 | + g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
613 | + g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp) | |
614 | + } | |
615 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
616 | + g_srcpos++; | |
617 | + return 0; | |
618 | +}; | |
619 | + | |
620 | +char* let_statement(){ | |
621 | + char* err; | |
622 | + char b2,b3; | |
623 | + int i; | |
624 | + next_position(); | |
625 | + i=get_var_number(); | |
626 | + if (i<0) return ERR_SYNTAX; | |
627 | + b2=g_source[g_srcpos]; | |
628 | + b3=g_source[g_srcpos+1]; | |
629 | + if (b2=='#' && b3=='(') { | |
630 | + // Float dimension | |
631 | + g_srcpos++; | |
632 | + check_obj_space(1); | |
633 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
634 | + let_dim_sub(i); | |
635 | + next_position(); | |
636 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
637 | + g_srcpos++; | |
638 | + err=get_float(); | |
639 | + if (err) return err; | |
640 | + check_obj_space(3); | |
641 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
642 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
643 | + g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
644 | + return 0; | |
645 | + } else if (b2=='#') { | |
646 | + // Float A-Z | |
647 | + g_srcpos++; | |
648 | + next_position(); | |
649 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
650 | + g_srcpos++; | |
651 | + err=get_float(); | |
652 | + if (err) return err; | |
653 | + check_obj_space(1); | |
654 | + g_object[g_objpos++]=0xAFC20000|(i*4); // sw v0,xxx(s8) | |
655 | + return 0; | |
656 | + } else if (b2=='$') { | |
657 | + // String | |
658 | + g_srcpos++; | |
659 | + next_position(); | |
660 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
661 | + g_srcpos++; | |
662 | + err=get_string(); | |
663 | + if (err) return err; | |
664 | + check_obj_space(1); | |
665 | + g_object[g_objpos++]=0x24040000|(i); //addiu a0,zero,xx | |
666 | + call_lib_code(LIB_LETSTR); | |
667 | + return 0; | |
668 | + } else if (b2=='(') { | |
669 | + // Dimension | |
670 | + check_obj_space(1); | |
671 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
672 | + let_dim_sub(i); | |
673 | + next_position(); | |
674 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
675 | + g_srcpos++; | |
676 | + err=get_value(); | |
677 | + if (err) return err; | |
678 | + check_obj_space(3); | |
679 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
680 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
681 | + g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
682 | + return 0; | |
683 | + } else { | |
684 | + // Integer A-Z | |
685 | + next_position(); | |
686 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
687 | + g_srcpos++; | |
688 | + err=get_value(); | |
689 | + if (err) return err; | |
690 | + check_obj_space(1); | |
691 | + g_object[g_objpos++]=0xAFC20000|(i*4); // sw v0,xxx(s8) | |
692 | + } | |
693 | + return 0; | |
694 | +} | |
695 | + | |
696 | +char* print_statement_main(enum libs lib_printstr, enum libs lib_string){ | |
697 | + char* err; | |
698 | + char b1; | |
699 | + int i; | |
700 | + int status=0;// 1:',' 2:';' 0:none | |
701 | + while(1){ | |
702 | + next_position(); | |
703 | + if (endOfStatement()) break; | |
704 | + if (!strncmp(g_source+g_srcpos,"ELSE " ,5)) break; | |
705 | + err=get_stringFloatOrValue(); | |
706 | + if (err) return err; | |
707 | + switch(g_lastvar){ | |
708 | + case VAR_INTEGER: | |
709 | + // Use DEC$() function. | |
710 | + call_lib_code(LIB_DEC); | |
711 | + break; | |
712 | + case VAR_FLOAT: | |
713 | + // Use FLOAT$() function. | |
714 | + check_obj_space(2); | |
715 | + g_object[g_objpos++]=0x00022021; //addu a0,zero,v0 | |
716 | + g_object[g_objpos++]=0x34020000; //ori v0,zero,0x0000 | |
717 | + call_lib_code(LIB_SPRINTF); | |
718 | + break; | |
719 | + case VAR_STRING: | |
720 | + default: | |
721 | + break; | |
722 | + } | |
723 | + // Call printstr() function | |
724 | + // First argument is the pointer to string | |
725 | + call_lib_code(lib_printstr); | |
726 | + next_position(); | |
727 | + b1=g_source[g_srcpos]; | |
728 | + if (b1==',') { | |
729 | + status=1; | |
730 | + g_srcpos++; | |
731 | + // Call lib_string() function for comma (,) | |
732 | + check_obj_space(1); | |
733 | + g_object[g_objpos++]=0x34020001; // ori v0,zero,1 | |
734 | + call_lib_code(lib_string); | |
735 | + } else if (b1==';') { | |
736 | + status=2; | |
737 | + g_srcpos++; | |
738 | + } else { | |
739 | + status=0; | |
740 | + } | |
741 | + } | |
742 | + if (status==0) { | |
743 | + // Call lib_string() function for CR (\n) | |
744 | + check_obj_space(1); | |
745 | + g_object[g_objpos++]=0x34020000; // ori v0,zero,0 | |
746 | + call_lib_code(lib_string); | |
747 | + } | |
748 | + return 0; | |
749 | +} | |
750 | + | |
751 | +char* break_statement(){ | |
752 | + check_obj_space(2); | |
753 | + g_object[g_objpos++]=0x08160000; // j xxxx (See link() function) | |
754 | + g_object[g_objpos++]=0x00000000; // nop | |
755 | + return 0; | |
756 | +} | |
757 | + | |
758 | +char* continue_statement(){ | |
759 | + check_obj_space(2); | |
760 | + g_object[g_objpos++]=0x08160008; // j xxxx (See link() function) | |
761 | + g_object[g_objpos++]=0x00000000; // nop | |
762 | + return 0; | |
763 | +} | |
764 | + | |
765 | +char* for_statement(){ | |
766 | + char* err; | |
767 | +// char b1; | |
768 | + int i; | |
769 | + int prepos=g_srcpos; | |
770 | + // Initialization of variable | |
771 | +// next_position(); | |
772 | +// b1=g_source[g_srcpos]; | |
773 | + i=get_var_number(); | |
774 | +// if (b1<'A' || 'Z'<b1) return ERR_SYNTAX; | |
775 | + if (i<0) return ERR_SYNTAX; | |
776 | + g_srcpos=prepos; | |
777 | + err=let_statement(); | |
778 | + if (err) return err; | |
779 | + // Check if "TO" exists | |
780 | + if (!nextCodeIs("TO ")) return ERR_SYNTAX; | |
781 | + err=get_value(); | |
782 | + if (err) return err; | |
783 | + // Usage of stack: | |
784 | + // 12(sp): "TO" value | |
785 | + // 8(sp): "STEP" value | |
786 | + // 4(sp): Address to return to in "NEXT" statement. | |
787 | + // Store "TO" value in stack | |
788 | + check_obj_space(2); | |
789 | + g_object[g_objpos++]=0x0820FFF4; // addiu sp,sp,-12 (see linker) | |
790 | + g_object[g_objpos++]=0xAFA2000C; // sw v0,12(sp) | |
791 | + // Check if "STEP" exists | |
792 | + g_valueisconst=1; | |
793 | + if (nextCodeIs("STEP ")) { | |
794 | + // "STEP" exists. Get value | |
795 | + err=get_value(); | |
796 | + if (err) return err; | |
797 | + } else { | |
798 | + // "STEP" not exist. Use "1". | |
799 | + check_obj_space(1); | |
800 | + g_object[g_objpos++]=0x24020001; // addiu v0,zero,1 | |
801 | + g_intconst=1; | |
802 | + } | |
803 | + check_obj_space(14); | |
804 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) (STEP value) | |
805 | + g_object[g_objpos++]=0x04130004; // bgezall zero,check | |
806 | +// g_object[g_objpos++]=0x8FC40000|((b1-'A')*4); // lw a0,xx(s8) (current var value) | |
807 | + g_object[g_objpos++]=0x8FC40000|(i*4); // lw a0,xx(s8) (current var value) | |
808 | + // After executing "NEXT" statement, process reaches following line. | |
809 | + // Update variable value by adding STEP value | |
810 | + // Note that STEP value is loaded onto $v0 in NEXT statement | |
811 | +// g_object[g_objpos++]=0x8FC40000|((b1-'A')*4); // lw a0,xx(s8) (current var value) | |
812 | + g_object[g_objpos++]=0x8FC40000|(i*4); // lw a0,xx(s8) (current var value) | |
813 | + g_object[g_objpos++]=0x00822021; // addu a0,a0,v0 | |
814 | +// g_object[g_objpos++]=0xAFC40000|((b1-'A')*4); // sw a0,xx(s8) (new var value) | |
815 | + g_object[g_objpos++]=0xAFC40000|(i*4); // sw a0,xx(s8) (new var value) | |
816 | + // Value-checking routine and storing ra in stack | |
817 | + // check: | |
818 | + g_object[g_objpos++]=0x8FA3000C; // lw v1,12(sp) (TO value) | |
819 | + g_object[g_objpos++]=0x00641823; // subu v1,v1,a0 | |
820 | + g_object[g_objpos++]=0x04420001; // bltzl v0,negative | |
821 | + g_object[g_objpos++]=0x00031823; // subu v1,zero,v1 | |
822 | + // negative: | |
823 | + g_object[g_objpos++]=0x04610003; // bgez v1,continue | |
824 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
825 | + break_statement(); // (2 words) | |
826 | + // continue: | |
827 | + return 0; | |
828 | +} | |
829 | + | |
830 | +char* next_statement(){ | |
831 | + // Return to address stored in 4($sp) | |
832 | + // while set $v0 to 8($sp) (see for_statement) | |
833 | + // Following assembly must be 4 words. | |
834 | + // If the number of words will be changed, link.c must be reviced for CONTINUE statement. | |
835 | + check_obj_space(4); | |
836 | + g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
837 | + g_object[g_objpos++]=0x03E00008; // jr ra | |
838 | + g_object[g_objpos++]=0x8FA20008; // lw v0,8(sp) (STEP value) | |
839 | + g_object[g_objpos++]=0x0830000C; // addiu sp,sp,12 (see linker) | |
840 | + return 0; | |
841 | +} | |
842 | + | |
843 | +char* do_statement(){ | |
844 | + char* err; | |
845 | + // Usage of stack: | |
846 | + // 4(sp): Address to return to in "DO" statement. | |
847 | + check_obj_space(3); | |
848 | + g_object[g_objpos++]=0x04130001;// bgezall zero,label1: | |
849 | + g_object[g_objpos++]=0x0822FFFC;// addiu sp,sp,-4 (see linker) | |
850 | + // label1: | |
851 | + g_object[g_objpos++]=0xAFBF0004;// sw ra,4(sp) | |
852 | + if (nextCodeIs("WHILE ")) { | |
853 | + // DO WHILE | |
854 | + err=get_floatOrValue(); | |
855 | + if (err) return err; | |
856 | + check_obj_space(2); | |
857 | + g_object[g_objpos++]=0x14400003; // bne v0,zero,labe2 | |
858 | + g_object[g_objpos++]=0x00000000; // nop | |
859 | + return break_statement(); // (2 words) | |
860 | + // label2: | |
861 | + | |
862 | + } else if (nextCodeIs("UNTIL ")) { | |
863 | + // DO UNTIL | |
864 | + err=get_floatOrValue(); | |
865 | + if (err) return err; | |
866 | + check_obj_space(2); | |
867 | + g_object[g_objpos++]=0x10400003; // beq v0,zero,label2 | |
868 | + g_object[g_objpos++]=0x00000000; // nop | |
869 | + return break_statement(); // (2 words) | |
870 | + // label2: | |
871 | + } else { | |
872 | + // DO statement without WHILE/UNTIL | |
873 | + return 0; | |
874 | + } | |
875 | +} | |
876 | + | |
877 | +char* loop_statement(){ | |
878 | + char* err; | |
879 | + int opos; | |
880 | + opos=g_objpos; | |
881 | + if (nextCodeIs("WHILE ")) { | |
882 | + // LOOP WHILE | |
883 | + err=get_floatOrValue(); | |
884 | + if (err) return err; | |
885 | + check_obj_space(1); | |
886 | + g_object[g_objpos++]=0x10400003; // beq v0,zero,label1 | |
887 | + } else if (nextCodeIs("UNTIL ")) { | |
888 | + // LOOP UNTIL | |
889 | + err=get_floatOrValue(); | |
890 | + if (err) return err; | |
891 | + check_obj_space(1); | |
892 | + g_object[g_objpos++]=0x14400003; // bne v0,zero,label | |
893 | + } else { | |
894 | + // LOOP statement without WHILE/UNTIL | |
895 | + } | |
896 | + check_obj_space(4); | |
897 | + g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
898 | + g_object[g_objpos++]=0x03E00008; // jr ra | |
899 | + opos=g_objpos+1-opos; | |
900 | + g_object[g_objpos++]=0x3000F000|opos; // nop (See linker, used for CONTINUE statement) | |
901 | + // label1: | |
902 | + g_object[g_objpos++]=0x08320004; // addiu sp,sp,4 (See link() function) | |
903 | + return 0; | |
904 | +} | |
905 | + | |
906 | +char* while_statement(){ | |
907 | + char* err; | |
908 | + check_obj_space(3); | |
909 | + g_object[g_objpos++]=0x04130001; // bgezall zero,label1: | |
910 | + g_object[g_objpos++]=0x0821FFFC; // addiu sp,sp,-4 (see linker) | |
911 | + // label1: | |
912 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
913 | + err=get_floatOrValue(); | |
914 | + if (err) return err; | |
915 | + check_obj_space(2); | |
916 | + g_object[g_objpos++]=0x14400003; // bne v0,zero,label2 | |
917 | + g_object[g_objpos++]=0x00000000; // nop | |
918 | + return break_statement(); // (2 words) | |
919 | + // label2: | |
920 | +} | |
921 | + | |
922 | +char* wend_statement(){ | |
923 | + check_obj_space(4); | |
924 | + g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
925 | + g_object[g_objpos++]=0x03E00008; // jr ra | |
926 | + g_object[g_objpos++]=0x3000F003; // nop (See linker, used for CONTINUE statement) | |
927 | + // label1: | |
928 | + g_object[g_objpos++]=0x08310004; // addiu sp,sp,4 (See link() function) | |
929 | + return 0; | |
930 | +} | |
931 | + | |
932 | +char* param4_statement(enum libs lib){ | |
933 | + // lib is either LIB_PALETTE or LIB_GPALETTE | |
934 | + // PALETTE N,R,G,B | |
935 | + char* err; | |
936 | + // Get N | |
937 | + err=get_value(); | |
938 | + if (err) return err; | |
939 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
940 | + g_srcpos++; | |
941 | + check_obj_space(2); | |
942 | + g_object[g_objpos++]=0x27BDFFF4; // addiu sp,sp,-12 | |
943 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
944 | + // Get R | |
945 | + err=get_value(); | |
946 | + if (err) return err; | |
947 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
948 | + g_srcpos++; | |
949 | + check_obj_space(1); | |
950 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
951 | + // Get G | |
952 | + err=get_value(); | |
953 | + if (err) return err; | |
954 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
955 | + g_srcpos++; | |
956 | + check_obj_space(1); | |
957 | + g_object[g_objpos++]=0xAFA2000C; // sw v0,12(sp) | |
958 | + // Get B | |
959 | + err=get_value(); | |
960 | + if (err) return err; | |
961 | + call_lib_code(lib); | |
962 | + check_obj_space(1); | |
963 | + g_object[g_objpos++]=0x27BD000C; // addiu sp,sp,12 | |
964 | + return 0; | |
965 | +} | |
966 | + | |
967 | +char* param3_statement(enum libs lib){ | |
968 | + char* err; | |
969 | + // Get 1st parameter | |
970 | + err=get_value(); | |
971 | + if (err) return err; | |
972 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
973 | + g_srcpos++; | |
974 | + check_obj_space(2); | |
975 | + g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
976 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
977 | + // Get 2nd parameter | |
978 | + err=get_value(); | |
979 | + if (err) return err; | |
980 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
981 | + g_srcpos++; | |
982 | + check_obj_space(1); | |
983 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
984 | + // Get 3rd parameter | |
985 | + err=get_value(); | |
986 | + if (err) return err; | |
987 | + call_lib_code(lib); | |
988 | + check_obj_space(1); | |
989 | + g_object[g_objpos++]=0x27BD0008; // addiu sp,sp,8 | |
990 | + return 0; | |
991 | +} | |
992 | + | |
993 | +char* bgcolor_statement(){ | |
994 | + // BGCOLOR R,G,B | |
995 | + return param3_statement(LIB_BGCOLOR); | |
996 | +} | |
997 | + | |
998 | +char* pcg_statement(){ | |
999 | + // PCG ASCII,D1,D2 | |
1000 | + return param3_statement(LIB_PCG); | |
1001 | +} | |
1002 | + | |
1003 | +char* usepcg_statement(){ | |
1004 | + int objpos=g_objpos; | |
1005 | + if (get_value()) { | |
1006 | + // Getting integer failed. | |
1007 | + // It supporsed to be not parameter | |
1008 | + // and same as parameter=1. | |
1009 | + g_objpos=objpos; | |
1010 | + check_obj_space(1); | |
1011 | + g_object[g_objpos++]=0x34020001; //ori v0,zero,0x01 | |
1012 | + } | |
1013 | + call_lib_code(LIB_USEPCG); | |
1014 | + return 0; | |
1015 | +} | |
1016 | + | |
1017 | +char* usegraphic_statement(){ | |
1018 | + int objpos=g_objpos; | |
1019 | + if (get_value()) { | |
1020 | + // Getting integer failed. | |
1021 | + // It supporsed to be not parameter | |
1022 | + // and same as parameter=1. | |
1023 | + g_objpos=objpos; | |
1024 | + check_obj_space(1); | |
1025 | + g_object[g_objpos++]=0x34020001; //ori v0,zero,0x01 | |
1026 | + } | |
1027 | + call_lib_code(LIB_USEGRAPHIC); | |
1028 | + return 0; | |
1029 | +} | |
1030 | + | |
1031 | +char* cls_statement(){ | |
1032 | + call_lib_code(LIB_CLS); | |
1033 | + return 0; | |
1034 | +} | |
1035 | + | |
1036 | +char* gcls_statement(){ | |
1037 | + call_lib_code(LIB_GCLS); | |
1038 | + return 0; | |
1039 | +} | |
1040 | + | |
1041 | +char* color_statement(){ | |
1042 | + char* err; | |
1043 | + err=get_value(); | |
1044 | + if (err) return err; | |
1045 | + call_lib_code(LIB_COLOR); | |
1046 | + return 0; | |
1047 | +} | |
1048 | + | |
1049 | +char* gcolor_statement(){ | |
1050 | + char* err; | |
1051 | + err=get_value(); | |
1052 | + if (err) return err; | |
1053 | + call_lib_code(LIB_GCOLOR); | |
1054 | + return 0; | |
1055 | +} | |
1056 | + | |
1057 | +char* param2_statement(enum libs lib){ | |
1058 | + char* err; | |
1059 | + // Get 1st | |
1060 | + err=get_value(); | |
1061 | + if (err) return err; | |
1062 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1063 | + g_srcpos++; | |
1064 | + check_obj_space(2); | |
1065 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
1066 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1067 | + // Get 2nd | |
1068 | + err=get_value(); | |
1069 | + if (err) return err; | |
1070 | + call_lib_code(lib); | |
1071 | + check_obj_space(1); | |
1072 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
1073 | + return 0; | |
1074 | +} | |
1075 | + | |
1076 | +char* system_statement(){ | |
1077 | + // SYSTEM X,Y | |
1078 | + char* err; | |
1079 | + // Get 1st | |
1080 | + err=get_value(); | |
1081 | + if (err) return err; | |
1082 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1083 | + g_srcpos++; | |
1084 | + check_obj_space(2); | |
1085 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
1086 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1087 | + // Get 2nd | |
1088 | + err=get_value(); | |
1089 | + if (err) return err; | |
1090 | + check_obj_space(2); | |
1091 | + g_object[g_objpos++]=0x8FA40004; // lw a0,4(sp) | |
1092 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
1093 | + call_lib_code(LIB_SYSTEM); | |
1094 | + return 0; | |
1095 | +} | |
1096 | + | |
1097 | +char* cursor_statement(){ | |
1098 | + // CURSOR X,Y | |
1099 | + return param2_statement(LIB_CURSOR); | |
1100 | +} | |
1101 | + | |
1102 | +char* scroll_statement(){ | |
1103 | + // SCROLL X,Y | |
1104 | + return param2_statement(LIB_SCROLL); | |
1105 | +} | |
1106 | + | |
1107 | +char* drawcount_statement(){ | |
1108 | + char* err; | |
1109 | + err=get_value(); | |
1110 | + if (err) return err; | |
1111 | + call_lib_code(LIB_SETDRAWCOUNT); | |
1112 | + return 0; | |
1113 | +} | |
1114 | + | |
1115 | +char* wait_statement(){ | |
1116 | + char* err; | |
1117 | + err=get_value(); | |
1118 | + if (err) return err; | |
1119 | + call_lib_code(LIB_WAIT); | |
1120 | + return 0; | |
1121 | +} | |
1122 | + | |
1123 | +char* width_statement(){ | |
1124 | + char* err; | |
1125 | + err=get_value(); | |
1126 | + if (err) return err; | |
1127 | + call_lib_code(LIB_WIDTH); | |
1128 | + return 0; | |
1129 | +} | |
1130 | + | |
1131 | +char* var_statement_sub(int a0, int a1){ | |
1132 | + // Construct parameter-setting scripts | |
1133 | + if (a0&0xffff0000) { | |
1134 | + check_obj_space(1); | |
1135 | + g_object[g_objpos++]=0x3C040000|(a0>>16); // lui a0,XXXX | |
1136 | + if (a0&0x0000ffff) { | |
1137 | + check_obj_space(1); | |
1138 | + g_object[g_objpos++]=0x34840000|(a0&0xffff); // ori a0,a0,XXXX | |
1139 | + } | |
1140 | + } else if (a0&0x0000ffff) { | |
1141 | + check_obj_space(1); | |
1142 | + g_object[g_objpos++]=0x34040000|(a0&0xffff); // ori a0,zero,xxxx | |
1143 | + } | |
1144 | + if (a1&0xffff0000) { | |
1145 | + check_obj_space(1); | |
1146 | + g_object[g_objpos++]=0x3C050000|(a1>>16); // lui a1,XXXX | |
1147 | + if (a1&0x0000ffff) { | |
1148 | + check_obj_space(1); | |
1149 | + g_object[g_objpos++]=0x34A50000|(a1&0xffff); // ori a1,a1,XXXX | |
1150 | + } | |
1151 | + } else if (a1&0x0000ffff) { | |
1152 | + check_obj_space(1); | |
1153 | + g_object[g_objpos++]=0x34050000|(a1&0xffff); // ori a1,zero,xxxx | |
1154 | + } else if (a0&0xff000000) { | |
1155 | + // # of variables is 4. Reset $a1 to let lib_var() know that there is no more variables to store. | |
1156 | + check_obj_space(1); | |
1157 | + g_object[g_objpos++]=0x34050000; // ori a1,zero,0 | |
1158 | + } | |
1159 | + return 0; | |
1160 | +} | |
1161 | + | |
1162 | +char* var_statement(){ | |
1163 | + char* err; | |
1164 | + int i,j,a0,a1; | |
1165 | + static int prevpos; | |
1166 | + short stack; | |
1167 | + do { | |
1168 | + // For stack, 4 bytes are used for return address, | |
1169 | + // 4 bytes are used in lib_var(), | |
1170 | + // and additinal bytes are used for storing variable values. | |
1171 | + stack=8; | |
1172 | + a0=a1=0; | |
1173 | + for (i=0;i<8;i++){ | |
1174 | + // Determine the variable number from source code | |
1175 | + j=get_var_number(); | |
1176 | + if (j<0) return ERR_SYNTAX; | |
1177 | + stack+=4; | |
1178 | + // Create parameters in $a0, or $a1 | |
1179 | + if (i<4) { | |
1180 | + a0=(a0<<8)|(j+1); | |
1181 | + } else { | |
1182 | + a1=(a1<<8)|(j+1); | |
1183 | + } | |
1184 | + // Check remaining variable(s) | |
1185 | + if (g_source[g_srcpos]=='#' || g_source[g_srcpos]=='$') g_srcpos++; | |
1186 | + next_position(); | |
1187 | + if (g_source[g_srcpos]!=',') break; | |
1188 | + g_srcpos++; | |
1189 | + } | |
1190 | + // Jump to push routine, first | |
1191 | + check_obj_space(2); | |
1192 | + prevpos=g_objpos; | |
1193 | + g_object[g_objpos++]=0x04130000; // bgezall zero,label1 | |
1194 | + g_object[g_objpos++]=0x27BD0000|((0-stack)&0xffff); // addiu sp,sp,-xx | |
1195 | + // Process will be here after RETURN statement | |
1196 | + // Pop routine | |
1197 | + err=var_statement_sub(a0,a1); // Prepare a0, and a1 | |
1198 | + if (err) return err; | |
1199 | + call_lib_code(LIB_VAR_POP); | |
1200 | + // Restore stack and return | |
1201 | + check_obj_space(3); | |
1202 | + g_object[g_objpos++]=0x8FA30000|stack; // lw v1,xx(sp) | |
1203 | + g_object[g_objpos++]=0x00600008; // jr v1 | |
1204 | + g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xx | |
1205 | + // Push rotine | |
1206 | + g_object[prevpos]|=g_objpos-prevpos-1; // label1: | |
1207 | + check_obj_space(1); | |
1208 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
1209 | + err=var_statement_sub(a0,a1); // Prepare a0, and a1 | |
1210 | + if (err) return err; | |
1211 | + call_lib_code(LIB_VAR_PUSH); | |
1212 | + | |
1213 | + } while (g_source[g_srcpos-1]==','); | |
1214 | + return 0; | |
1215 | +} | |
1216 | + | |
1217 | + | |
1218 | +char* graphic_statement(enum functions func){ | |
1219 | + /* | |
1220 | + PSET X1,Y1[,C] | |
1221 | + LINE X1,Y1,X2,Y2[,C] | |
1222 | + BOXFILL X1,Y1,X2,Y2[,C] | |
1223 | + CIRCLE X1,Y1,R[,C] | |
1224 | + CIRCLEFILL X1,Y1,R[,C] | |
1225 | + GPRINT X1,Y1,C,BC,S$ | |
1226 | + PUTBMP X1,Y1,M,N,BMP | |
1227 | + 4(sp): X1 | |
1228 | + 8(sp): Y1 | |
1229 | + 12(sp): X2/R/M | |
1230 | + 16(sp): Y2/N | |
1231 | + v0: C/S$/BMP | |
1232 | + */ | |
1233 | + char* err; | |
1234 | + int paramnum; | |
1235 | + switch(func){ | |
1236 | + case FUNC_PSET:// X1,Y1[,C] | |
1237 | + case FUNC_GCOLOR:// X1,Y1 | |
1238 | + case FUNC_POINT:// X1,Y1 | |
1239 | + paramnum=2; | |
1240 | + break; | |
1241 | + case FUNC_CIRCLE:// X1,Y1,R[,C] | |
1242 | + case FUNC_CIRCLEFILL:// X1,Y1,R[,C] | |
1243 | + paramnum=3; | |
1244 | + break; | |
1245 | + case FUNC_LINE:// X1,Y1,X2,Y2[,C] | |
1246 | + case FUNC_BOXFILL:// X1,Y1,X2,Y2[,C] | |
1247 | + paramnum=4; | |
1248 | + break; | |
1249 | + case FUNC_GPRINT:// X1,Y1,C,BC,S$ | |
1250 | + case FUNC_PUTBMP:// X1,Y1,M,N,BMP | |
1251 | + paramnum=5; | |
1252 | + break; | |
1253 | + default: | |
1254 | + return ERR_UNKNOWN; | |
1255 | + } | |
1256 | + | |
1257 | + next_position(); | |
1258 | + if (g_source[g_srcpos]==',') { | |
1259 | + // X1 and Y1 is omitted. Set 0x80000000 for both. | |
1260 | + check_obj_space(4); | |
1261 | + g_object[g_objpos++]=0x27BDFFF0; // addiu sp,sp,-16 | |
1262 | + g_object[g_objpos++]=0x3C028000; // lui v0,0x0080 | |
1263 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1264 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
1265 | + } else { | |
1266 | + // X1 | |
1267 | + err=get_value(); | |
1268 | + if (err) return err; | |
1269 | + check_obj_space(2); | |
1270 | + g_object[g_objpos++]=0x27BDFFF0; // addiu sp,sp,-16 | |
1271 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1272 | + // Y1 | |
1273 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1274 | + g_srcpos++; | |
1275 | + err=get_value(); | |
1276 | + if (err) return err; | |
1277 | + check_obj_space(1); | |
1278 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
1279 | + } | |
1280 | + if (2<paramnum) { | |
1281 | + // X2, R, or M | |
1282 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1283 | + g_srcpos++; | |
1284 | + err=get_value(); | |
1285 | + if (err) return err; | |
1286 | + check_obj_space(1); | |
1287 | + g_object[g_objpos++]=0xAFA2000C; // sw v0,12(sp) | |
1288 | + if (3<paramnum) { | |
1289 | + // Y2, BC, or N | |
1290 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1291 | + g_srcpos++; | |
1292 | + err=get_value(); | |
1293 | + if (err) return err; | |
1294 | + check_obj_space(1); | |
1295 | + g_object[g_objpos++]=0xAFA20010; // sw v0,16(sp) | |
1296 | + } | |
1297 | + } | |
1298 | + if (func==FUNC_GPRINT) { | |
1299 | + // S$ | |
1300 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1301 | + g_srcpos++; | |
1302 | + err=get_string(); | |
1303 | + if (err) return err; | |
1304 | + } else if (func==FUNC_PUTBMP) { | |
1305 | + // BMP | |
1306 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1307 | + g_srcpos++; | |
1308 | + err=get_label(); | |
1309 | + if (g_label && !err) { | |
1310 | + // Label/number is constant. | |
1311 | + // Linker will change following codes later. | |
1312 | + // Note that 0x0814xxxx and 0x0815xxxx are specific codes for these. | |
1313 | + check_obj_space(2); | |
1314 | + g_object[g_objpos++]=0x08140000|((g_label>>16)&0x0000FFFF); // lui v0,xxxx | |
1315 | + g_object[g_objpos++]=0x08150000|(g_label&0x0000FFFF); // ori v0,v0,xxxx | |
1316 | + // Change func to FUNC_PUTBMP2 (label mode). | |
1317 | + func=FUNC_PUTBMP2; | |
1318 | + } else { | |
1319 | + err=get_value(); | |
1320 | + if (err) return err; | |
1321 | + } | |
1322 | + } else { | |
1323 | + // [,C] | |
1324 | + if (g_source[g_srcpos]==',') { | |
1325 | + g_srcpos++; | |
1326 | + err=get_value(); | |
1327 | + if (err) return err; | |
1328 | + } else { | |
1329 | + // If C is omitted, use -1. | |
1330 | + check_obj_space(1); | |
1331 | + g_object[g_objpos++]=0x2402FFFF; // addiu v0,zero,-1 | |
1332 | + } | |
1333 | + } | |
1334 | + // Call library | |
1335 | + call_lib_code(LIB_GRAPHIC | func); | |
1336 | + // Restore stack pointer | |
1337 | + check_obj_space(1); | |
1338 | + g_object[g_objpos++]=0x27BD0010; // addiu sp,sp,16 | |
1339 | + return 0; | |
1340 | +} | |
1341 | + | |
1342 | +char* fopen_statement_main(enum functions func){ | |
1343 | + // func is either FUNC_FOPENST or FUNC_FOPEN | |
1344 | + char* err; | |
1345 | + // Get 1st | |
1346 | + err=get_string(); | |
1347 | + if (err) return err; | |
1348 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1349 | + g_srcpos++; | |
1350 | + check_obj_space(2); | |
1351 | + g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
1352 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1353 | + // Get 2nd | |
1354 | + err=get_string(); | |
1355 | + if (err) return err; | |
1356 | + check_obj_space(1); | |
1357 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
1358 | + // Get 3rd | |
1359 | + if (g_source[g_srcpos]==',') { | |
1360 | + g_srcpos++; | |
1361 | + err=get_value(); | |
1362 | + if (err) return err; | |
1363 | + } else { | |
1364 | + // If 3rd parameter is omitted, use 0. | |
1365 | + check_obj_space(1); | |
1366 | + g_object[g_objpos++]=0x24020000; // addiu v0,zero,0 | |
1367 | + } | |
1368 | + call_lib_code(LIB_FILE | func); | |
1369 | + check_obj_space(1); | |
1370 | + g_object[g_objpos++]=0x27BD0008; // addiu sp,sp,8 | |
1371 | + return 0; | |
1372 | +} | |
1373 | + | |
1374 | +char* file_statement(){ | |
1375 | + char* err; | |
1376 | + err=get_value(); | |
1377 | + if (err) return err; | |
1378 | + call_lib_code(LIB_FILE | FUNC_FILE); | |
1379 | + return 0; | |
1380 | +} | |
1381 | + | |
1382 | +char* fclose_statement(){ | |
1383 | + char* err; | |
1384 | + int orgpos=g_srcpos; | |
1385 | + if (endOfStatement()) { | |
1386 | + // If no argument, use 0 | |
1387 | + check_obj_space(1); | |
1388 | + g_object[g_objpos++]=0x24020000; // addiu v0,zero,0 | |
1389 | + } else { | |
1390 | + err=get_value(); | |
1391 | + if (err) return err; | |
1392 | + } | |
1393 | + call_lib_code(LIB_FILE | FUNC_FCLOSE); | |
1394 | + return 0; | |
1395 | +} | |
1396 | + | |
1397 | +char* fget_statement(){ | |
1398 | + return param2_statement(LIB_FILE | FUNC_FGET); | |
1399 | +} | |
1400 | + | |
1401 | +char* fput_statement(){ | |
1402 | + return param2_statement(LIB_FILE | FUNC_FPUT); | |
1403 | +} | |
1404 | + | |
1405 | +char* fseek_statement(){ | |
1406 | + char* err; | |
1407 | + err=get_value(); | |
1408 | + if (err) return err; | |
1409 | + call_lib_code(LIB_FILE | FUNC_FSEEK); | |
1410 | + return 0; | |
1411 | +} | |
1412 | + | |
1413 | +char* fputc_statement(){ | |
1414 | + char* err; | |
1415 | + err=get_value(); | |
1416 | + if (err) return err; | |
1417 | + call_lib_code(LIB_FILE | FUNC_FPUTC); | |
1418 | + return 0; | |
1419 | +} | |
1420 | + | |
1421 | +char* fremove_statement(){ | |
1422 | + char* err; | |
1423 | + err=get_string(); | |
1424 | + if (err) return err; | |
1425 | + call_lib_code(LIB_FILE | FUNC_FREMOVE); | |
1426 | + return 0; | |
1427 | +} | |
1428 | + | |
1429 | +char* usevar_statement(){ | |
1430 | + char* err; | |
1431 | + int i; | |
1432 | + do { | |
1433 | + next_position(); | |
1434 | + i=check_var_name(); | |
1435 | + if (i<65536) return ERR_SYNTAX; | |
1436 | + err=register_var_name(i); | |
1437 | + if (err) return err; | |
1438 | + if (g_source[g_srcpos]=='#' || g_source[g_srcpos]=='$') g_srcpos++; | |
1439 | + next_position(); | |
1440 | + if (g_source[g_srcpos]==',') { | |
1441 | + g_srcpos++; | |
1442 | + } else { | |
1443 | + break; | |
1444 | + } | |
1445 | + } while(1); | |
1446 | + return 0; | |
1447 | +} | |
1448 | + | |
1449 | +char* playwave_statement(){ | |
1450 | + char* err; | |
1451 | + err=get_string(); | |
1452 | + if (err) return err; | |
1453 | + check_obj_space(2); | |
1454 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
1455 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1456 | + if (g_source[g_srcpos]==',') { | |
1457 | + g_srcpos++; | |
1458 | + // Get 2nd | |
1459 | + err=get_value(); | |
1460 | + if (err) return err; | |
1461 | + } else { | |
1462 | + // If 2rd parameter is omitted, use 0. | |
1463 | + check_obj_space(1); | |
1464 | + g_object[g_objpos++]=0x24020000; // addiu v0,zero,0 | |
1465 | + } | |
1466 | + call_lib_code(LIB_PLAYWAVE); | |
1467 | + check_obj_space(1); | |
1468 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
1469 | + return 0; | |
1470 | +} | |
1471 | + | |
1472 | +#ifdef __DEBUG | |
1473 | + char* debug_statement(){ | |
1474 | + call_lib_code(LIB_DEBUG); | |
1475 | + return 0; | |
1476 | + } | |
1477 | +#endif | |
1478 | + | |
1479 | +// Aliases follow | |
1480 | + | |
1481 | +char* palette_statement(){ | |
1482 | + return param4_statement(LIB_PALETTE); | |
1483 | +} | |
1484 | + | |
1485 | +char* gpalette_statement(){ | |
1486 | + return param4_statement(LIB_GPALETTE); | |
1487 | +} | |
1488 | + | |
1489 | +char* print_statement(){ | |
1490 | + return print_statement_main(LIB_PRINTSTR,LIB_STRING); | |
1491 | +} | |
1492 | + | |
1493 | +char* pset_statement(){ | |
1494 | + return graphic_statement(FUNC_PSET); | |
1495 | +} | |
1496 | + | |
1497 | +char* line_statement(){ | |
1498 | + return graphic_statement(FUNC_LINE); | |
1499 | +} | |
1500 | + | |
1501 | +char* boxfill_statement(){ | |
1502 | + return graphic_statement(FUNC_BOXFILL); | |
1503 | +} | |
1504 | + | |
1505 | +char* circle_statement(){ | |
1506 | + return graphic_statement(FUNC_CIRCLE); | |
1507 | +} | |
1508 | + | |
1509 | +char* circlefill_statement(){ | |
1510 | + return graphic_statement(FUNC_CIRCLEFILL); | |
1511 | +} | |
1512 | + | |
1513 | +char* gprint_statement(){ | |
1514 | + return graphic_statement(FUNC_GPRINT); | |
1515 | +} | |
1516 | + | |
1517 | +char* putbmp_statement(){ | |
1518 | + return graphic_statement(FUNC_PUTBMP); | |
1519 | +} | |
1520 | + | |
1521 | +char* point_statement(){ | |
1522 | + return graphic_statement(FUNC_POINT); | |
1523 | +} | |
1524 | + | |
1525 | +char* fopen_statement(){ | |
1526 | + return fopen_statement_main(FUNC_FOPENST); | |
1527 | +} | |
1528 | + | |
1529 | +char* fprint_statement(){ | |
1530 | + return print_statement_main(LIB_FILE | FUNC_FPRINTSTR,LIB_FILE | FUNC_FSTRING); | |
1531 | +} | |
1532 | + | |
1533 | +static const void* statement_list[]={ | |
1534 | + "REM",rem_statement, | |
1535 | + "SOUND ",sound_statement, | |
1536 | + "MUSIC ",music_statement, | |
1537 | + "DRAWCOUNT ",drawcount_statement, | |
1538 | + "CURSOR ",cursor_statement, | |
1539 | + "PALETTE ",palette_statement, | |
1540 | + "GPALETTE ",gpalette_statement, | |
1541 | + "BGCOLOR ",bgcolor_statement, | |
1542 | + "CLS",cls_statement, | |
1543 | + "GCLS",gcls_statement, | |
1544 | + "COLOR ",color_statement, | |
1545 | + "GCOLOR ",gcolor_statement, | |
1546 | + "RESTORE ",restore_statement, | |
1547 | + "DATA ",data_statement, | |
1548 | + "CDATA ",cdata_statement, | |
1549 | + "LABEL ",label_statement, | |
1550 | + "DIM ",dim_statement, | |
1551 | + "CLEAR",clear_statement, | |
1552 | + "PRINT",print_statement, | |
1553 | + "IF ",if_statement, | |
1554 | + "ELSEIF ",elseif_statement, | |
1555 | + "ELSE",else_statement, | |
1556 | + "ENDIF",endif_statement, | |
1557 | + "END",end_statement, | |
1558 | + "EXEC ",exec_statement, | |
1559 | + "GOTO ",goto_statement, | |
1560 | + "GOSUB ",gosub_statement, | |
1561 | + "RETURN",return_statement, | |
1562 | + "POKE ",poke_statement, | |
1563 | + "FOR ",for_statement, | |
1564 | + "NEXT",next_statement, | |
1565 | + "LET ",let_statement, | |
1566 | + "PCG ",pcg_statement, | |
1567 | + "USEPCG",usepcg_statement, | |
1568 | + "SCROLL ",scroll_statement, | |
1569 | + "WAIT ",wait_statement, | |
1570 | + "USEGRAPHIC",usegraphic_statement, | |
1571 | + "PSET ",pset_statement, | |
1572 | + "LINE ",line_statement, | |
1573 | + "BOXFILL ",boxfill_statement, | |
1574 | + "CIRCLE ",circle_statement, | |
1575 | + "CIRCLEFILL ",circlefill_statement, | |
1576 | + "GPRINT ",gprint_statement, | |
1577 | + "PUTBMP ",putbmp_statement, | |
1578 | + "POINT ",point_statement, | |
1579 | + "VAR ",var_statement, | |
1580 | + "DO",do_statement, | |
1581 | + "LOOP",loop_statement, | |
1582 | + "WHILE ",while_statement, | |
1583 | + "WEND",wend_statement, | |
1584 | + "BREAK",break_statement, | |
1585 | + "CONTINUE",continue_statement, | |
1586 | + "SYSTEM",system_statement, | |
1587 | + "WIDTH ",width_statement, | |
1588 | + "FOPEN ",fopen_statement, | |
1589 | + "FILE ",file_statement, | |
1590 | + "FCLOSE",fclose_statement, | |
1591 | + "FPRINT ",fprint_statement, | |
1592 | + "FGET ",fget_statement, | |
1593 | + "FPUT ",fput_statement, | |
1594 | + "FPUTC ",fputc_statement, | |
1595 | + "FSEEK ",fseek_statement, | |
1596 | + "FREMOVE ",fremove_statement, | |
1597 | + "USEVAR ",usevar_statement, | |
1598 | + "PLAYWAVE ",playwave_statement, | |
1599 | + // List of additional statements follows | |
1600 | + ADDITIONAL_STATEMENTS | |
1601 | +}; | |
1602 | + | |
1603 | +char* statement(void){ | |
1604 | + char* err; | |
1605 | + int prevpos; | |
1606 | + int i; | |
1607 | + char* (*f)(); | |
1608 | + // Clear flag for temp area usage. | |
1609 | + g_temp_area_used=0; | |
1610 | + // Initialize stack handler used for value | |
1611 | + g_sdepth=g_maxsdepth=0; | |
1612 | + // Seek the statement | |
1613 | + for (i=0;i<sizeof(statement_list)/sizeof(statement_list[0]);i+=2){ | |
1614 | + if (nextCodeIs((char*)statement_list[i])) break; | |
1615 | + } | |
1616 | + if (i<sizeof(statement_list)/sizeof(statement_list[0])) { | |
1617 | + // Statement found. Call it. | |
1618 | + f=statement_list[i+1]; | |
1619 | + err=f(); | |
1620 | +#ifdef __DEBUG | |
1621 | + } else if (nextCodeIs("DEBUG")) { | |
1622 | + err=debug_statement(); | |
1623 | +#endif | |
1624 | + } else { | |
1625 | + err=let_statement(); | |
1626 | + } | |
1627 | + if (err) return err; | |
1628 | + // Stack handler must be zero here. | |
1629 | + if (g_sdepth!=0) return ERR_UNKNOWN; | |
1630 | + // Check if temp area is used | |
1631 | + if (g_temp_area_used) { | |
1632 | + // Temp area is used. Insert a garbage collection flag setting routine. | |
1633 | + check_obj_space(1); | |
1634 | + g_object[g_objpos++]=0x7ED6F000;// ext s6,s6,0,31 | |
1635 | + } | |
1636 | + return 0; | |
1637 | +} |
@@ -0,0 +1,170 @@ | ||
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 | + "Invalid parameter(s)", | |
30 | + "File error", | |
31 | + "Invalid variable name", | |
32 | + "WAVE format error", | |
33 | +}; | |
34 | + | |
35 | +char* resolve_label(int s6){ | |
36 | + static char str[7]; | |
37 | + int i,j; | |
38 | + if (s6<65536) { | |
39 | + // Line number | |
40 | + for(i=0;i<5;i++){ | |
41 | + str[5-i]='0'+rem10_32(s6); | |
42 | + s6=div10_32(s6); | |
43 | + } | |
44 | + str[6]=0x00; | |
45 | + for(j=1;j<5;j++){ | |
46 | + if (str[j]!='0') break; | |
47 | + } | |
48 | + return (char*)(str+j); | |
49 | + } else { | |
50 | + // Label | |
51 | + s6-=65536; | |
52 | + str[6]=0x00; | |
53 | + for(i=5;0<=i;i--){ | |
54 | + if (s6<36) { | |
55 | + // First character must be A-Z, corresponding to 1-26 but not 10-35. | |
56 | + // See get_label() for the detail. | |
57 | + str[i]=s6-1+'A'; | |
58 | + break; | |
59 | + } else { | |
60 | + // From second, 0-9 corresponds to 0-9 and A-Z corresponds to 10-35. | |
61 | + str[i]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[rem36_32(s6)]; | |
62 | + s6=div36_32(s6); | |
63 | + } | |
64 | + } | |
65 | + return (char*)(str+i); | |
66 | + } | |
67 | +} | |
68 | + | |
69 | +void pre_end_addr(int s6){ | |
70 | + int i,j; | |
71 | + char str[7]; | |
72 | + // Cool down the system | |
73 | + stop_music(); | |
74 | + // Resolve line and show it | |
75 | + if (s6<0) s6=s6&0x7fffffff; | |
76 | + g_label=s6; | |
77 | + if (s6<65536) { | |
78 | + // Line number | |
79 | + printstr("\nIn line "); | |
80 | + } else { | |
81 | + // Label | |
82 | + printstr("\nAfter label "); | |
83 | + } | |
84 | + printstr(resolve_label(s6)); | |
85 | + asm volatile("la $v0,%0"::"i"(&g_end_addr)); | |
86 | + asm volatile("lw $v0,0($v0)"); | |
87 | + asm volatile("nop"); | |
88 | + asm volatile("jr $v0"); | |
89 | +} | |
90 | + | |
91 | +#define end_exec() \ | |
92 | + asm volatile("addu $a0,$s6,$zero");\ | |
93 | + asm volatile("j pre_end_addr") | |
94 | + | |
95 | +void err_break(void){ | |
96 | + stop_music(); | |
97 | + printstr(ERR_BREAK); | |
98 | + end_exec(); | |
99 | +} | |
100 | + | |
101 | +void err_data_not_found(void){ | |
102 | + printstr(ERR_DATA_NF); | |
103 | + end_exec(); | |
104 | +} | |
105 | + | |
106 | +void err_label_not_found(void){ | |
107 | + printstr(ERR_LABEL_NF); | |
108 | + printstr(resolve_label(g_label)); | |
109 | + printstr("\n"); | |
110 | + end_exec(); | |
111 | +} | |
112 | + | |
113 | +void err_div_zero(void){ | |
114 | + printstr(ERR_DIV_0); | |
115 | + end_exec(); | |
116 | +} | |
117 | + | |
118 | +void err_no_mem(void){ | |
119 | + printstr(ERR_NE_MEMORY); | |
120 | + end_exec(); | |
121 | +} | |
122 | + | |
123 | +void err_str_complex(void){ | |
124 | + printstr(ERR_STR_COMPLEX); | |
125 | + end_exec(); | |
126 | +} | |
127 | + | |
128 | +void err_unknown(void){ | |
129 | + asm volatile("la $v0,%0"::"i"(&g_temp)); | |
130 | + asm volatile("sw $ra,0($v0)"); | |
131 | + printstr(ERR_UNKNOWN); | |
132 | + printhex32(g_temp); | |
133 | + end_exec(); | |
134 | +} | |
135 | + | |
136 | +void err_music(char* str){ | |
137 | + printstr(ERR_MUSIC); | |
138 | + printstr(str); | |
139 | + printstr("'\n"); | |
140 | + // Restore s6 from g_s6 | |
141 | + asm volatile("la $s6,%0"::"i"(&g_s6)); | |
142 | + asm volatile("lw $s6,0($s6)"); | |
143 | + end_exec(); | |
144 | +} | |
145 | + | |
146 | +void err_unexp_next(void){ | |
147 | + printstr(ERR_UNEXP_NEXT); | |
148 | + end_exec(); | |
149 | +} | |
150 | + | |
151 | +void err_no_block(void){ | |
152 | + printstr(ERR_NO_BLOCK); | |
153 | + end_exec(); | |
154 | +} | |
155 | + | |
156 | +void err_invalid_param(void){ | |
157 | + printstr(ERR_INVALID_PARAM); | |
158 | + end_exec(); | |
159 | +} | |
160 | + | |
161 | +void err_file(void){ | |
162 | + printstr(ERR_FILE); | |
163 | + end_exec(); | |
164 | +} | |
165 | + | |
166 | +void err_wave(void){ | |
167 | + printstr(ERR_WAVE); | |
168 | + end_exec(); | |
169 | +} | |
170 | + |
@@ -0,0 +1,30 @@ | ||
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 asm("wait") but use asm("nop") | |
19 | +#undef WAIT | |
20 | +#define WAIT "nop" | |
21 | + | |
22 | +#endif // __DEBUG | |
23 | + | |
24 | +// key waiting macro | |
25 | + | |
26 | +#define debug_wait() lineinput((char*)&g_temp,3) | |
27 | +#define debug_wait_char(x) do {\ | |
28 | + printchar(x); \ | |
29 | + lineinput((char*)&g_temp,3);\ | |
30 | + } while(0) |
@@ -0,0 +1,2554 @@ | ||
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 | +int line_no; //現在のカーソル位置の行 | |
38 | +int line_no1; //範囲選択時のカーソルスタート位置の行 | |
39 | + | |
40 | +// カーソル関連位置の一時避難用 | |
41 | +_tbuf *cursorbp_t; | |
42 | +unsigned short cursorix_t; | |
43 | +_tbuf *disptopbp_t; | |
44 | +unsigned short disptopix_t; | |
45 | +int cx_t,cy_t,line_no_t; | |
46 | + | |
47 | +//unsigned char clipboard[WIDTH_XMAX*EDITWIDTHY]; //クリップボード、最大サイズは編集画面領域と同じ | |
48 | +unsigned char *clipboard; //実体は配列RAM[]の中に確保する | |
49 | + | |
50 | +int clipsize; //現在クリップボードに格納されている文字数 | |
51 | +int edited; //保存後に変更されたかを表すフラグ | |
52 | + | |
53 | +//配列RAM[]内にメモリ動的確保するためのポインタ | |
54 | +char *editormallocp; | |
55 | + | |
56 | +//unsigned char filebuf[FILEBUFSIZE]; //ファイルアクセス用バッファ | |
57 | +unsigned char *filebuf; //実体は配列RAM[]の中に確保する | |
58 | + | |
59 | +//unsigned char cwdpath[PATHNAMEMAX]; //現在のディレクトリのパス名 | |
60 | +unsigned char *cwdpath; //実体は配列RAM[]の中に確保する | |
61 | + | |
62 | +unsigned char currentfile[13],tempfile[13]; //編集中のファイル名、一時ファイル名 | |
63 | + | |
64 | +//unsigned char filenames[MAXFILENUM][13]; //ロード時のファイル名一覧バッファ | |
65 | +unsigned char (*filenames)[13]; //実体は配列RAM[]の中に確保する | |
66 | + | |
67 | +//unsigned char undobuf[UNDOBUFSIZE]; //アンドゥ用バッファ | |
68 | +unsigned char *undobuf; //実体は配列RAM[]の中に確保する | |
69 | +unsigned char *undobuf_top; //アンドゥ用バッファの先頭を指すポインタ | |
70 | +int undobuf_used; //アンドゥ用バッファ使用量 | |
71 | + | |
72 | +const unsigned char Message1[]="Hit Any Key\n"; | |
73 | +const unsigned char Message2[]="File System Error\n"; | |
74 | +const unsigned char Message3[]="Retry:[Enter] / Quit:[ESC]\n"; | |
75 | +const unsigned char ROOTDIR[]="\\"; | |
76 | + | |
77 | +unsigned char * editormalloc(int size){ | |
78 | +//配列RAM[]内にサイズsizeの領域を確保し、先頭アドレスを返す | |
79 | +//確保できない場合は、エラー表示し動作停止 | |
80 | + unsigned char *p; | |
81 | + if(editormallocp+size>RAM+RAMSIZE){ | |
82 | + printstr("Cannot allocate memory"); | |
83 | + while(1) asm("wait"); | |
84 | + } | |
85 | + p=editormallocp; | |
86 | + editormallocp+=size; | |
87 | + return p; | |
88 | +} | |
89 | + | |
90 | +void wait60thsec(unsigned short n){ | |
91 | +#ifndef __DEBUG | |
92 | + // 60分のn秒ウェイト(ビデオ画面の最下行信号出力終了まで待つ) | |
93 | + n+=drawcount; | |
94 | + while(drawcount!=n) asm(WAIT); | |
95 | +#else | |
96 | + // DEBUGモードでは、待ち時間無し | |
97 | + drawcount+=n; | |
98 | +#endif | |
99 | +} | |
100 | + | |
101 | +unsigned int bpixtopos(_tbuf *bp,unsigned int ix){ | |
102 | +// テキストバッファ上の位置からテキスト全体の先頭から何文字目かを返す | |
103 | +// bp:テキストバッファポインタ | |
104 | +// ix:bp->Bufの先頭からの文字数 | |
105 | + unsigned int pos; | |
106 | + _tbuf *sbp; | |
107 | + pos=0; | |
108 | + sbp=TBufstart; | |
109 | + while(sbp!=bp){ | |
110 | + pos+=sbp->n; | |
111 | + sbp=sbp->next; | |
112 | + if(sbp==NULL) return 0; //エラー | |
113 | + } | |
114 | + return pos+ix; | |
115 | +} | |
116 | +_tbuf * postobpix(int pos,unsigned short *pix){ | |
117 | +// テキスト全体の先頭からpos文字目のテキストバッファ上の位置を返す | |
118 | +// 戻り値 テキストバッファポインタ | |
119 | +// *pix(戻り値):戻り値テキストバッファの先頭からの位置(ポインタ渡し) | |
120 | + _tbuf *bp; | |
121 | + bp=TBufstart; | |
122 | + while(pos >= bp->n){ | |
123 | + if(bp->next==NULL) break; //全体最後尾の場合 | |
124 | + pos-=bp->n; | |
125 | + bp=bp->next; | |
126 | + } | |
127 | + if(pos > bp->n){ | |
128 | + // オーバーランエラーの場合先頭を返す | |
129 | + *pix=0; | |
130 | + return TBufstart; | |
131 | + } | |
132 | + *pix=pos; | |
133 | + return bp; | |
134 | +} | |
135 | +_tbuf * linetobpix(int line,unsigned short *pix){ | |
136 | +// テキスト全体の先頭からline行目のテキストバッファ上の位置を返す | |
137 | +// 戻り値 テキストバッファポインタ | |
138 | +// *pix(戻り値):戻り値テキストバッファの先頭からの位置(ポインタ渡し) | |
139 | + _tbuf *bp,*bp2; | |
140 | + int ix,ix2; | |
141 | + bp=TBufstart; | |
142 | + bp2=TBufstart; | |
143 | + ix=0; | |
144 | + ix2=0; | |
145 | + while(line>1){ | |
146 | + while(1){ | |
147 | + if(ix>=bp->n){ | |
148 | + if(bp->next==NULL) break; | |
149 | + bp=bp->next; | |
150 | + ix=0; | |
151 | + continue; | |
152 | + } | |
153 | + if(bp->Buf[ix++] == '\n'){ | |
154 | + bp2=bp; | |
155 | + ix2=ix; | |
156 | + break; | |
157 | + } | |
158 | + } | |
159 | + line--; | |
160 | + } | |
161 | + *pix=ix2; | |
162 | + return bp2; | |
163 | +} | |
164 | + | |
165 | +_tbuf * newTBuf(_tbuf *prev){ | |
166 | +// 新しいテキストバッファ1行を生成 | |
167 | +// prev:挿入先の行(prevの後ろに追加) | |
168 | +// 戻り値 生成したバッファへのポインタ、生成できない場合NULL | |
169 | + _tbuf *bp,*next; | |
170 | + | |
171 | + //バッファの先頭から空きをサーチ | |
172 | + bp=TextBuffer; | |
173 | + while(1){ | |
174 | + if(bp->prev==NULL && bp!=TBufstart) break; | |
175 | + bp++; | |
176 | + if(bp>=TextBuffer+TBUFMAXLINE) return NULL;//最後まで空きなし | |
177 | + } | |
178 | + next=prev->next; | |
179 | + //行挿入 | |
180 | + bp->prev=prev; | |
181 | + bp->next=next; | |
182 | + prev->next=bp; | |
183 | + if(next!=NULL) next->prev=bp; | |
184 | + bp->n=0; | |
185 | + return bp; | |
186 | +} | |
187 | + | |
188 | +_tbuf * deleteTBuf(_tbuf *bp){ | |
189 | +// テキストバッファの削除 | |
190 | +// bp:削除する行のポインタ | |
191 | +// 戻り値 削除前の次のバッファへのポインタ、ない場合NULL | |
192 | + unsigned short a,b; | |
193 | + _tbuf *prev,*next; | |
194 | + prev=bp->prev; | |
195 | + next=bp->next; | |
196 | + if(prev==NULL){ | |
197 | + //先頭行の場合 | |
198 | + if(next==NULL) return next; //最後の1行の場合は削除しない | |
199 | + TBufstart=next; //次の行を先頭行設定 | |
200 | + } | |
201 | + else prev->next=next; //前を次にリンク(最終行ならNULLがコピーされる) | |
202 | + if(next!=NULL) next->prev=prev; //次があれば次を前にリンク | |
203 | + bp->prev=NULL; //空きフラグ設定 | |
204 | + return next; | |
205 | +} | |
206 | + | |
207 | +// アンドゥバッファ | |
208 | +/* | |
209 | +UNDOBUFSIZEバイトの環状バッファ。テキストバッファに対する変更発生ごとに、 | |
210 | +変更内容、変更場所をバッファの先頭に記録し、先頭位置を進める。 | |
211 | +アンドゥ実行が呼び出されると、バッファ先頭から読み出し、テキストバッファに対して | |
212 | +元に戻す変更を行う。 | |
213 | +バッファがいっぱいになると、最後尾から消去(上書き)していく。 | |
214 | + | |
215 | +<バッファ仕様> | |
216 | + 開始位置:テキストバッファトップから何バイト目か(2バイト。下位、上位の順) | |
217 | + 繰り返し数:連続動作の場合の回数(2バイト。下位、上位の順) | |
218 | + バッファの前からも後ろからも削除できるよう、先頭と最後に命令をおく。ただし、 | |
219 | + 後ろの命令コードが10以上の場合は削除された文字そのものを意味する。 | |
220 | +1文字挿入 | |
221 | + UNDO_INSERT,開始位置,UNDO_INSERT | |
222 | +1文字上書き | |
223 | + UNDO_OVERWRITE,開始位置,消去文字 [,消去文字が0?9の場合さらに0を付加] | |
224 | +1文字削除(Delete) | |
225 | + UNDO_DELETE,開始位置,消去文字 [,消去文字が0?9の場合さらに0を付加] | |
226 | +1文字削除(BackSpace) | |
227 | + UNDO_BACKSPACE,開始位置,消去文字 [,消去文字が0?9の場合さらに0を付加] | |
228 | +連続挿入(Ctrl+Vで貼り付け) | |
229 | + UNDO_CONTINS,開始位置,繰り返し数,UNDO_CONTINS | |
230 | +連続削除(領域選択して削除) | |
231 | + UNDO_CONTDEL,繰り返し数,消去文字列,開始位置,繰り返し数,UNDO_CONTDEL | |
232 | +*/ | |
233 | + | |
234 | +void pushundomem(unsigned char c){ | |
235 | +// アンドゥ用メモリの先頭に1バイトを貯める | |
236 | +// 空きがなくなった場合、最後尾の1命令分を無効化 | |
237 | + unsigned char *p; | |
238 | + int n; | |
239 | + | |
240 | + if(undobuf_used>=UNDOBUFSIZE){ | |
241 | + //空きがない場合、最後尾のブロックのバイト数分をバッファ利用済み量から減らす | |
242 | + p=undobuf_top-undobuf_used; //最後尾 | |
243 | + if(p<undobuf) p+=UNDOBUFSIZE; | |
244 | + switch(*p){ | |
245 | + case UNDO_INSERT: //1文字挿入 | |
246 | + undobuf_used-=4; | |
247 | + break; | |
248 | + case UNDO_OVERWRITE: //1文字上書き | |
249 | + case UNDO_DELETE: //1文字削除 | |
250 | + case UNDO_BACKSPACE: //1文字削除(BS) | |
251 | + undobuf_used-=4; | |
252 | + p+=3; | |
253 | + if(p>=undobuf+UNDOBUFSIZE) p-=UNDOBUFSIZE; | |
254 | + if(*p<10) undobuf_used--; //コード0?9の場合後ろに0が付加されている | |
255 | + break; | |
256 | + case UNDO_CONTINS: //連続挿入 | |
257 | + undobuf_used-=6; | |
258 | + break; | |
259 | + case UNDO_CONTDEL: //連続削除 | |
260 | + //繰り返し数の読み出し | |
261 | + p++; | |
262 | + if(p>=undobuf+UNDOBUFSIZE) p-=UNDOBUFSIZE; | |
263 | + n=*p++; | |
264 | + if(p>=undobuf+UNDOBUFSIZE) p-=UNDOBUFSIZE; | |
265 | + n+=*p<<8; | |
266 | + undobuf_used-=n+8; | |
267 | + break; | |
268 | + } | |
269 | + } | |
270 | + //アンドゥバッファ先頭に1バイト挿入し、先頭位置を1進める | |
271 | + *undobuf_top++=c; | |
272 | + if(undobuf_top>=undobuf+UNDOBUFSIZE) undobuf_top-=UNDOBUFSIZE; | |
273 | + undobuf_used++; | |
274 | +} | |
275 | +void pushundomem2(unsigned short w){ | |
276 | +// アンドゥバッファに2バイト貯める、下位、上位の順 | |
277 | + pushundomem((unsigned char)w); | |
278 | + pushundomem(w>>8); | |
279 | +} | |
280 | +unsigned char popundomem(){ | |
281 | +// アンドゥバッファから1バイト読み出し、先頭を1つ戻す | |
282 | +// 戻り値:読み出したコード | |
283 | + undobuf_top--; | |
284 | + if(undobuf_top<undobuf) undobuf_top+=UNDOBUFSIZE; | |
285 | + undobuf_used--; | |
286 | + return *undobuf_top; | |
287 | +} | |
288 | +unsigned short popundomem2(){ | |
289 | +// アンドゥバッファから2バイト読み出し | |
290 | +// 戻り値:読み出した2バイトコード | |
291 | + unsigned short w; | |
292 | + w=popundomem()<<8; | |
293 | + w+=popundomem(); | |
294 | + return w; | |
295 | +} | |
296 | +void setundobuf(int com,_tbuf *bp,unsigned short ix,unsigned char c,unsigned short n){ | |
297 | +//アンドゥバッファにデータをセットする | |
298 | +//com:コマンド 1:1文字削除、2:1文字上書き、3:1文字挿入、4:連続削除、5:連続挿入開始 | |
299 | +//bp,ix:バッファ上の実行場所(カーソル位置) | |
300 | +//c:文字(上書き、挿入の場合のみ使用) | |
301 | +//n:連続数(連続の場合のみ使用) | |
302 | + unsigned short pos; | |
303 | + | |
304 | + pos=bpixtopos(bp,ix); //テキストバッファ先頭から何バイト目かを求める | |
305 | + switch(com){ | |
306 | + case UNDO_INSERT: //1文字挿入 | |
307 | + pushundomem(com); | |
308 | + pushundomem2(pos); | |
309 | + pushundomem(com); | |
310 | + break; | |
311 | + case UNDO_OVERWRITE: //1文字上書き | |
312 | + case UNDO_DELETE: //1文字削除(Delete) | |
313 | + case UNDO_BACKSPACE: //1文字削除(BackSpace) | |
314 | + pushundomem(com); | |
315 | + pushundomem2(pos); | |
316 | + pushundomem(c); | |
317 | + if(c<10) pushundomem(0); //10未満のコードの場合0を付加 | |
318 | + break; | |
319 | + case UNDO_CONTINS: //連続挿入 | |
320 | + pushundomem(com); | |
321 | + pushundomem2(pos); | |
322 | + pushundomem2(n); | |
323 | + pushundomem(com); | |
324 | + break; | |
325 | + case UNDO_CONTDEL: //連続削除 | |
326 | + pushundomem(com); | |
327 | + pushundomem2(n); | |
328 | + break; | |
329 | + } | |
330 | +} | |
331 | + | |
332 | +int insertchar(_tbuf *bp,unsigned int ix,unsigned char c,int undo){ | |
333 | +//テキストバッファbpの先頭からixバイトの位置にcを挿入 | |
334 | +//undo 0:通常(アンドゥバッファに格納する)、1:連続挿入中、2:アンドゥ中 | |
335 | +//戻り値 成功:0、不正または容量オーバー:-1、空きがあるはずなのに失敗:1 | |
336 | + unsigned char *p; | |
337 | + | |
338 | + if(ix > bp->n) return -1; //不正指定 | |
339 | + if(num >= TBUFMAXSIZE) return -1; //バッファ容量オーバー | |
340 | + if(bp->n < TBUFSIZE){ | |
341 | + //ライン内だけで1バイト挿入可能// | |
342 | + for(p=bp->Buf + bp->n ; p > bp->Buf+ix ; p--) *p=*(p-1); | |
343 | + *p=c; | |
344 | + if(!undo) setundobuf(UNDO_INSERT,bp,ix,0,0); //アンドゥバッファ設定 | |
345 | + bp->n++; | |
346 | + num++; //バッファ使用量 | |
347 | +// if(bp->n >= TBUFSIZE && bp->next==NULL) newTBuf(bp); //バッファがいっぱいになったら新たにバッファ生成 | |
348 | + return 0; | |
349 | + } | |
350 | + //ラインがあふれる場合 | |
351 | + if(bp->next==NULL || bp->next->n >=TBUFSIZE){ | |
352 | + // 最終行または次のラインバッファがいっぱいだったら一行挿入 | |
353 | + if(newTBuf(bp)==NULL){ | |
354 | + // ラインバッファ挿入不可 | |
355 | + return 1; | |
356 | + } | |
357 | + } | |
358 | + if(ix==TBUFSIZE){ | |
359 | + insertchar(bp->next,0,c,undo); | |
360 | + return 0; | |
361 | + } | |
362 | + p=bp->Buf + TBUFSIZE-1; | |
363 | + insertchar(bp->next,0,*p,1); //次の行の先頭に1文字挿入(必ず空きあり) | |
364 | + for( ; p > bp->Buf+ix ; p--) *p=*(p-1); | |
365 | + *p=c; | |
366 | + if(!undo) setundobuf(UNDO_INSERT,bp,ix,0,0); //アンドゥバッファ設定 | |
367 | + return 0; | |
368 | +} | |
369 | + | |
370 | +int overwritechar(_tbuf *bp,unsigned int ix,unsigned char c,int undo){ | |
371 | +//テキストバッファbpの先頭からixバイトの位置をcで上書き | |
372 | +//undo 0:通常(アンドゥバッファに格納する)、1:連続中、2:アンドゥ中 | |
373 | +//戻り値 成功:0、不正または容量オーバー:-1、空きがあるはずなのに失敗:1 | |
374 | + | |
375 | + //現在のバッファ位置の文字が終端または改行の場合、挿入モード | |
376 | + if(ix > bp->n) return -1; //不正指定 | |
377 | + while(ix >= bp->n){ | |
378 | + if(bp->next==NULL){ | |
379 | + //テキスト全体最後尾の場合は挿入 | |
380 | + return insertchar(bp,ix,c,undo); | |
381 | + } | |
382 | + bp=bp->next; | |
383 | + ix=0; | |
384 | + } | |
385 | + if(bp->Buf[ix]=='\n') return insertchar(bp,ix,c,undo); | |
386 | + if(!undo) setundobuf(UNDO_OVERWRITE,bp,ix,bp->Buf[ix],0); //アンドゥバッファ設定 | |
387 | + bp->Buf[ix]=c; | |
388 | + return 0; | |
389 | +} | |
390 | + | |
391 | +void deletechar(_tbuf *bp,unsigned int ix,int undo){ | |
392 | +//テキストバッファbpの先頭からixバイトの位置の1バイト削除 | |
393 | +//undo -1:通常BackSpace(アンドゥバッファに格納する) | |
394 | +// 0:通常DELETE(アンドゥバッファに格納する)、1:連続中、2:アンドゥ中 | |
395 | + unsigned char *p; | |
396 | + | |
397 | + if(ix > bp->n) return; //不正指定 | |
398 | + if(ix !=bp->n){ | |
399 | + //バッファの最後の文字より後ろでない場合 | |
400 | + | |
401 | + //アンドゥバッファ設定 | |
402 | + if(undo==1) pushundomem(bp->Buf[ix]); //連続削除中 | |
403 | + else if(undo==-1) setundobuf(UNDO_BACKSPACE,bp,ix,bp->Buf[ix],0); //1文字削除(backspace) | |
404 | + else if(undo==0) setundobuf(UNDO_DELETE,bp,ix,bp->Buf[ix],0); //1文字削除 | |
405 | + | |
406 | + for(p=bp->Buf+ix ; p< bp->Buf + bp->n-1 ; p++) *p=*(p+1); | |
407 | + bp->n--; | |
408 | + num--; //バッファ使用量 | |
409 | + return; | |
410 | + } | |
411 | + //行バッファの現在の最後の場合(削除する文字がない場合) | |
412 | + if(bp->next==NULL) return; //全体の最後の場合、何もしない | |
413 | + deletechar(bp->next,0,undo); //次の行の先頭文字を削除 | |
414 | +} | |
415 | +int gabagecollect1(void){ | |
416 | +//断片化されたテキストバッファの隙間を埋めるガベージコレクション | |
417 | +//カーソルの前と後ろそれぞれ探索して最初の1バイト分のみ実施 | |
418 | +//戻り値 1バイトでも移動した場合:1、なかった場合:0 | |
419 | + | |
420 | + _tbuf *bp; | |
421 | + int f=0; | |
422 | + unsigned char *p,*p2; | |
423 | + | |
424 | + //カーソルがバッファの先頭にある場合、前のバッファの最後尾に変更 | |
425 | + //(ただし前に空きがない場合と先頭バッファの場合を除く) | |
426 | + while(cursorix==0 && cursorbp->prev!=NULL && cursorbp->prev->n <TBUFSIZE){ | |
427 | + cursorbp=cursorbp->prev; | |
428 | + cursorix=cursorbp->n; | |
429 | + } | |
430 | + //画面左上位置がバッファの先頭にある場合、前のバッファの最後尾に変更 | |
431 | + //(ただし先頭バッファの場合を除く) | |
432 | + while(disptopix==0 && disptopbp->prev!=NULL){ | |
433 | + disptopbp=disptopbp->prev; | |
434 | + disptopix=disptopbp->n; | |
435 | + } | |
436 | + //カーソルのあるバッファ以外の空バッファを全て削除 | |
437 | + bp=TBufstart; | |
438 | + while(bp!=NULL){ | |
439 | + if(bp->n == 0 && bp!=cursorbp){ | |
440 | + if(bp==disptopbp) disptopbp=bp->next; //画面左上位置が空バッファ先頭の場合、次にずらす | |
441 | + bp=deleteTBuf(bp); //空きバッファ削除 | |
442 | + } | |
443 | + else bp=bp->next; | |
444 | + } | |
445 | + | |
446 | + //カーソル位置より前の埋まっていないバッファを先頭からサーチ | |
447 | + bp=TBufstart; | |
448 | + while(bp->n >= TBUFSIZE){ | |
449 | + if(bp==cursorbp) break; | |
450 | + bp=bp->next; | |
451 | + } | |
452 | + if(bp!=cursorbp){ | |
453 | + //最初に見つけた空き場所に次のバッファから1バイト移動 | |
454 | + bp->Buf[bp->n++] = bp->next->Buf[0]; | |
455 | + bp=bp->next; | |
456 | + p=bp->Buf; | |
457 | + p2=p+bp->n-1; | |
458 | + for( ; p<p2 ; p++) *p=*(p+1); | |
459 | + bp->n--; | |
460 | + f=1; | |
461 | + if(bp == disptopbp) disptopix--; | |
462 | + if(bp == cursorbp) cursorix--; | |
463 | +// else if(bp->n == 0) deleteTBuf(bp); | |
464 | + } | |
465 | + if(cursorbp->next ==NULL) return f; //カーソル位置が最終バッファなら終了 | |
466 | + //カーソル位置の次のバッファから埋まっていないバッファをサーチ | |
467 | + bp=cursorbp; | |
468 | + do{ | |
469 | + bp=bp->next; | |
470 | + if(bp->next ==NULL) return f; //最終バッファに到達なら終了 | |
471 | + } while(bp->n >=TBUFSIZE); | |
472 | + | |
473 | + //最初に見つけた空き場所に次のバッファから1バイト移動 | |
474 | + bp->Buf[bp->n++] = bp->next->Buf[0]; | |
475 | + bp=bp->next; | |
476 | + p=bp->Buf; | |
477 | + p2=p+bp->n-1; | |
478 | + for( ; p<p2 ; p++) *p=*(p+1); | |
479 | + bp->n--; | |
480 | + f=1; | |
481 | + if(bp->n == 0) deleteTBuf(bp); | |
482 | + return f; | |
483 | +} | |
484 | +void gabagecollect2(void){ | |
485 | +// 変化がなくなるまで1バイト分のガベージコレクションを呼び出し | |
486 | + while(gabagecollect1()) ; | |
487 | +} | |
488 | +void inittextbuf(void){ | |
489 | +// テキストバッファの初期化 | |
490 | + _tbuf *bp; | |
491 | + for(bp=TextBuffer;bp<TextBuffer+TBUFMAXLINE;bp++) bp->prev=NULL; //未使用バッファ化 | |
492 | + TBufstart=TextBuffer; //リンクの先頭設定 | |
493 | + TBufstart->next=NULL; | |
494 | + TBufstart->n=0; | |
495 | + num=0; //バッファ使用量 | |
496 | + edited=0; //編集済みフラグクリア | |
497 | + undobuf_top=undobuf; | |
498 | + undobuf_used=0; | |
499 | +} | |
500 | +void redraw(){ | |
501 | +//画面の再描画 | |
502 | + unsigned char *vp; | |
503 | + _tbuf *bp,*bp1,*bp2; | |
504 | + int ix,ix1,ix2; | |
505 | + int x,y; | |
506 | + unsigned char ch,cl; | |
507 | + | |
508 | + vp=TVRAM; | |
509 | + bp=disptopbp; | |
510 | + ix=disptopix; | |
511 | + cl=COLOR_NORMALTEXT; | |
512 | + if(cursorbp1==NULL){ | |
513 | + //範囲選択モードでない場合 | |
514 | + bp1=NULL; | |
515 | + bp2=NULL; | |
516 | + } | |
517 | + else{ | |
518 | + //範囲選択モードの場合、開始位置と終了の前後判断して | |
519 | + //bp1,ix1を開始位置、bp2,ix2を終了位置に設定 | |
520 | + if(cy<cy1 || (cy==cy1 && cx<cx1)){ | |
521 | + bp1=cursorbp; | |
522 | + ix1=cursorix; | |
523 | + bp2=cursorbp1; | |
524 | + ix2=cursorix1; | |
525 | + } | |
526 | + else{ | |
527 | + bp1=cursorbp1; | |
528 | + ix1=cursorix1; | |
529 | + bp2=cursorbp; | |
530 | + ix2=cursorix; | |
531 | + } | |
532 | + } | |
533 | + for(y=0;y<EDITWIDTHY;y++){ | |
534 | + if(bp==NULL) break; | |
535 | + for(x=0;x<twidth;x++){ | |
536 | + //文字がある位置までサーチ | |
537 | + while(ix>=bp->n){ | |
538 | + if(bp==bp1 && ix==ix1){ | |
539 | + if(textmode!=TMODE_MONOTEXT){ | |
540 | + cl=COLOR_AREASELECTTEXT; | |
541 | + } | |
542 | + else{ | |
543 | + cl=COLOR_INV; | |
544 | + } | |
545 | + } | |
546 | + if(bp==bp2 && ix==ix2) cl=COLOR_NORMALTEXT; | |
547 | + bp=bp->next; | |
548 | + ix=0; | |
549 | + if(bp==NULL) break; | |
550 | + } | |
551 | + if(bp==NULL) break; //バッファ最終 | |
552 | + if(bp==bp1 && ix==ix1){ | |
553 | + if(textmode!=TMODE_MONOTEXT){ | |
554 | + cl=COLOR_AREASELECTTEXT; | |
555 | + } | |
556 | + else{ | |
557 | + cl=COLOR_INV; | |
558 | + } | |
559 | + } | |
560 | + if(bp==bp2 && ix==ix2) cl=COLOR_NORMALTEXT; | |
561 | + ch=bp->Buf[ix++]; | |
562 | + if(ch=='\n') break; | |
563 | + *(vp+attroffset)=cl; | |
564 | + *vp++=ch; | |
565 | + } | |
566 | + //改行およびバッファ最終以降の右側表示消去 | |
567 | + for(;x<twidth;x++){ | |
568 | + *(vp+attroffset)=0; | |
569 | + *vp++=0; | |
570 | + } | |
571 | + } | |
572 | + //バッファ最終以降の下側表示消去 | |
573 | + for(;y<EDITWIDTHY;y++){ | |
574 | + for(x=0;x<twidth;x++){ | |
575 | + *(vp+attroffset)=0; | |
576 | + *vp++=0; | |
577 | + } | |
578 | + } | |
579 | +} | |
580 | + | |
581 | +void cursor_left(void){ | |
582 | +//カーソルを1つ前に移動 | |
583 | +//出力:下記変数を移動先の値に変更 | |
584 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
585 | +//cx,cy 画面上のカーソル位置 | |
586 | +//cx2 cxと同じ | |
587 | +//disptopbp,disptopix 画面左上のバッファ上の位置 | |
588 | + | |
589 | + _tbuf *bp; | |
590 | + int ix; | |
591 | + int i; | |
592 | + int x; | |
593 | + | |
594 | + //バッファ上のカーソル位置を1つ前に移動 | |
595 | + if(cursorix!=0) cursorix--; | |
596 | + else while(1) { | |
597 | + //1つ前のバッファの最後尾に移動、ただし空バッファは飛ばす | |
598 | + if(cursorbp->prev==NULL) return; //テキスト全体先頭なので移動しない | |
599 | + cursorbp=cursorbp->prev; | |
600 | + if(cursorbp->n >0){ | |
601 | + cursorix=cursorbp->n-1;//バッファ最後尾 | |
602 | + break; | |
603 | + } | |
604 | + } | |
605 | + | |
606 | + //カーソルおよび画面左上位置の更新 | |
607 | + if(cx>0){ | |
608 | + //左端でなければカーソルを単純に1つ左に移動して終了 | |
609 | + cx--; | |
610 | + cx2=cx; | |
611 | + return; | |
612 | + } | |
613 | + if(cy>0){ | |
614 | + //左端だが上端ではない場合 | |
615 | + if(cursorbp->Buf[cursorix]!='\n'){ | |
616 | + // 移動先が改行コードでない場合、カーソルは1つ上の行の右端に移動 | |
617 | + cx=twidth-1; | |
618 | + cx2=cx; | |
619 | + cy--; | |
620 | + return; | |
621 | + } | |
622 | + //画面左上位置から最後尾のX座標をサーチ | |
623 | + bp=disptopbp; | |
624 | + ix=disptopix; | |
625 | + x=0; | |
626 | + while(ix!=cursorix || bp!=cursorbp){ | |
627 | + if(bp->n==0){ | |
628 | + //空バッファの場合次へ | |
629 | + bp=bp->next; | |
630 | + ix=0; | |
631 | + continue; | |
632 | + } | |
633 | + if(bp->Buf[ix++]=='\n' || x>=twidth-1) x=0; | |
634 | + else x++; | |
635 | + if(ix >= bp->n){ | |
636 | + bp=bp->next; | |
637 | + ix=0; | |
638 | + } | |
639 | + } | |
640 | + cx=x; | |
641 | + cx2=cx; | |
642 | + cy--; | |
643 | + line_no--; | |
644 | + return; | |
645 | + } | |
646 | + | |
647 | + //左端かつ上端の場合 | |
648 | + if(cursorbp->Buf[cursorix]!='\n'){ | |
649 | + // 移動先が改行コードでない場合、カーソルは右端に移動 | |
650 | + // 画面左上位置は画面横幅分前に移動 | |
651 | + cx=twidth-1; | |
652 | + cx2=cx; | |
653 | + } | |
654 | + else{ | |
655 | + //移動先が改行コードの場合 | |
656 | + //行頭(改行の次の文字またはバッファ先頭)と現在位置の文字数差を | |
657 | + //画面横幅で割った余りがカーソルX座標 | |
658 | + bp=cursorbp; | |
659 | + ix=cursorix; | |
660 | + i=0; | |
661 | + while(1){ | |
662 | + if(ix==0){ | |
663 | + if(bp->prev==NULL) break; | |
664 | + bp=bp->prev; | |
665 | + ix=bp->n; | |
666 | + continue; | |
667 | + } | |
668 | + ix--; | |
669 | + if(bp->Buf[ix]=='\n') break; | |
670 | + i++; | |
671 | + } | |
672 | + cx=i % twidth; | |
673 | + cx2=cx; | |
674 | + line_no--; | |
675 | + } | |
676 | + //画面左上位置は現在位置からX座標分引いたところ | |
677 | + bp=cursorbp; | |
678 | + ix=cursorix; | |
679 | + x=cx; | |
680 | + while(x>0){ | |
681 | + if(ix==0){ | |
682 | + bp=bp->prev; | |
683 | + ix=bp->n; | |
684 | + continue; | |
685 | + } | |
686 | + ix--; | |
687 | + x--; | |
688 | + } | |
689 | + disptopbp=bp; | |
690 | + disptopix=ix; | |
691 | +} | |
692 | +void cursor_right(void){ | |
693 | +//カーソルを1つ後ろに移動 | |
694 | +//出力:下記変数を移動先の値に変更 | |
695 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
696 | +//cx,cy 画面上のカーソル位置 | |
697 | +//cx2 cxと同じ | |
698 | +//disptopbp,disptopix 画面左上のバッファ上の位置 | |
699 | + | |
700 | + _tbuf *bp; | |
701 | + int ix; | |
702 | + int i; | |
703 | + int x; | |
704 | + unsigned char c; | |
705 | + | |
706 | + if(cursorix >= cursorbp->n){ | |
707 | + //バッファ最後尾の場合、次の先頭に移動 | |
708 | + bp=cursorbp; | |
709 | + while(1) { | |
710 | + //空バッファは飛ばす | |
711 | + if(bp->next==NULL) return; //テキスト全体最後尾なので移動しない | |
712 | + bp=bp->next; | |
713 | + if(bp->n >0) break; | |
714 | + } | |
715 | + cursorbp=bp; | |
716 | + cursorix=0;//バッファ先頭 | |
717 | + } | |
718 | + c=cursorbp->Buf[cursorix++]; //バッファ上のカーソル位置のコードを読んで1つ後ろに移動 | |
719 | + if(c!='\n' && cx<twidth-1){ | |
720 | + //カーソル位置が改行でも右端でもない場合単純に1つ右に移動して終了 | |
721 | + cx++; | |
722 | + cx2=cx; | |
723 | + return; | |
724 | + } | |
725 | + cx=0; //カーソルを左端に移動 | |
726 | + cx2=cx; | |
727 | + if(c=='\n') line_no++; | |
728 | + if(cy<EDITWIDTHY-1){ | |
729 | + //下端でなければカーソルを次行に移動して終了 | |
730 | + cy++; | |
731 | + return; | |
732 | + } | |
733 | + //下端の場合 | |
734 | + //画面左上位置を更新 | |
735 | + //改行コードまたは画面横幅超えるまでサーチ | |
736 | + bp=disptopbp; | |
737 | + ix=disptopix; | |
738 | + x=0; | |
739 | + while(x<twidth){ | |
740 | + if(ix >= bp->n){ | |
741 | + bp=bp->next; | |
742 | + ix=0; | |
743 | + continue; | |
744 | + } | |
745 | + if(bp->Buf[ix++]=='\n') break; | |
746 | + x++; | |
747 | + } | |
748 | + disptopbp=bp; | |
749 | + disptopix=ix; | |
750 | +} | |
751 | +void cursor_up(void){ | |
752 | +//カーソルを1つ上に移動 | |
753 | +//出力:下記変数を移動先の値に変更 | |
754 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
755 | +//cx,cy 画面上のカーソル位置 | |
756 | +//cx2 移動前のcxと同じ | |
757 | +//disptopbp,disptopix 画面左上のバッファ上の位置 | |
758 | + | |
759 | + _tbuf *bp; | |
760 | + int ix; | |
761 | + int i; | |
762 | + int x; | |
763 | + unsigned char c; | |
764 | + | |
765 | + //画面幅分前に戻ったところがバッファ上カーソルの移動先 | |
766 | + //途中で改行コードがあれば別の手段で検索 | |
767 | + bp=cursorbp; | |
768 | + ix=cursorix; | |
769 | + i=cx2-cx; | |
770 | + while(i<twidth){ | |
771 | + if(ix==0){ | |
772 | + if(bp->prev==NULL) return; //バッファ先頭までサーチしたら移動なし | |
773 | + bp=bp->prev; | |
774 | + ix=bp->n; | |
775 | + continue; | |
776 | + } | |
777 | + ix--; | |
778 | + if(bp->Buf[ix]=='\n') break; | |
779 | + i++; | |
780 | + } | |
781 | + cursorbp=bp; | |
782 | + cursorix=ix; | |
783 | + //画面幅の間に改行コードがなかった場合 | |
784 | + if(i==twidth){ | |
785 | + cx=cx2; | |
786 | + //画面上端でなければカーソルを1つ上に移動して終了 | |
787 | + if(cy>0){ | |
788 | + cy--; | |
789 | + return; | |
790 | + } | |
791 | + //画面上端の場合、カーソル位置からX座標分戻ったところが画面左上位置 | |
792 | + x=cx; | |
793 | + while(x>0){ | |
794 | + if(ix==0){ | |
795 | + bp=bp->prev; | |
796 | + ix=bp->n; | |
797 | + continue; | |
798 | + } | |
799 | + ix--; | |
800 | + x--; | |
801 | + } | |
802 | + disptopbp=bp; | |
803 | + disptopix=ix; | |
804 | + return; | |
805 | + } | |
806 | + //改行が見つかった場合 | |
807 | + //行頭(改行の次の文字またはバッファ先頭)と現在位置の文字数差を | |
808 | + //画面横幅で割った余りを求める | |
809 | + line_no--; | |
810 | + i=0; | |
811 | + while(1){ | |
812 | + if(ix==0){ | |
813 | + if(bp->prev==NULL) break; | |
814 | + bp=bp->prev; | |
815 | + ix=bp->n; | |
816 | + continue; | |
817 | + } | |
818 | + ix--; | |
819 | + if(bp->Buf[ix]=='\n') break; | |
820 | + i++; | |
821 | + } | |
822 | + x=i % twidth; //改行ブロックの最終行の右端 | |
823 | + bp=cursorbp; | |
824 | + ix=cursorix; | |
825 | + //バッファ上のカーソル位置は改行ブロックの最終行右端からカーソルX座標分戻る | |
826 | + //最終行右端のほうが小さい場合、その場所をバッファ上のカーソル位置とする | |
827 | + while(x>cx2){ | |
828 | + if(ix==0){ | |
829 | + bp=bp->prev; | |
830 | + ix=bp->n; | |
831 | + continue; | |
832 | + } | |
833 | + ix--; | |
834 | + x--; | |
835 | + } | |
836 | + cursorbp=bp; | |
837 | + cursorix=ix; | |
838 | + cx=x; //cx2または改行ブロック最終行右端 | |
839 | + if(cy>0){ | |
840 | + //画面上端でなければカーソルを1つ上に移動して終了 | |
841 | + cy--; | |
842 | + return; | |
843 | + } | |
844 | + //画面上端の場合 | |
845 | + //画面左上位置は現在位置からX座標分引いたところ | |
846 | + while(x>0){ | |
847 | + if(ix==0){ | |
848 | + bp=bp->prev; | |
849 | + ix=bp->n; | |
850 | + continue; | |
851 | + } | |
852 | + ix--; | |
853 | + x--; | |
854 | + } | |
855 | + disptopbp=bp; | |
856 | + disptopix=ix; | |
857 | +} | |
858 | +void cursor_down(void){ | |
859 | +//カーソルを1つ下に移動 | |
860 | +//出力:下記変数を移動先の値に変更 | |
861 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
862 | +//cx,cy 画面上のカーソル位置 | |
863 | +//cx2 移動前のcxと同じ | |
864 | +//disptopbp,disptopix 画面左上のバッファ上の位置 | |
865 | + | |
866 | + _tbuf *bp; | |
867 | + int ix; | |
868 | + int x; | |
869 | + unsigned char c; | |
870 | + | |
871 | + //次行の先頭サーチ | |
872 | + //カーソル位置から画面右端までの間に改行コードがあれば次の文字が先頭 | |
873 | + bp=cursorbp; | |
874 | + ix=cursorix; | |
875 | + x=cx; | |
876 | + while(x<twidth){ | |
877 | + if(ix>=bp->n){ | |
878 | + if(bp->next==NULL) return; //バッファ最後までサーチしたら移動なし | |
879 | + bp=bp->next; | |
880 | + ix=0; | |
881 | + continue; | |
882 | + } | |
883 | + c=bp->Buf[ix]; | |
884 | + ix++; | |
885 | + x++; | |
886 | + if(c=='\n'){ | |
887 | + line_no++; | |
888 | + break; | |
889 | + } | |
890 | + } | |
891 | + //次行先頭からcx2文字数分後ろにサーチ | |
892 | + x=0; | |
893 | + while(x<cx2){ | |
894 | + if(ix>=bp->n){ | |
895 | + if(bp->next==NULL) break; //バッファ最後の場合そこに移動 | |
896 | + bp=bp->next; | |
897 | + ix=0; | |
898 | + continue; | |
899 | + } | |
900 | + if(bp->Buf[ix]=='\n') break; //改行コードの場合そこに移動 | |
901 | + ix++; | |
902 | + x++; | |
903 | + } | |
904 | + cursorbp=bp; | |
905 | + cursorix=ix; | |
906 | + cx=x; | |
907 | + //画面下端でなければカーソルを1つ下に移動して終了 | |
908 | + if(cy<EDITWIDTHY-1){ | |
909 | + cy++; | |
910 | + return; | |
911 | + } | |
912 | + //下端の場合 | |
913 | + //画面左上位置を更新 | |
914 | + //改行コードまたは画面横幅超えるまでサーチ | |
915 | + bp=disptopbp; | |
916 | + ix=disptopix; | |
917 | + x=0; | |
918 | + while(x<twidth){ | |
919 | + if(ix >= bp->n){ | |
920 | + bp=bp->next; | |
921 | + ix=0; | |
922 | + continue; | |
923 | + } | |
924 | + if(bp->Buf[ix++]=='\n') break; | |
925 | + x++; | |
926 | + } | |
927 | + disptopbp=bp; | |
928 | + disptopix=ix; | |
929 | +} | |
930 | +void cursor_home(void){ | |
931 | +//カーソルを行先頭に移動 | |
932 | +//出力:下記変数を移動先の値に変更 | |
933 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
934 | +//cx,cx2 0 | |
935 | +//cy 変更なし | |
936 | +//disptopbp,disptopix 画面左上のバッファ上の位置(変更なし) | |
937 | + | |
938 | + //カーソルX座標分前に移動 | |
939 | + while(cx>0){ | |
940 | + if(cursorix==0){ | |
941 | + //空バッファは飛ばす | |
942 | + cursorbp=cursorbp->prev; | |
943 | + cursorix=cursorbp->n; | |
944 | + continue; | |
945 | + } | |
946 | + cursorix--; | |
947 | + cx--; | |
948 | + } | |
949 | + cx2=0; | |
950 | +} | |
951 | +void cursor_end(void){ | |
952 | +//カーソルを行末に移動 | |
953 | +//出力:下記変数を移動先の値に変更 | |
954 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
955 | +//cx,cx2 行末 | |
956 | +//cy 変更なし | |
957 | +//disptopbp,disptopix 画面左上のバッファ上の位置(変更なし) | |
958 | + | |
959 | + //カーソルX座標を画面幅分後ろに移動 | |
960 | + //改行コードまたはバッファ最終があればそこに移動 | |
961 | + while(cx<twidth-1){ | |
962 | + if(cursorix>=cursorbp->n){ | |
963 | + //空バッファは飛ばす | |
964 | + if(cursorbp->next==NULL) break; | |
965 | + cursorbp=cursorbp->next; | |
966 | + cursorix=0; | |
967 | + continue; | |
968 | + } | |
969 | + if(cursorbp->Buf[cursorix]=='\n') break; | |
970 | + cursorix++; | |
971 | + cx++; | |
972 | + } | |
973 | + cx2=cx; | |
974 | +} | |
975 | +void cursor_pageup(void){ | |
976 | +//PageUpキー | |
977 | +//最上行が最下行になるまでスクロール | |
978 | +//出力:下記変数を移動先の値に変更 | |
979 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
980 | +//cx,cx2 | |
981 | +//cy | |
982 | +//disptopbp,disptopix 画面左上のバッファ上の位置 | |
983 | + | |
984 | + _tbuf *bp; | |
985 | + int ix; | |
986 | + int i; | |
987 | + int cy_old; | |
988 | + | |
989 | + cy_old=cy; | |
990 | + while(cy>0) cursor_up(); // cy==0になるまでカーソルを上に移動 | |
991 | + for(i=0;i<EDITWIDTHY-1;i++){ | |
992 | + //画面行数-1行分カーソルを上に移動 | |
993 | + bp=disptopbp; | |
994 | + ix=disptopix; | |
995 | + cursor_up(); | |
996 | + if(bp==disptopbp && ix==disptopix) break; //最上行で移動できなかった場合抜ける | |
997 | + } | |
998 | + //元のY座標までカーソルを下に移動、1行も動かなかった場合は最上行に留まる | |
999 | + if(i>0) while(cy<cy_old) cursor_down(); | |
1000 | +} | |
1001 | +void cursor_pagedown(void){ | |
1002 | +//PageDownキー | |
1003 | +//最下行が最上行になるまでスクロール | |
1004 | +//出力:下記変数を移動先の値に変更 | |
1005 | +//cursorbp,cursorix バッファ上のカーソル位置 | |
1006 | +//cx,cx2 | |
1007 | +//cy | |
1008 | +//disptopbp,disptopix 画面左上のバッファ上の位置 | |
1009 | + | |
1010 | + _tbuf *bp; | |
1011 | + int ix; | |
1012 | + int i; | |
1013 | + int y; | |
1014 | + int cy_old; | |
1015 | + | |
1016 | + cy_old=cy; | |
1017 | + while(cy<EDITWIDTHY-1){ | |
1018 | + // cy==EDITWIDTH-1になるまでカーソルを下に移動 | |
1019 | + y=cy; | |
1020 | + cursor_down(); | |
1021 | + if(y==cy) break;// バッファ最下行で移動できなかった場合抜ける | |
1022 | + } | |
1023 | + for(i=0;i<EDITWIDTHY-1;i++){ | |
1024 | + //画面行数-1行分カーソルを下に移動 | |
1025 | + bp=disptopbp; | |
1026 | + ix=disptopix; | |
1027 | + cursor_down(); | |
1028 | + if(bp==disptopbp && ix==disptopix) break; //最下行で移動できなかった場合抜ける | |
1029 | + } | |
1030 | + //下端からさらに移動した行数分、カーソルを上に移動、1行も動かなかった場合は最下行に留まる | |
1031 | + if(i>0) while(cy>cy_old) cursor_up(); | |
1032 | +} | |
1033 | +void cursor_top(void){ | |
1034 | +//カーソルをテキストバッファの先頭に移動 | |
1035 | + cursorbp=TBufstart; | |
1036 | + cursorix=0; | |
1037 | + cursorbp1=NULL; //範囲選択モード解除 | |
1038 | + disptopbp=cursorbp; | |
1039 | + disptopix=cursorix; | |
1040 | + cx=0; | |
1041 | + cx2=0; | |
1042 | + cy=0; | |
1043 | + line_no=1; | |
1044 | +} | |
1045 | + | |
1046 | +int countarea(void){ | |
1047 | +//テキストバッファの指定範囲の文字数をカウント | |
1048 | +//範囲は(cursorbp,cursorix)と(cursorbp1,cursorix1)で指定 | |
1049 | +//後ろ側の一つ前の文字までをカウント | |
1050 | + _tbuf *bp1,*bp2; | |
1051 | + int ix1,ix2; | |
1052 | + int n; | |
1053 | + | |
1054 | + //範囲選択モードの場合、開始位置と終了の前後判断して | |
1055 | + //bp1,ix1を開始位置、bp2,ix2を終了位置に設定 | |
1056 | + if(cy<cy1 || (cy==cy1 && cx<cx1)){ | |
1057 | + bp1=cursorbp; | |
1058 | + ix1=cursorix; | |
1059 | + bp2=cursorbp1; | |
1060 | + ix2=cursorix1; | |
1061 | + } | |
1062 | + else{ | |
1063 | + bp1=cursorbp1; | |
1064 | + ix1=cursorix1; | |
1065 | + bp2=cursorbp; | |
1066 | + ix2=cursorix; | |
1067 | + } | |
1068 | + n=0; | |
1069 | + while(1){ | |
1070 | + if(bp1==bp2 && ix1==ix2) return n; | |
1071 | + if(ix1 < bp1->n){ | |
1072 | + n++; | |
1073 | + ix1++; | |
1074 | + } | |
1075 | + else{ | |
1076 | + bp1=bp1->next; | |
1077 | + ix1=0; | |
1078 | + } | |
1079 | + } | |
1080 | +} | |
1081 | +void deletearea_len(_tbuf *bp,unsigned int ix,int n,int undo){ | |
1082 | +//テキストバッファの指定位置から複数文字削除 | |
1083 | +//bp,ix:削除開始位置 | |
1084 | +//n:削除する文字数 | |
1085 | +//undo:0:通常、2:アンドゥ中 | |
1086 | + unsigned char *p; | |
1087 | + int i; | |
1088 | + | |
1089 | + //選択範囲が最初のバッファの最後まである場合 | |
1090 | + if(n>=(bp->n - ix)){ | |
1091 | + if(!undo){ | |
1092 | + p=bp->Buf+ix; | |
1093 | + for(i=ix;i < bp->n;i++) pushundomem(*p++); //アンドゥバッファに格納 | |
1094 | + } | |
1095 | + n -= bp->n - ix; //削除文字数減 | |
1096 | + num-=bp->n - ix; //バッファ使用量を減数 | |
1097 | + bp->n=ix; //ix以降を削除 | |
1098 | + bp=bp->next; | |
1099 | + if(bp==NULL) return; | |
1100 | + ix=0; | |
1101 | + } | |
1102 | + //次のバッファ以降、選択範囲の終了位置が含まれないバッファは削除 | |
1103 | + while(n>=bp->n){ | |
1104 | + if(!undo){ | |
1105 | + p=bp->Buf; | |
1106 | + for(i=0;i < bp->n;i++) pushundomem(*p++); //アンドゥバッファに格納 | |
1107 | + } | |
1108 | + n-=bp->n; //削除文字数減 | |
1109 | + num-=bp->n; //バッファ使用量を減数 | |
1110 | + bp=deleteTBuf(bp); //バッファ削除して次のバッファに進む | |
1111 | + if(bp==NULL) return; | |
1112 | + } | |
1113 | + //選択範囲の終了位置を含む場合、1文字ずつ削除 | |
1114 | + if(!undo) undo=1; | |
1115 | + while(n>0){ | |
1116 | + deletechar(bp,ix,undo); //バッファから1文字削除(numは関数内で1減される) | |
1117 | + n--; | |
1118 | + } | |
1119 | +} | |
1120 | +void deletearea(void){ | |
1121 | +//テキストバッファの指定範囲を削除 | |
1122 | +//範囲は(cursorbp,cursorix)と(cursorbp1,cursorix1)で指定 | |
1123 | +//後ろ側の一つ前の文字までを削除 | |
1124 | +//削除後のカーソル位置は選択範囲の先頭にし、範囲選択モード解除する | |
1125 | + | |
1126 | + _tbuf *bp; | |
1127 | + int ix; | |
1128 | + int n; | |
1129 | + | |
1130 | + n=countarea(); //選択範囲の文字数カウント | |
1131 | + if(n==0) return; | |
1132 | + | |
1133 | + //範囲選択の開始位置と終了位置の前後を判断してカーソルを開始位置に設定 | |
1134 | + if(cy>cy1 || (cy==cy1 && cx>cx1)){ | |
1135 | + cursorbp=cursorbp1; | |
1136 | + cursorix=cursorix1; | |
1137 | + cx=cx1; | |
1138 | + cy=cy1; | |
1139 | + line_no=line_no1; | |
1140 | + } | |
1141 | + cx2=cx; | |
1142 | + cursorbp1=NULL; //範囲選択モード解除 | |
1143 | + | |
1144 | + //bp,ixを開始位置に設定 | |
1145 | + bp=cursorbp; | |
1146 | + ix=cursorix; | |
1147 | + | |
1148 | + setundobuf(UNDO_CONTDEL,bp,ix,0,n); //アンドゥバッファ設定(連続削除開始) | |
1149 | + deletearea_len(bp,ix,n,0); //n文字分削除 | |
1150 | + //アンドゥバッファに連続削除終了設定 | |
1151 | + pushundomem2(bpixtopos(bp,ix)); | |
1152 | + pushundomem2(n); | |
1153 | + pushundomem(UNDO_CONTDEL); | |
1154 | +} | |
1155 | +void clipcopy(void){ | |
1156 | +// 選択範囲をクリップボードにコピー | |
1157 | + _tbuf *bp1,*bp2; | |
1158 | + int ix1,ix2; | |
1159 | + char *ps,*pd; | |
1160 | + | |
1161 | + //範囲選択モードの場合、開始位置と終了の前後判断して | |
1162 | + //bp1,ix1を開始位置、bp2,ix2を終了位置に設定 | |
1163 | + if(cy<cy1 || (cy==cy1 && cx<cx1)){ | |
1164 | + bp1=cursorbp; | |
1165 | + ix1=cursorix; | |
1166 | + bp2=cursorbp1; | |
1167 | + ix2=cursorix1; | |
1168 | + } | |
1169 | + else{ | |
1170 | + bp1=cursorbp1; | |
1171 | + ix1=cursorix1; | |
1172 | + bp2=cursorbp; | |
1173 | + ix2=cursorix; | |
1174 | + } | |
1175 | + ps=bp1->Buf+ix1; | |
1176 | + pd=clipboard; | |
1177 | + clipsize=0; | |
1178 | + while(bp1!=bp2 || ix1!=ix2){ | |
1179 | + if(ix1 < bp1->n){ | |
1180 | + *pd++=*ps++; | |
1181 | + clipsize++; | |
1182 | + ix1++; | |
1183 | + } | |
1184 | + else{ | |
1185 | + bp1=bp1->next; | |
1186 | + ps=bp1->Buf; | |
1187 | + ix1=0; | |
1188 | + } | |
1189 | + } | |
1190 | +} | |
1191 | +void clippaste(void){ | |
1192 | +// クリップボードから貼り付け | |
1193 | + int n,i; | |
1194 | + unsigned char *p; | |
1195 | + | |
1196 | + if(clipsize==0 || num+clipsize>TBUFMAXSIZE) return; | |
1197 | + setundobuf(UNDO_CONTINS,cursorbp,cursorix,0,clipsize); //アンドゥバッファ設定 | |
1198 | + p=clipboard; | |
1199 | + for(n=clipsize;n>0;n--){ | |
1200 | + i=insertchar(cursorbp,cursorix,*p,1); | |
1201 | + if(i>0){ | |
1202 | + //バッファ空きがあるのに挿入失敗の場合 | |
1203 | + gabagecollect2(); //全体ガベージコレクション | |
1204 | + i=insertchar(cursorbp,cursorix,*p,1);//テキストバッファに1文字挿入 | |
1205 | + } | |
1206 | + if(i!=0) break;//挿入失敗 | |
1207 | + cursor_right();//画面上、バッファ上のカーソル位置を1つ後ろに移動 | |
1208 | + p++; | |
1209 | + } | |
1210 | +} | |
1211 | +void movecursor(int pos){ | |
1212 | +// カーソルを現在の位置から任意の位置に移動 | |
1213 | +// pos:移動したいテキストバッファ先頭からのバイト位置 | |
1214 | + int pos2,d; | |
1215 | + pos2=bpixtopos(cursorbp,cursorix); | |
1216 | + d=pos-pos2; | |
1217 | + if(d==0) return; | |
1218 | + if(d>0){ | |
1219 | + while(d>0){ | |
1220 | + cursor_right(); | |
1221 | + d--; | |
1222 | + } | |
1223 | + } | |
1224 | + else{ | |
1225 | + while(d<0){ | |
1226 | + cursor_left(); | |
1227 | + d++; | |
1228 | + } | |
1229 | + } | |
1230 | +} | |
1231 | +void undoexec(){ | |
1232 | +//アンドゥ実行 | |
1233 | + unsigned char c,c1; | |
1234 | + _tbuf *bp; | |
1235 | + unsigned short n,ix; | |
1236 | + int pos; | |
1237 | + | |
1238 | + if(undobuf_used==0) return; //アンドゥバッファ空 | |
1239 | + cursorbp1=NULL; //範囲選択解除 | |
1240 | + c=popundomem(); //アンドゥバッファ先頭の命令読み出し | |
1241 | + switch(c){ | |
1242 | + case UNDO_INSERT: //1文字挿入 | |
1243 | + //カーソル移動し1文字削除 | |
1244 | + pos=popundomem2(); | |
1245 | + movecursor(pos); | |
1246 | + bp=postobpix(pos,&ix); | |
1247 | + deletechar(bp,ix,2); | |
1248 | + popundomem(); //dummy read | |
1249 | + break; | |
1250 | + case UNDO_CONTINS: //連続挿入 | |
1251 | + //カーソル移動し連続数分削除 | |
1252 | + n=popundomem2(); | |
1253 | + pos=popundomem2(); | |
1254 | + movecursor(pos); | |
1255 | + bp=postobpix(pos,&ix); | |
1256 | + deletearea_len(bp,ix,n,2); | |
1257 | + popundomem(); //dummy read | |
1258 | + break; | |
1259 | + case UNDO_CONTDEL: //連続削除 | |
1260 | + //カーソル移動し連続数分、コードを読み出して挿入 | |
1261 | + n=popundomem2(); | |
1262 | + pos=popundomem2(); | |
1263 | + movecursor(pos); | |
1264 | + bp=postobpix(pos,&ix); | |
1265 | + while(n>0){ | |
1266 | + insertchar(bp,ix,popundomem(),2); | |
1267 | + n--; | |
1268 | + } | |
1269 | + popundomem2(); //dummy read | |
1270 | + popundomem(); //dummy read | |
1271 | + break; | |
1272 | + case 0: //0の場合、次の1バイトが実際の有効なコード | |
1273 | + c=popundomem(); | |
1274 | + default: //1文字削除(DEL、BS)、1文字上書き | |
1275 | + //カーソル移動し1文字挿入(または上書き) | |
1276 | + pos=popundomem2(); | |
1277 | + movecursor(pos); | |
1278 | + bp=postobpix(pos,&ix); | |
1279 | + c1=popundomem(); | |
1280 | + if(c1==UNDO_OVERWRITE){ | |
1281 | + overwritechar(bp,ix,c,2); | |
1282 | + } | |
1283 | + else{ | |
1284 | + insertchar(bp,ix,c,2); | |
1285 | + if(c1==UNDO_BACKSPACE) cursor_right(); | |
1286 | + } | |
1287 | + break; | |
1288 | + } | |
1289 | +} | |
1290 | + | |
1291 | +void set_areamode(){ | |
1292 | +//範囲選択モード開始時のカーソル開始位置グローバル変数設定 | |
1293 | + cursorbp1=cursorbp; | |
1294 | + cursorix1=cursorix; | |
1295 | + cx1=cx; | |
1296 | + cy1=cy; | |
1297 | + line_no1=line_no; | |
1298 | +} | |
1299 | +void save_cursor(void){ | |
1300 | +//カーソル関連グローバル変数を一時避難 | |
1301 | + cursorbp_t=cursorbp; | |
1302 | + cursorix_t=cursorix; | |
1303 | + disptopbp_t=disptopbp; | |
1304 | + disptopix_t=disptopix; | |
1305 | + cx_t=cx; | |
1306 | + cy_t=cy; | |
1307 | + line_no_t=line_no; | |
1308 | +} | |
1309 | +void restore_cursor(void){ | |
1310 | +//カーソル関連グローバル変数を一時避難場所から戻す | |
1311 | + cursorbp=cursorbp_t; | |
1312 | + cursorix=cursorix_t; | |
1313 | + disptopbp=disptopbp_t; | |
1314 | + disptopix=disptopix_t; | |
1315 | + cx=cx_t; | |
1316 | + cy=cy_t; | |
1317 | + line_no=line_no_t; | |
1318 | +} | |
1319 | + | |
1320 | +int filesystemretry(){ | |
1321 | +// SDファイルシステムの再初期化確認と実施 | |
1322 | +// SDファイルへの保存や読み込み時にファイルエラーが発生した場合に呼び出す | |
1323 | +// 戻り値 0:初期化成功、-1:成功することなくEscapeで抜けた | |
1324 | + unsigned short vk; | |
1325 | + while(1){ | |
1326 | + setcursorcolor(COLOR_NORMALTEXT); | |
1327 | + printstr((unsigned char *)Message3); //Retry / Quit | |
1328 | + while(1){ | |
1329 | + inputchar(); //1文字入力待ち | |
1330 | + vk=vkey & 0xff; | |
1331 | + if(vk==VK_RETURN || vk==VK_SEPARATOR) break; | |
1332 | + if(vk==VK_ESCAPE) return -1; | |
1333 | + } | |
1334 | + //ファイルシステム初期化 | |
1335 | + if(FSInit()!=FALSE) return 0; //成功 | |
1336 | + //エラーの場合 | |
1337 | + setcursorcolor(COLOR_ERRORTEXT); | |
1338 | + printstr((unsigned char *)Message2);//File System Error | |
1339 | + } | |
1340 | +} | |
1341 | + | |
1342 | +int sdfilecopy(char *sourcefile,char *distfile){ | |
1343 | +// SDカード上のファイルをコピー | |
1344 | +// soucefile:コピー元ファイル名 | |
1345 | +// distfile:コピー先ファイル名 | |
1346 | +// 戻り値:正常終了 0、エラー終了時エラー番号 | |
1347 | + FSFILE *sfp,*dfp; | |
1348 | + int n,er,c; | |
1349 | + er=0; | |
1350 | + sfp=FSfopen(sourcefile,"r"); | |
1351 | + if(sfp==NULL) return ERR_CANTFILEOPEN; | |
1352 | + dfp=FSfopen(distfile,"w"); | |
1353 | + if(dfp==NULL){ | |
1354 | + FSfclose(sfp); | |
1355 | + return ERR_CANTFILEOPEN; | |
1356 | + } | |
1357 | + c=0; | |
1358 | + while(1){ | |
1359 | + if(c==0){ | |
1360 | + printchar('.'); | |
1361 | + c=100; | |
1362 | + } | |
1363 | + c--; | |
1364 | + n=FSfread(filebuf,1,FILEBUFSIZE,sfp); | |
1365 | + if(n==0) break; | |
1366 | + if(FSfwrite(filebuf,1,n,dfp)!=n){ | |
1367 | + er=ERR_CANTWRITEFILE; | |
1368 | + break; | |
1369 | + } | |
1370 | + } | |
1371 | + FSfclose(sfp); | |
1372 | + FSfclose(dfp); | |
1373 | + return er; | |
1374 | +} | |
1375 | +int savetextfile(char *filename){ | |
1376 | +// テキストバッファをテキストファイルに書き込み | |
1377 | +// 書き込み成功で0、失敗でエラーコード(負数)を返す | |
1378 | + FSFILE *fp; | |
1379 | + _tbuf *bp; | |
1380 | + int ix,n,i,er; | |
1381 | + unsigned char *ps,*pd; | |
1382 | + er=0;//エラーコード | |
1383 | + i=-1; | |
1384 | + fp=FSfopen(filename,"w"); | |
1385 | + if(fp==NULL) return ERR_CANTFILEOPEN; | |
1386 | + bp=TBufstart; | |
1387 | + ix=0; | |
1388 | + ps=bp->Buf; | |
1389 | + do{ | |
1390 | + pd=filebuf; | |
1391 | + n=0; | |
1392 | + while(n<FILEBUFSIZE-1){ | |
1393 | + //改行コードが2バイトになることを考慮してバッファサイズ-1までとする | |
1394 | + while(ix>=bp->n){ | |
1395 | + bp=bp->next; | |
1396 | + if(bp==NULL){ | |
1397 | + break; | |
1398 | + } | |
1399 | + ix=0; | |
1400 | + ps=bp->Buf; | |
1401 | + } | |
1402 | + if(bp==NULL) break; | |
1403 | + if(*ps=='\n'){ | |
1404 | + *pd++='\r'; //改行コード0A→0D 0Aにする | |
1405 | + n++; | |
1406 | + } | |
1407 | + *pd++=*ps++; | |
1408 | + ix++; | |
1409 | + n++; | |
1410 | + } | |
1411 | + if(n>0){ | |
1412 | + i=FSfwrite(filebuf,1,n,fp); | |
1413 | + if(i!=n) er=ERR_CANTWRITEFILE; | |
1414 | + } | |
1415 | + } while(bp!=NULL && er==0); | |
1416 | + FSfclose(fp); | |
1417 | + return er; | |
1418 | +} | |
1419 | +int loadtextfile(char *filename){ | |
1420 | +// テキストファイルをテキストバッファに読み込み | |
1421 | +// 読み込み成功で0、失敗でエラーコード(負数)を返す | |
1422 | + FSFILE *fp; | |
1423 | + _tbuf *bp; | |
1424 | + int ix,n,i,er; | |
1425 | + unsigned char *ps,*pd; | |
1426 | + er=0;//エラーコード | |
1427 | + fp=FSfopen(filename,"r"); | |
1428 | + if(fp==NULL) return ERR_CANTFILEOPEN; | |
1429 | + inittextbuf(); | |
1430 | + bp=TextBuffer; | |
1431 | + ix=0; | |
1432 | + pd=bp->Buf; | |
1433 | + do{ | |
1434 | + n=FSfread(filebuf,1,FILEBUFSIZE,fp); | |
1435 | + ps=filebuf; | |
1436 | + for(i=0;i<n;i++){ | |
1437 | + if(ix>=TBUFSIZE){ | |
1438 | + bp->n=TBUFSIZE; | |
1439 | + bp=newTBuf(bp); | |
1440 | + if(bp==NULL){ | |
1441 | + er=ERR_FILETOOBIG; | |
1442 | + break; | |
1443 | + } | |
1444 | + ix=0; | |
1445 | + pd=bp->Buf; | |
1446 | + } | |
1447 | + if(*ps=='\r') ps++; //改行コード0D 0A→0Aにする(単純に0D無視) | |
1448 | + else{ | |
1449 | + *pd++=*ps++; | |
1450 | + ix++; | |
1451 | + num++;//バッファ総文字数 | |
1452 | + if(num>TBUFMAXSIZE){ | |
1453 | + er=ERR_FILETOOBIG; | |
1454 | + break; | |
1455 | + } | |
1456 | + } | |
1457 | + } | |
1458 | + } while(n==FILEBUFSIZE && er==0); | |
1459 | + if(bp!=NULL) bp->n=ix;//最後のバッファの文字数 | |
1460 | + FSfclose(fp); | |
1461 | + if(er){ | |
1462 | + //エラー発生の場合バッファ、カーソル位置初期化 | |
1463 | + inittextbuf(); | |
1464 | + cursor_top(); | |
1465 | + } | |
1466 | + return er; | |
1467 | +} | |
1468 | +int overwritecheck(char *fn){ | |
1469 | +// ファイルの上書き確認 | |
1470 | +// ファイルの存在をチェックし、存在する場合キーボードから上書き確認する | |
1471 | +// fn:ファイル名へのポインタ | |
1472 | +// 戻り値 0:存在しないまたは上書き、-1:上書きしない | |
1473 | + SearchRec sr; | |
1474 | + unsigned short vk; | |
1475 | + if(FindFirst(fn,ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE,&sr)) return 0; //ファイルが存在しない | |
1476 | + setcursorcolor(COLOR_ERRORTEXT); | |
1477 | + printstr(fn); | |
1478 | + printstr(": File Exists\n"); | |
1479 | + setcursorcolor(COLOR_NORMALTEXT); | |
1480 | + printstr("Ovewrite:[Enter] / Stop:[ESC]\n"); | |
1481 | + while(1){ | |
1482 | + inputchar(); //1文字入力待ち | |
1483 | + vk=vkey & 0xff; | |
1484 | + if(vk==VK_RETURN || vk==VK_SEPARATOR) return 0; | |
1485 | + if(vk==VK_ESCAPE) return -1; | |
1486 | + } | |
1487 | +} | |
1488 | +void printfilename(unsigned char x,unsigned char y,int f,int num_dir){ | |
1489 | +// x,yの位置にファイル名またはディレクトリ名を表示 | |
1490 | + | |
1491 | + if(f==-2){ | |
1492 | + setcursor(x,y,COLOR_ERRORTEXT); | |
1493 | + printchar('<'); | |
1494 | + printstr("New FILE"); | |
1495 | + printchar('>'); | |
1496 | + } | |
1497 | + else if(f==-1){ | |
1498 | + setcursor(x,y,COLOR_ERRORTEXT); | |
1499 | + printchar('<'); | |
1500 | + printstr("New Dir"); | |
1501 | + printchar('>'); | |
1502 | + } | |
1503 | + else if(f<num_dir){ | |
1504 | + setcursor(x,y,COLOR_DIR); | |
1505 | + printchar('['); | |
1506 | + printstr(filenames[f]); | |
1507 | + printchar(']'); | |
1508 | + } | |
1509 | + else{ | |
1510 | + setcursor(x,y,COLOR_NORMALTEXT); | |
1511 | + printstr(filenames[f]); | |
1512 | + } | |
1513 | +} | |
1514 | +int select_dir_file(int filenum,int num_dir, unsigned char* msg){ | |
1515 | +// filenames[]配列に読み込まれたファイルまたはディレクトリを画面表示しキーボードで選択する | |
1516 | +// filenum:ファイル+ディレクトリ数 | |
1517 | +// num_dir:ディレクトリ数(filenames[]は先頭からnum_dir-1までがディレクトリ) | |
1518 | +// msg:画面上部に表示するメッセージ | |
1519 | +// 戻り値 | |
1520 | +// filenames[]の選択されたファイルまたはディレクトリ番号 | |
1521 | +// -1:新規ディレクトリ作成、tempfile[]にディレクトリ名 | |
1522 | +// -2:新規ファイル作成、tempfile[]にファイル名 | |
1523 | +// -3:ESCキーが押された | |
1524 | + int top,f; | |
1525 | + unsigned char *ps,*pd; | |
1526 | + int x,y; | |
1527 | + unsigned char vk; | |
1528 | + unsigned char vm; | |
1529 | + | |
1530 | + //ファイル一覧を画面に表示 | |
1531 | + vm=videomode; | |
1532 | + set_videomode(VMODE_STDTEXT,0); | |
1533 | + cls(); | |
1534 | + setcursor(0,0,COLOR_NORMALTEXT); | |
1535 | + printstr(msg); | |
1536 | + printstr(": "); | |
1537 | + setcursorcolor(4); | |
1538 | + printstr("Select&[Enter] / [ESC]\n"); | |
1539 | + for(f=-2;f<filenum;f++){ | |
1540 | + x=(f&1)*15+1; | |
1541 | + y=(f+2)/2+1; | |
1542 | + if(y>=twidthy-1) break; | |
1543 | + printfilename(x,y,f,num_dir); | |
1544 | + } | |
1545 | + top=-2;//画面一番先頭のファイル番号 | |
1546 | + f=-2;//現在選択中のファイル番号 | |
1547 | + while(1){ | |
1548 | + setcursor((f&1)*15,(f-top)/2+1,5); | |
1549 | + printchar(0x1c);// Right Arrow | |
1550 | + cursor--; | |
1551 | + while(1){ | |
1552 | + inputchar(); | |
1553 | + vk=vkey & 0xff; | |
1554 | + if(vk) break; | |
1555 | + } | |
1556 | + printchar(' '); | |
1557 | + setcursor(0,twidthy-1,COLOR_NORMALTEXT); | |
1558 | + for(x=0;x<twidth-1;x++) printchar(' '); //最下行のステータス表示を消去 | |
1559 | + switch(vk){ | |
1560 | + case VK_UP: | |
1561 | + case VK_NUMPAD8: | |
1562 | + //上矢印キー | |
1563 | + if(f>=0){ | |
1564 | + f-=2; | |
1565 | + if(f<top){ | |
1566 | + //画面最上部の場合、下にスクロールして最上部にファイル名2つ表示 | |
1567 | + setcursor(twidth-1,twidthy-2,COLOR_NORMALTEXT); | |
1568 | + while(cursor>=TVRAM+twidth*2){ | |
1569 | + *cursor=*(cursor-twidth); | |
1570 | + *(cursor+attroffset)=*(cursor+attroffset-twidth); | |
1571 | + cursor--; | |
1572 | + } | |
1573 | + while(cursor>=TVRAM+twidth) *cursor--=' '; | |
1574 | + top-=2; | |
1575 | + printfilename(1,1,top,num_dir); | |
1576 | + printfilename(16,1,top+1,num_dir); | |
1577 | + } | |
1578 | + } | |
1579 | + break; | |
1580 | + case VK_DOWN: | |
1581 | + case VK_NUMPAD2: | |
1582 | + //下矢印キー | |
1583 | + if(((f+2)&0xfffe)<filenum){ | |
1584 | + f+=2; | |
1585 | + if(f>=filenum) f--; | |
1586 | + if(f-top>=(twidthy-2)*2){ | |
1587 | + //画面最下部の場合、上にスクロールして最下部にファイル名1つor2つ表示 | |
1588 | + setcursor(0,1,COLOR_NORMALTEXT); | |
1589 | + while(cursor<TVRAM+twidth*(twidthy-2)){ | |
1590 | + *cursor=*(cursor+twidth); | |
1591 | + *(cursor+attroffset)=*(cursor+attroffset+twidth); | |
1592 | + cursor++; | |
1593 | + } | |
1594 | + while(cursor<TVRAM+twidth*(twidthy-1)) *cursor++=' '; | |
1595 | + top+=2; | |
1596 | + printfilename(1,twidthy-2,f&0xfffe,num_dir); | |
1597 | + if((f|1)<filenum){ | |
1598 | + printfilename(16,twidthy-2,f|1,num_dir); | |
1599 | + } | |
1600 | + } | |
1601 | + } | |
1602 | + break; | |
1603 | + case VK_LEFT: | |
1604 | + case VK_NUMPAD4: | |
1605 | + //左矢印キー | |
1606 | + if(f&1) f--; | |
1607 | + break; | |
1608 | + case VK_RIGHT: | |
1609 | + case VK_NUMPAD6: | |
1610 | + //右矢印キー | |
1611 | + if((f&1)==0 && f+1<filenum) f++; | |
1612 | + break; | |
1613 | + case VK_RETURN: //Enterキー | |
1614 | + case VK_SEPARATOR: //テンキーのEnter | |
1615 | + if(f==-2){ | |
1616 | + //新規ファイル | |
1617 | + setcursor(0,twidthy-1,COLOR_ERRORTEXT); | |
1618 | + printstr("Input File Name: "); | |
1619 | + setcursorcolor(COLOR_NORMALTEXT); | |
1620 | + //ファイル名入力 | |
1621 | + *tempfile=0; | |
1622 | + if(lineinput(tempfile,8+1+3)<0) break; //ESCキー | |
1623 | + if(*tempfile==0) break; //ファイル名入力なし | |
1624 | + } | |
1625 | + else if(f==-1){ | |
1626 | + //新規ディレクトリ | |
1627 | + setcursor(0,twidthy-1,COLOR_ERRORTEXT); | |
1628 | + printstr("Input Dir Name: "); | |
1629 | + setcursorcolor(COLOR_NORMALTEXT); | |
1630 | + //ディレクトリ名入力 | |
1631 | + *tempfile=0; | |
1632 | + if(lineinput(tempfile,8+1+3)<0) break; //ESCキー | |
1633 | + if(FSmkdir(tempfile)){ | |
1634 | + setcursor(0,twidthy-1,COLOR_ERRORTEXT); | |
1635 | + printstr("Cannot Make Directory "); | |
1636 | + break; | |
1637 | + } | |
1638 | + } | |
1639 | + else{ | |
1640 | + //ファイル名またはディレクトリ名をtempfileにコピー | |
1641 | + ps=filenames[f]; | |
1642 | + pd=tempfile; | |
1643 | + while(*ps) *pd++=*ps++; | |
1644 | + *pd=0; | |
1645 | + } | |
1646 | + set_videomode(vm,0); | |
1647 | + return f; | |
1648 | + case VK_ESCAPE: | |
1649 | + //ESCキー | |
1650 | + set_videomode(vm,0); | |
1651 | + return -3; | |
1652 | + } | |
1653 | + } | |
1654 | +} | |
1655 | +int getfilelist(int *p_num_dir){ | |
1656 | +// カレントディレクトリでのディレクトリ、.BAS、.TXT、.INIファイル一覧を読み込む | |
1657 | +// *p_num_dir:ディレクトリ数を返す | |
1658 | +// filenames[]:ファイル名およびディレクトリ名一覧 | |
1659 | +// 戻り値 ファイル+ディレクトリ数 | |
1660 | + | |
1661 | + unsigned char *ps,*pd; | |
1662 | + int filenum; | |
1663 | + SearchRec sr; | |
1664 | + filenum=0; | |
1665 | + //ディレクトリのサーチ | |
1666 | + if(FindFirst("*.*",ATTR_DIRECTORY,&sr)==0){ | |
1667 | + do{ | |
1668 | + //filenames[]にディレクトリ名の一覧を読み込み | |
1669 | + ps=sr.filename; | |
1670 | + pd=filenames[filenum]; | |
1671 | + while(*ps!=0) *pd++=*ps++; | |
1672 | + *pd=0; | |
1673 | + filenum++; | |
1674 | + } | |
1675 | + while(!FindNext(&sr) && filenum<MAXFILENUM); | |
1676 | + } | |
1677 | + *p_num_dir=filenum; | |
1678 | + if(filenum>=MAXFILENUM) return filenum; | |
1679 | + //拡張子 BASファイルのサーチ | |
1680 | + if(FindFirst("*.BAS",ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE,&sr)==0){ | |
1681 | + do{ | |
1682 | + //filenames[]にファイル名の一覧を読み込み | |
1683 | + ps=sr.filename; | |
1684 | + pd=filenames[filenum]; | |
1685 | + while(*ps!=0) *pd++=*ps++; | |
1686 | + *pd=0; | |
1687 | + filenum++; | |
1688 | + } | |
1689 | + while(!FindNext(&sr) && filenum<MAXFILENUM); | |
1690 | + } | |
1691 | + if(filenum>=MAXFILENUM) return filenum; | |
1692 | + //拡張子 TXTファイルのサーチ | |
1693 | + if(FindFirst("*.TXT",ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE,&sr)==0){ | |
1694 | + do{ | |
1695 | + //filenames[]にファイル名の一覧を読み込み | |
1696 | + ps=sr.filename; | |
1697 | + pd=filenames[filenum]; | |
1698 | + while(*ps!=0) *pd++=*ps++; | |
1699 | + *pd=0; | |
1700 | + filenum++; | |
1701 | + } | |
1702 | + while(!FindNext(&sr) && filenum<MAXFILENUM); | |
1703 | + } | |
1704 | + if(filenum>=MAXFILENUM) return filenum; | |
1705 | + //拡張子 INIファイルのサーチ | |
1706 | + if(FindFirst("*.INI",ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE,&sr)==0){ | |
1707 | + do{ | |
1708 | + //filenames[]にファイル名の一覧を読み込み | |
1709 | + ps=sr.filename; | |
1710 | + pd=filenames[filenum]; | |
1711 | + while(*ps!=0) *pd++=*ps++; | |
1712 | + *pd=0; | |
1713 | + filenum++; | |
1714 | + } | |
1715 | + while(!FindNext(&sr) && filenum<MAXFILENUM); | |
1716 | + } | |
1717 | + return filenum; | |
1718 | +} | |
1719 | +void save_as(int ow){ | |
1720 | +// 現在のテキストバッファの内容をSDカードに保存 | |
1721 | +// ow 0:名前を付けて保存 1:上書き保存 | |
1722 | +// ファイル名はグローバル変数currentfile[] | |
1723 | +// ファイル名はキーボードから変更可能 | |
1724 | +// 成功した場合currentfileを更新 | |
1725 | + | |
1726 | + int er; | |
1727 | + int filenum,num_dir,f; | |
1728 | + unsigned char *ps,*pd; | |
1729 | + | |
1730 | + cls(); | |
1731 | + setcursor(0,0,COLOR_NORMALTEXT); | |
1732 | + printstr("Save To SD Card\n"); | |
1733 | + if(currentfile[0]==0) ow=0; //ファイル名が設定されていない場合名前を付けて保存 | |
1734 | + | |
1735 | + //currentfileからtempfileにコピー | |
1736 | + ps=currentfile; | |
1737 | + pd=tempfile; | |
1738 | + while(*ps!=0) *pd++=*ps++; | |
1739 | + *pd=0; | |
1740 | + | |
1741 | + //カレントディレクトリを変数cwdpathにコピー | |
1742 | + while(1){ | |
1743 | + if(FSgetcwd(cwdpath,PATHNAMEMAX)) break; | |
1744 | + setcursorcolor(COLOR_ERRORTEXT); | |
1745 | + printstr("Cannot Get Current Dir\n"); | |
1746 | + if(filesystemretry()) return; //ファイルシステム再初期化、あきらめた場合はreturnする | |
1747 | + } | |
1748 | + //現在のディレクトリのパスを表示 | |
1749 | + setcursorcolor(COLOR_NORMALTEXT); | |
1750 | + printstr("Current Directory is\n"); | |
1751 | + printstr(cwdpath); | |
1752 | + printchar('\n'); | |
1753 | + while(1){ | |
1754 | + if(ow==0){ | |
1755 | + printstr("Input File Name + [Enter]\n"); | |
1756 | + printstr("[ESC] Select File/Dir or Quit\n"); | |
1757 | + //ファイル名入力 | |
1758 | + if(lineinput(tempfile,8+1+3)<0){ | |
1759 | + //ESCキーが押された場合、ファイル選択、ディレクトリ変更画面または終了 | |
1760 | + while(1){ | |
1761 | + filenum=getfilelist(&num_dir); //ディレクトリ、ファイル名一覧を読み込み | |
1762 | + f=select_dir_file(filenum,num_dir,"Save"); //ファイルの選択 | |
1763 | + cls(); | |
1764 | + if(f==-3){ | |
1765 | + //終了 | |
1766 | + FSchdir(cwdpath);//カレントディレクトリを元に戻す | |
1767 | + return; | |
1768 | + } | |
1769 | + else if(f==-2){ | |
1770 | + //新規ファイル | |
1771 | + if(overwritecheck(tempfile)==0) break;//上書きチェック | |
1772 | + } | |
1773 | + else if(f<num_dir){ | |
1774 | + //新規ディレクトリまたはディレクトリ変更 | |
1775 | + FSchdir(tempfile);//ディレクトリ変更して再度ファイル一覧へ | |
1776 | + } | |
1777 | + else break; | |
1778 | + } | |
1779 | + } | |
1780 | + else{ | |
1781 | + if(*tempfile==0) continue; //NULL文字列の場合 | |
1782 | + if(overwritecheck(tempfile)) continue; | |
1783 | + } | |
1784 | + } | |
1785 | + printstr("Writing...\n"); | |
1786 | + er=savetextfile(tempfile); //ファイル保存、er:エラーコード | |
1787 | + if(er==0){ | |
1788 | + printstr("OK"); | |
1789 | + FSremove(TEMPFILENAME); //実行時に生成する一時ファイルを削除 | |
1790 | + //tempfileからcurrentfileにコピーして終了 | |
1791 | + ps=tempfile; | |
1792 | + pd=currentfile; | |
1793 | + while(*ps!=0) *pd++=*ps++; | |
1794 | + *pd=0; | |
1795 | + FSgetcwd(cwdpath,PATHNAMEMAX); //カレントパスを更新 | |
1796 | + edited=0; //編集済みフラグクリア | |
1797 | + wait60thsec(60);//1秒待ち | |
1798 | + return; | |
1799 | + } | |
1800 | + setcursorcolor(COLOR_ERRORTEXT); | |
1801 | + if(er==ERR_CANTFILEOPEN) printstr("Bad File Name or File Error\n"); | |
1802 | + else printstr("Cannot Write\n"); | |
1803 | + if(filesystemretry()) return; //ファイルシステム再初期化、あきらめた場合はreturnする | |
1804 | + } | |
1805 | +} | |
1806 | + | |
1807 | +void newtext(void){ | |
1808 | +// 新規テキスト作成 | |
1809 | + unsigned char vk; | |
1810 | + if(edited && num){ | |
1811 | + //最終保存後に編集済みの場合、保存の確認 | |
1812 | + cls(); | |
1813 | + setcursorcolor(COLOR_NORMALTEXT); | |
1814 | + printstr("Save Editing File?\n"); | |
1815 | + printstr("Save:[Enter] / Not Save:[ESC]\n"); | |
1816 | + while(1){ | |
1817 | + inputchar(); //1文字キー入力待ち | |
1818 | + vk=vkey & 0xff; | |
1819 | + if(vk==VK_RETURN || vk==VK_SEPARATOR){ | |
1820 | + save_as(0); //名前を付けて保存 | |
1821 | + break; | |
1822 | + } | |
1823 | + else if(vk==VK_ESCAPE) break; | |
1824 | + } | |
1825 | + } | |
1826 | + inittextbuf(); //テキストバッファ初期化 | |
1827 | + cursor_top(); //カーソルをテキストバッファの先頭に設定 | |
1828 | + currentfile[0]=0; //作業中ファイル名クリア | |
1829 | +} | |
1830 | + | |
1831 | +void msra(void){ | |
1832 | +// Make Self-Running Application (自己実行アプリケーションの作成) | |
1833 | +// 最初にソースファイルを名前を付けて保存 | |
1834 | +// 次にBASICシステムのHEXファイルをソースファイル名の拡張子をHEXにした名前でコピー | |
1835 | + | |
1836 | + int er; | |
1837 | + unsigned char *ps,*pd; | |
1838 | + cls(); | |
1839 | + setcursor(0,0,COLOR_NORMALTEXT); | |
1840 | + printstr("Make Self-Running Application\n\n"); | |
1841 | + printstr("(Work on Root Directory)\n"); | |
1842 | + | |
1843 | + //カレントディレクトリを変数cwdpathにコピー | |
1844 | + while(1){ | |
1845 | + if(FSgetcwd(cwdpath,PATHNAMEMAX)) break; | |
1846 | + setcursorcolor(COLOR_ERRORTEXT); | |
1847 | + printstr("Cannot Get Current Dir\n"); | |
1848 | + if(filesystemretry()) return; //ファイルシステム再初期化、あきらめた場合はreturnする | |
1849 | + } | |
1850 | + while(1){ | |
1851 | + //カレントディレクトリをルートに変更 | |
1852 | + if(FSchdir((char *)ROOTDIR)==0) break; | |
1853 | + setcursorcolor(COLOR_ERRORTEXT); | |
1854 | + printstr("Cannot Change To Root Dir\n"); | |
1855 | + if(filesystemretry()) return; //ファイルシステム再初期化、あきらめた場合はreturnする | |
1856 | + } | |
1857 | + //currentfileからtempfileにコピー | |
1858 | + ps=currentfile; | |
1859 | + pd=tempfile; | |
1860 | + while(*ps!=0) *pd++=*ps++; | |
1861 | + *pd=0; | |
1862 | + | |
1863 | + while(1){ | |
1864 | + setcursorcolor(COLOR_NORMALTEXT); | |
1865 | + printstr("Input File Name (xxx.BAS)\n"); | |
1866 | + if(lineinput(tempfile,8+1+3)<0){ | |
1867 | + //ESCキーが押された | |
1868 | + FSchdir(cwdpath); //カレントディレクトリを元に戻す | |
1869 | + return; | |
1870 | + } | |
1871 | + ps=tempfile; | |
1872 | + while(*ps!='.' && *ps!=0) ps++; | |
1873 | + if(ps+4>=tempfile+13 || | |
1874 | + *ps!='.' || | |
1875 | + (*(ps+1)!='b' && *(ps+1)!='B') || | |
1876 | + (*(ps+2)!='a' && *(ps+2)!='A') || | |
1877 | + (*(ps+3)!='s' && *(ps+3)!='S') || | |
1878 | + *(ps+4)!=0){ | |
1879 | + setcursorcolor(COLOR_ERRORTEXT); | |
1880 | + printstr("File Name Must Be xxx.BAS\n"); | |
1881 | + continue; | |
1882 | + } | |
1883 | + if(overwritecheck(tempfile)) continue; | |
1884 | + printstr("Writing BASIC File\n"); | |
1885 | + er=savetextfile(tempfile); //ファイル保存、er:エラーコード | |
1886 | + if(er==0) break; | |
1887 | + setcursorcolor(COLOR_ERRORTEXT); | |
1888 | + if(er==ERR_CANTFILEOPEN) printstr("Bad File Name or File Error\n"); | |
1889 | + else printstr("Cannot Write\n"); | |
1890 | + | |
1891 | + //ファイルシステム再初期化、あきらめた場合はreturnする | |
1892 | + if(filesystemretry()){ | |
1893 | + if(FSchdir(cwdpath)){ | |
1894 | + cwdpath[0]='\\'; | |
1895 | + cwdpath[1]=0; | |
1896 | + } | |
1897 | + return; | |
1898 | + } | |
1899 | + } | |
1900 | + printstr("OK\n\n"); | |
1901 | + FSremove(TEMPFILENAME); //実行時に生成する一時ファイルを削除 | |
1902 | + //tempfileからcurrentfileにコピーして終了 | |
1903 | + ps=tempfile; | |
1904 | + pd=currentfile; | |
1905 | + while(*ps!=0) *pd++=*ps++; | |
1906 | + *pd=0; | |
1907 | + edited=0; //編集済みフラグクリア | |
1908 | + // 拡張子をHEXにしてBASICシステムファイルをコピー | |
1909 | + *(ps-3)='H'; | |
1910 | + *(ps-2)='E'; | |
1911 | + *(ps-1)='X'; | |
1912 | + if(overwritecheck(tempfile)) return; | |
1913 | + printstr("Copying\n"); | |
1914 | + printstr(HEXFILE); | |
1915 | + printstr(" To "); | |
1916 | + printstr(tempfile); | |
1917 | + printstr("\nWait For A While"); | |
1918 | + er=sdfilecopy(HEXFILE,tempfile); | |
1919 | + if(FSchdir(cwdpath)){ | |
1920 | + cwdpath[0]='\\'; | |
1921 | + cwdpath[1]=0; | |
1922 | + } | |
1923 | + if(er==0){ | |
1924 | + printstr("\nDone"); | |
1925 | + wait60thsec(120);//2秒待ち | |
1926 | + return; | |
1927 | + } | |
1928 | + setcursorcolor(COLOR_ERRORTEXT); | |
1929 | + if(er==ERR_CANTFILEOPEN){ | |
1930 | + printstr(HEXFILE); | |
1931 | + printstr(" Not Found\n"); | |
1932 | + } | |
1933 | + else if(er==ERR_CANTWRITEFILE){ | |
1934 | + printstr("Write Error\n"); | |
1935 | + } | |
1936 | + setcursorcolor(COLOR_NORMALTEXT); | |
1937 | + printstr((unsigned char *)Message1);// Hit Any Key | |
1938 | + inputchar(); //1文字入力待ち | |
1939 | + return; | |
1940 | +} | |
1941 | +int fileload(void){ | |
1942 | +// SDカードからファイルを選択して読み込み | |
1943 | +// currenfile[]にファイル名を記憶 | |
1944 | +// 対象ファイル拡張子 BASおよびTXT | |
1945 | +// 戻り値 0:読み込みを行った -1:読み込みなし | |
1946 | + int filenum,f,er; | |
1947 | + unsigned char *ps,*pd; | |
1948 | + unsigned char vk; | |
1949 | + int num_dir;//ディレクトリ数 | |
1950 | + | |
1951 | + //ファイルの一覧をSDカードから読み出し | |
1952 | + cls(); | |
1953 | + if(edited && num){ | |
1954 | + //最終保存後に編集済みの場合、保存の確認 | |
1955 | + setcursorcolor(COLOR_NORMALTEXT); | |
1956 | + printstr("Save Program Before Load?\n"); | |
1957 | + printstr("Save:[Enter] / Not Save:[ESC]\n"); | |
1958 | + while(1){ | |
1959 | + inputchar(); //1文字キー入力待ち | |
1960 | + vk=vkey & 0xff; | |
1961 | + if(vk==VK_RETURN || vk==VK_SEPARATOR){ | |
1962 | + save_as(0); //名前を付けて保存 | |
1963 | + break; | |
1964 | + } | |
1965 | + else if(vk==VK_ESCAPE) break; | |
1966 | + } | |
1967 | + } | |
1968 | + //カレントディレクトリを変数cwdpathにコピー | |
1969 | + while(1){ | |
1970 | + if(FSgetcwd(cwdpath,PATHNAMEMAX)) break; | |
1971 | + setcursorcolor(COLOR_ERRORTEXT); | |
1972 | + printstr("Cannot Get Current Dir\n"); | |
1973 | + if(filesystemretry()) return -1; //ファイルシステム再初期化、あきらめた場合はreturnする | |
1974 | + } | |
1975 | + while(1){ | |
1976 | + filenum=getfilelist(&num_dir); //ディレクトリ、ファイル名一覧を読み込み | |
1977 | + if(filenum==0){ | |
1978 | + setcursorcolor(COLOR_ERRORTEXT); | |
1979 | + printstr(".BAS or .TXT File Not Found\n"); | |
1980 | + printstr((unsigned char *)Message1);// Hit Any Key | |
1981 | + inputchar(); //1文字入力待ち | |
1982 | + FSchdir(cwdpath);//カレントディレクトリを元に戻す | |
1983 | + return -1; | |
1984 | + } | |
1985 | + //ファイルの選択 | |
1986 | + f=select_dir_file(filenum,num_dir,"Load"); | |
1987 | + if(f==-3){ | |
1988 | + //読み込まずに終了 | |
1989 | + FSchdir(cwdpath);//カレントディレクトリを元に戻す | |
1990 | + return -1; | |
1991 | + } | |
1992 | + else if(f==-2){ | |
1993 | + //新規ファイルまたはファイル名を入力して読み込み | |
1994 | + er=loadtextfile(tempfile); //テキストバッファにファイル読み込み | |
1995 | + if(er==ERR_CANTFILEOPEN){ | |
1996 | + //ファイルが存在しない場合、新規テキスト | |
1997 | + edited=0; | |
1998 | + newtext(); | |
1999 | + } | |
2000 | + else if(er==ERR_FILETOOBIG){ | |
2001 | + //ファイルサイズエラーの場合、選択画面に戻る | |
2002 | + setcursor(0,twidthy-1,COLOR_ERRORTEXT); | |
2003 | + printstr("File Too Big "); | |
2004 | + wait60thsec(60);//1秒待ち | |
2005 | + continue; | |
2006 | + } | |
2007 | + //currenfile[]にファイル名をコピー | |
2008 | + ps=tempfile; | |
2009 | + pd=currentfile; | |
2010 | + while(*ps) *pd++=*ps++; | |
2011 | + *pd=0; | |
2012 | + FSgetcwd(cwdpath,PATHNAMEMAX);//cwdpathをカレントディレクトリのパスに変更 | |
2013 | + return 0; | |
2014 | + } | |
2015 | + else if(f<num_dir){ | |
2016 | + //新規ディレクトリまたはディレクトリ変更して、再度ファイル一覧画面へ | |
2017 | + FSchdir(tempfile); | |
2018 | + } | |
2019 | + else{ | |
2020 | + er=loadtextfile(filenames[f]); //テキストバッファにファイル読み込み | |
2021 | + if(er==0){ | |
2022 | + //cwdpath[]、currenfile[]にパス、ファイル名をコピーして終了 | |
2023 | + FSgetcwd(cwdpath,PATHNAMEMAX); | |
2024 | + ps=filenames[f]; | |
2025 | + pd=currentfile; | |
2026 | + while(*ps!=0) *pd++=*ps++; | |
2027 | + *pd=0; | |
2028 | + return 0; | |
2029 | + } | |
2030 | + setcursor(0,twidthy-1,COLOR_ERRORTEXT); | |
2031 | + if(er==ERR_CANTFILEOPEN) printstr("Cannot Open File "); | |
2032 | + else if(er=ERR_FILETOOBIG) printstr("File Too Big "); | |
2033 | + wait60thsec(60);//1秒待ち | |
2034 | + } | |
2035 | + } | |
2036 | +} | |
2037 | +void changewidth(void){ | |
2038 | +// 画面幅の切り替え | |
2039 | + if(videomode==VMODE_STDTEXT) set_videomode(VMODE_WIDETEXT,0); | |
2040 | + else if(videomode==VMODE_WIDETEXT) set_videomode(VMODE_MONOTEXT,0); | |
2041 | + else set_videomode(VMODE_STDTEXT,0); | |
2042 | + cursor_top(); //カーソルをテキストバッファの先頭に設定 | |
2043 | + redraw(); //再描画 | |
2044 | +} | |
2045 | +void run(int test){ | |
2046 | +//KM-BASICコンパイル&実行 | |
2047 | +// test 0:コンパイルと実行、0以外:コンパイルのみで終了 | |
2048 | + int er,er2; | |
2049 | + FSFILE *fp; | |
2050 | + unsigned int disptoppos,cursorpos; | |
2051 | + unsigned char widthmode; | |
2052 | + int i,edited1; | |
2053 | + _tbuf *bp; | |
2054 | + unsigned short ix; | |
2055 | + unsigned char *p; | |
2056 | + | |
2057 | + cls(); | |
2058 | + setcursor(0,0,COLOR_NORMALTEXT); | |
2059 | + while(1){ | |
2060 | + //カレントディレクトリをルートに変更 | |
2061 | + if(FSchdir((char *)ROOTDIR)){ | |
2062 | + setcursorcolor(COLOR_ERRORTEXT); | |
2063 | + printstr("Cannot Change To Root Dir\n"); | |
2064 | + if(filesystemretry()) return; //ファイルシステム再初期化、あきらめた場合はreturnする | |
2065 | + continue; | |
2066 | + } | |
2067 | + //ルートディレクトリのパス名保存ファイルに実行時パスを保存 | |
2068 | + fp=FSfopen(WORKDIRFILE,"w"); | |
2069 | + if(fp==NULL){ | |
2070 | + setcursorcolor(COLOR_ERRORTEXT); | |
2071 | + printstr("Cannot Open Work Dir File\n"); | |
2072 | + if(filesystemretry()){ | |
2073 | + //ファイルシステム再初期化、あきらめた場合はカレントディレクトリを戻しreturnする | |
2074 | + FSchdir(cwdpath); | |
2075 | + return; | |
2076 | + } | |
2077 | + continue; | |
2078 | + } | |
2079 | + for(p=cwdpath;*p;p++) ; | |
2080 | + er=FSfwrite(cwdpath,1,p-cwdpath+1,fp); | |
2081 | + FSfclose(fp); | |
2082 | + if(er!=p-cwdpath+1){ | |
2083 | + FSremove(WORKDIRFILE); | |
2084 | + setcursorcolor(COLOR_ERRORTEXT); | |
2085 | + printstr("Cannot Write Work Dir File\n"); | |
2086 | + if(filesystemretry()){ | |
2087 | + //ファイルシステム再初期化、あきらめた場合はカレントディレクトリを戻しreturnする | |
2088 | + FSchdir(cwdpath); | |
2089 | + return; | |
2090 | + } | |
2091 | + continue; | |
2092 | + } | |
2093 | + break; | |
2094 | + } | |
2095 | + while(1){ | |
2096 | + //カレントディレクトリを元に戻す | |
2097 | + if(FSchdir(cwdpath)){ | |
2098 | + setcursorcolor(COLOR_ERRORTEXT); | |
2099 | + printstr("Cannot Change To CWD\n"); | |
2100 | + if(filesystemretry()) return; //ファイルシステム再初期化、あきらめた場合はreturnする | |
2101 | + continue; | |
2102 | + } | |
2103 | + //実行用引渡しファイルに保存 | |
2104 | + if(savetextfile(TEMPFILENAME)){ | |
2105 | + setcursorcolor(COLOR_ERRORTEXT); | |
2106 | + printstr("Cannot Write To SD Card\n"); | |
2107 | + if(filesystemretry()) return; //ファイルシステム再初期化、あきらめた場合はreturnする | |
2108 | + continue; | |
2109 | + } | |
2110 | + break; | |
2111 | + } | |
2112 | + | |
2113 | + //カーソル位置、画面表示位置、画面モードの保存 | |
2114 | + disptoppos=bpixtopos(disptopbp,disptopix); | |
2115 | + cursorpos=bpixtopos(cursorbp,cursorix); | |
2116 | + widthmode=videomode; | |
2117 | + edited1=edited; //編集済みフラグの一時退避 | |
2118 | + set_videomode(VMODE_T30,0);//30文字モードに設定 | |
2119 | + | |
2120 | + // Enable Break key | |
2121 | + g_disable_break=0; | |
2122 | + //KM-BASIC実行 | |
2123 | + er2=runbasic(TEMPFILENAME,test); | |
2124 | + | |
2125 | + stopPCG();//システムフォントに戻す | |
2126 | + setcursorcolor(COLOR_NORMALTEXT); | |
2127 | + printchar('\n'); | |
2128 | + printstr((unsigned char *)Message1);// Hit Any Key | |
2129 | + do ps2readkey(); //キーバッファが空になるまで読み出し | |
2130 | + while(vkey!=0); | |
2131 | + inputchar(); //1文字入力待ち | |
2132 | + stop_music(); //音楽再生停止 | |
2133 | + init_composite(); //パレット初期化のため画面初期化 | |
2134 | + | |
2135 | + //画面モードを戻す | |
2136 | + set_videomode(widthmode,0); | |
2137 | + | |
2138 | + FSgetcwd(cwdpath,PATHNAMEMAX);//カレントディレクトリパス変数を戻す | |
2139 | + while(1){ | |
2140 | + //カレントディレクトリをルートに変更 | |
2141 | + if(FSchdir((char *)ROOTDIR)){ | |
2142 | + setcursorcolor(COLOR_ERRORTEXT); | |
2143 | + printstr("Cannot Change To Root Dir\n"); | |
2144 | + filesystemretry(); //ファイルシステム再初期化 | |
2145 | + continue; | |
2146 | + } | |
2147 | + //ルートディレクトリのパス名保存ファイルからパス名を読み出し | |
2148 | + fp=FSfopen(WORKDIRFILE,"r"); | |
2149 | + if(fp==NULL){ | |
2150 | + setcursorcolor(COLOR_ERRORTEXT); | |
2151 | + printstr("Cannot Open Work Dir File\n"); | |
2152 | + filesystemretry(); //ファイルシステム再初期化 | |
2153 | + continue; | |
2154 | + } | |
2155 | + er=FSfread(cwdpath,1,PATHNAMEMAX,fp); | |
2156 | + FSfclose(fp); | |
2157 | + if(er<=0){ | |
2158 | + setcursorcolor(COLOR_ERRORTEXT); | |
2159 | + printstr("Cannot Read Work Dir File\n"); | |
2160 | + filesystemretry(); //ファイルシステム再初期化 | |
2161 | + continue; | |
2162 | + } | |
2163 | + FSremove(WORKDIRFILE); //パス名保存ファイル削除 | |
2164 | + break; | |
2165 | + } | |
2166 | + while(1){ | |
2167 | + //カレントディレクトリを元に戻す | |
2168 | + if(FSchdir(cwdpath)){ | |
2169 | + setcursorcolor(COLOR_ERRORTEXT); | |
2170 | + printstr("Cannot Change To CWD\n"); | |
2171 | + filesystemretry(); //ファイルシステム再初期化 | |
2172 | + continue; | |
2173 | + } | |
2174 | + //実行用引渡しファイルから元に戻す | |
2175 | + if(loadtextfile(TEMPFILENAME)){ | |
2176 | + setcursorcolor(COLOR_ERRORTEXT); | |
2177 | + printstr("Cannot Load From SD Card\n"); | |
2178 | + filesystemretry(); //ファイルシステム再初期化 | |
2179 | + continue; | |
2180 | + } | |
2181 | + break; | |
2182 | + } | |
2183 | + if(er2<=0){ | |
2184 | + //正常終了またはファイルエラーまたはリンクエラーの場合 | |
2185 | + //カーソルを元の位置に設定 | |
2186 | + disptopbp=postobpix(disptoppos,&disptopix); | |
2187 | + cursorbp=postobpix(cursorpos,&cursorix); | |
2188 | + } | |
2189 | + else{ | |
2190 | + //コンパイルエラーの場合 | |
2191 | + //カーソルをエラー行で画面トップに移動 | |
2192 | + disptopbp=linetobpix(er2,&disptopix); | |
2193 | + cursorbp=disptopbp; | |
2194 | + cursorix=disptopix; | |
2195 | + cx=0; | |
2196 | + cx2=0; | |
2197 | + cy=0; | |
2198 | + line_no=er2; | |
2199 | + //中央になるようスクロール | |
2200 | + for(i=0;i<EDITWIDTHY/2;i++){ | |
2201 | + //画面行数半分カーソルを上に移動 | |
2202 | + bp=disptopbp; | |
2203 | + ix=disptopix; | |
2204 | + cursor_up(); | |
2205 | + if(bp==disptopbp && ix==disptopix) break; //最上行で移動できなかった場合抜ける | |
2206 | + } | |
2207 | + for(;i>0;i--) cursor_down(); //元のY座標までカーソルを下に移動 | |
2208 | + } | |
2209 | + cursorbp1=NULL; //範囲選択モード解除 | |
2210 | + clipsize=0; //クリップボードクリア | |
2211 | + edited=edited1; | |
2212 | + FSremove(TEMPFILENAME); | |
2213 | +} | |
2214 | +void displaybottomline(void){ | |
2215 | +//エディター画面最下行の表示 | |
2216 | + unsigned char *p; | |
2217 | + unsigned char c; | |
2218 | + int t; | |
2219 | + p=cursor; //カーソル位置の退避 | |
2220 | + c=cursorcolor; | |
2221 | + if(shiftkeys() & CHK_SHIFT){ | |
2222 | + if(videomode!=VMODE_MONOTEXT){ | |
2223 | + setcursor(0,twidthy-1,COLOR_BOTTOMLINE); | |
2224 | + printstr("NEW |MSRA |WIDTH|TEST | "); | |
2225 | + } | |
2226 | + else{ | |
2227 | + setcursor(0,twidthy-1,COLOR_INV); | |
2228 | + printstr(" NEW \x87 MSRA \x87 WIDTH\x87 TEST \x87\x87"); | |
2229 | + } | |
2230 | + setcursorcolor(COLOR_ERRORTEXT); | |
2231 | + t=TBUFMAXSIZE-num; | |
2232 | + if(t==0) t=1; | |
2233 | + while(t<10000){ | |
2234 | + printchar(' '); | |
2235 | + t*=10; | |
2236 | + } | |
2237 | + printstr("LEFT:"); | |
2238 | + printnum(TBUFMAXSIZE-num); | |
2239 | + } | |
2240 | + else{ | |
2241 | + if(videomode!=VMODE_MONOTEXT){ | |
2242 | + setcursor(0,twidthy-1,COLOR_BOTTOMLINE); | |
2243 | + printstr("LOAD |SAVE | |RUN | "); | |
2244 | + } | |
2245 | + else{ | |
2246 | + setcursor(0,twidthy-1,COLOR_INV); | |
2247 | + printstr(" LOAD \x87 SAVE \x87 \x87 RUN \x87\x87"); | |
2248 | + } | |
2249 | + setcursorcolor(COLOR_ERRORTEXT); | |
2250 | + t=line_no; | |
2251 | + if(t==0) t=1; | |
2252 | + while(t<10000){ | |
2253 | + printchar(' '); | |
2254 | + t*=10; | |
2255 | + } | |
2256 | + printstr("LINE:"); | |
2257 | + printnum(line_no); | |
2258 | + } | |
2259 | + cursor=p; //カーソル位置戻し | |
2260 | + cursorcolor=c; | |
2261 | +} | |
2262 | +void normal_code_process(unsigned char k){ | |
2263 | +// 通常文字入力処理 | |
2264 | +// k:入力された文字コード | |
2265 | + int i; | |
2266 | + | |
2267 | + edited=1; //編集済みフラグ | |
2268 | + if(insertmode || k=='\n' || cursorbp1!=NULL){ //挿入モード | |
2269 | + if(cursorbp1!=NULL) deletearea();//選択範囲を削除 | |
2270 | + i=insertchar(cursorbp,cursorix,k,0);//テキストバッファに1文字挿入 | |
2271 | + if(i>0){ | |
2272 | + //バッファ空きがあるのに挿入失敗の場合 | |
2273 | + gabagecollect2(); //全体ガベージコレクション | |
2274 | + i=insertchar(cursorbp,cursorix,k,0);//テキストバッファに1文字挿入 | |
2275 | + } | |
2276 | + if(i==0) cursor_right();//画面上、バッファ上のカーソル位置を1つ後ろに移動 | |
2277 | + } | |
2278 | + else{ //上書きモード | |
2279 | + i=overwritechar(cursorbp,cursorix,k,0);//テキストバッファに1文字上書き | |
2280 | + if(i>0){ | |
2281 | + //バッファ空きがあるのに上書き(挿入)失敗の場合 | |
2282 | + //(行末やバッファ最後尾では挿入) | |
2283 | + gabagecollect2(); //全体ガベージコレクション | |
2284 | + i=overwritechar(cursorbp,cursorix,k,0);//テキストバッファに1文字上書き | |
2285 | + } | |
2286 | + if(i==0) cursor_right();//画面上、バッファ上のカーソル位置を1つ後ろに移動 | |
2287 | + } | |
2288 | +} | |
2289 | +void control_code_process(unsigned char k,unsigned char sh){ | |
2290 | +// 制御文字入力処理 | |
2291 | +// k:制御文字の仮想キーコード | |
2292 | +// sh:シフト関連キー状態 | |
2293 | + | |
2294 | + save_cursor(); //カーソル関連変数退避(カーソル移動できなかった場合戻すため) | |
2295 | + switch(k){ | |
2296 | + case VK_LEFT: | |
2297 | + case VK_NUMPAD4: | |
2298 | + //シフトキー押下していなければ範囲選択モード解除(NumLock+シフト+テンキーでも解除) | |
2299 | + if((sh & CHK_SHIFT)==0 || (k==VK_NUMPAD4) && (sh & CHK_NUMLK)) cursorbp1=NULL; | |
2300 | + else if(cursorbp1==NULL) set_areamode(); //範囲選択モードでなければ範囲選択モード開始 | |
2301 | + if(sh & CHK_CTRL){ | |
2302 | + //CTRL+左矢印でHome | |
2303 | + cursor_home(); | |
2304 | + break; | |
2305 | + } | |
2306 | + cursor_left(); | |
2307 | + if(cursorbp1!=NULL && (disptopbp!=disptopbp_t || disptopix!=disptopix_t)){ | |
2308 | + //範囲選択モードで画面スクロールがあった場合 | |
2309 | + if(cy1<EDITWIDTHY-1) cy1++; //範囲スタート位置もスクロール | |
2310 | + else restore_cursor(); //カーソル位置を戻す(画面範囲外の範囲選択禁止) | |
2311 | + } | |
2312 | + break; | |
2313 | + case VK_RIGHT: | |
2314 | + case VK_NUMPAD6: | |
2315 | + //シフトキー押下していなければ範囲選択モード解除(NumLock+シフト+テンキーでも解除) | |
2316 | + if((sh & CHK_SHIFT)==0 || (k==VK_NUMPAD6) && (sh & CHK_NUMLK)) cursorbp1=NULL; | |
2317 | + else if(cursorbp1==NULL) set_areamode(); //範囲選択モードでなければ範囲選択モード開始 | |
2318 | + if(sh & CHK_CTRL){ | |
2319 | + //CTRL+右矢印でEnd | |
2320 | + cursor_end(); | |
2321 | + break; | |
2322 | + } | |
2323 | + cursor_right(); | |
2324 | + if(cursorbp1!=NULL && (disptopbp!=disptopbp_t || disptopix!=disptopix_t)){ | |
2325 | + //範囲選択モードで画面スクロールがあった場合 | |
2326 | + if(cy1>0) cy1--; //範囲スタート位置もスクロール | |
2327 | + else restore_cursor(); //カーソル位置を戻す(画面範囲外の範囲選択禁止) | |
2328 | + } | |
2329 | + break; | |
2330 | + case VK_UP: | |
2331 | + case VK_NUMPAD8: | |
2332 | + //シフトキー押下していなければ範囲選択モード解除(NumLock+シフト+テンキーでも解除) | |
2333 | + if((sh & CHK_SHIFT)==0 || (k==VK_NUMPAD8) && (sh & CHK_NUMLK)) cursorbp1=NULL; | |
2334 | + else if(cursorbp1==NULL) set_areamode(); //範囲選択モードでなければ範囲選択モード開始 | |
2335 | + cursor_up(); | |
2336 | + if(cursorbp1!=NULL && (disptopbp!=disptopbp_t || disptopix!=disptopix_t)){ | |
2337 | + //範囲選択モードで画面スクロールがあった場合 | |
2338 | + if(cy1<EDITWIDTHY-1) cy1++; //範囲スタート位置もスクロール | |
2339 | + else restore_cursor(); //カーソル位置を戻す(画面範囲外の範囲選択禁止) | |
2340 | + } | |
2341 | + break; | |
2342 | + case VK_DOWN: | |
2343 | + case VK_NUMPAD2: | |
2344 | + //シフトキー押下していなければ範囲選択モード解除(NumLock+シフト+テンキーでも解除) | |
2345 | + if((sh & CHK_SHIFT)==0 || (k==VK_NUMPAD2) && (sh & CHK_NUMLK)) cursorbp1=NULL; | |
2346 | + else if(cursorbp1==NULL) set_areamode(); //範囲選択モードでなければ範囲選択モード開始 | |
2347 | + cursor_down(); | |
2348 | + if(cursorbp1!=NULL && (disptopbp!=disptopbp_t || disptopix!=disptopix_t)){ | |
2349 | + //範囲選択モードで画面スクロールがあった場合 | |
2350 | + if(cy1>0) cy1--; //範囲スタート位置もスクロール | |
2351 | + else restore_cursor(); //カーソル位置を戻す(画面範囲外の範囲選択禁止) | |
2352 | + } | |
2353 | + break; | |
2354 | + case VK_HOME: | |
2355 | + case VK_NUMPAD7: | |
2356 | + //シフトキー押下していなければ範囲選択モード解除(NumLock+シフト+テンキーでも解除) | |
2357 | + if((sh & CHK_SHIFT)==0 || (k==VK_NUMPAD7) && (sh & CHK_NUMLK)) cursorbp1=NULL; | |
2358 | + else if(cursorbp1==NULL) set_areamode(); //範囲選択モードでなければ範囲選択モード開始 | |
2359 | + cursor_home(); | |
2360 | + break; | |
2361 | + case VK_END: | |
2362 | + case VK_NUMPAD1: | |
2363 | + //シフトキー押下していなければ範囲選択モード解除(NumLock+シフト+テンキーでも解除) | |
2364 | + if((sh & CHK_SHIFT)==0 || (k==VK_NUMPAD1) && (sh & CHK_NUMLK)) cursorbp1=NULL; | |
2365 | + else if(cursorbp1==NULL) set_areamode(); //範囲選択モードでなければ範囲選択モード開始 | |
2366 | + cursor_end(); | |
2367 | + break; | |
2368 | + case VK_PRIOR: // PageUpキー | |
2369 | + case VK_NUMPAD9: | |
2370 | + //シフト+PageUpは無効(NumLock+シフト+「9」除く) | |
2371 | + if((sh & CHK_SHIFT) && ((k!=VK_NUMPAD9) || ((sh & CHK_NUMLK)==0))) break; | |
2372 | + cursorbp1=NULL; //範囲選択モード解除 | |
2373 | + cursor_pageup(); | |
2374 | + break; | |
2375 | + case VK_NEXT: // PageDownキー | |
2376 | + case VK_NUMPAD3: | |
2377 | + //シフト+PageDownは無効(NumLock+シフト+「3」除く) | |
2378 | + if((sh & CHK_SHIFT) && ((k!=VK_NUMPAD3) || ((sh & CHK_NUMLK)==0))) break; | |
2379 | + cursorbp1=NULL; //範囲選択モード解除 | |
2380 | + cursor_pagedown(); | |
2381 | + break; | |
2382 | + case VK_DELETE: //Deleteキー | |
2383 | + case VK_DECIMAL: //テンキーの「.」 | |
2384 | + edited=1; //編集済みフラグ | |
2385 | + if(cursorbp1!=NULL) deletearea();//選択範囲を削除 | |
2386 | + else deletechar(cursorbp,cursorix,0); | |
2387 | + break; | |
2388 | + case VK_BACK: //BackSpaceキー | |
2389 | + edited=1; //編集済みフラグ | |
2390 | + if(cursorbp1!=NULL){ | |
2391 | + deletearea();//選択範囲を削除 | |
2392 | + break; | |
2393 | + } | |
2394 | + if(cursorix==0 && cursorbp->prev==NULL) break; //バッファ先頭では無視 | |
2395 | + cursor_left(); | |
2396 | + deletechar(cursorbp,cursorix,-1); | |
2397 | + break; | |
2398 | + case VK_INSERT: | |
2399 | + case VK_NUMPAD0: | |
2400 | + insertmode^=1; //挿入モード、上書きモードを切り替え | |
2401 | + break; | |
2402 | + case 'C': | |
2403 | + //CTRL+C、クリップボードにコピー | |
2404 | + if(cursorbp1!=NULL && (sh & CHK_CTRL)) clipcopy(); | |
2405 | + break; | |
2406 | + case 'X': | |
2407 | + //CTRL+X、クリップボードに切り取り | |
2408 | + if(cursorbp1!=NULL && (sh & CHK_CTRL)){ | |
2409 | + clipcopy(); | |
2410 | + deletearea(); //選択範囲の削除 | |
2411 | + edited=1; //編集済みフラグ | |
2412 | + } | |
2413 | + break; | |
2414 | + case 'V': | |
2415 | + //CTRL+V、クリップボードから貼り付け | |
2416 | + if((sh & CHK_CTRL)==0) break; | |
2417 | + if(clipsize==0) break; | |
2418 | + edited=1; //編集済みフラグ | |
2419 | + if(cursorbp1!=NULL){ | |
2420 | + //範囲選択している時は削除してから貼り付け | |
2421 | + if(num-countarea()+clipsize<=TBUFMAXSIZE){ //バッファ空き容量チェック | |
2422 | + deletearea();//選択範囲を削除 | |
2423 | + clippaste();//クリップボード貼り付け | |
2424 | + } | |
2425 | + } | |
2426 | + else{ | |
2427 | + if(num+clipsize<=TBUFMAXSIZE){ //バッファ空き容量チェック | |
2428 | + clippaste();//クリップボード貼り付け | |
2429 | + } | |
2430 | + } | |
2431 | + break; | |
2432 | + case 'S': | |
2433 | + //CTRL+S、SDカードに保存 | |
2434 | + if(num==0) break; | |
2435 | + if(sh & CHK_CTRL) save_as(1); //上書き保存 | |
2436 | + break; | |
2437 | + case 'O': | |
2438 | + //CTRL+O、ファイル読み込み | |
2439 | + if(sh & CHK_CTRL){ | |
2440 | + if(fileload()==0){ //ファイルを選択して読み込み | |
2441 | + //読み込みを行った場合、カーソル位置を先頭に | |
2442 | + cursor_top(); | |
2443 | + } | |
2444 | + } | |
2445 | + break; | |
2446 | + case 'N': | |
2447 | + //CTRL+N、新規作成 | |
2448 | + if(sh & CHK_CTRL) newtext(); | |
2449 | + break; | |
2450 | + case VK_F1: //F1キー | |
2451 | + if(sh & CHK_SHIFT) newtext();//SHIFT+F1キー 新規作成 | |
2452 | + else{ | |
2453 | + //ファイル読み込み | |
2454 | + if(fileload()==0){ //ファイルを選択して読み込み | |
2455 | + //読み込みを行った場合、カーソル位置を先頭に | |
2456 | + cursor_top(); | |
2457 | + } | |
2458 | + } | |
2459 | + break; | |
2460 | + case VK_F2: //F2キー | |
2461 | + if(num==0) break; | |
2462 | + if(sh & CHK_SHIFT) msra(); //create direct running file | |
2463 | + else save_as(0); //ファイル名を付けて保存 | |
2464 | + break; | |
2465 | + case VK_F3: //F3キー | |
2466 | + if(sh & CHK_SHIFT) changewidth(); //画面幅の切り替え | |
2467 | + break; | |
2468 | + case VK_F4: //F4キー | |
2469 | + if(num==0) break; | |
2470 | + if(sh & CHK_SHIFT) run(1); //コンパイルテスト | |
2471 | + else run(0); //コンパイル&実行 | |
2472 | + break; | |
2473 | + case 'Z': | |
2474 | + //CTRL+Z、アンドゥ | |
2475 | + if(sh & CHK_CTRL) undoexec(); | |
2476 | + break; | |
2477 | + } | |
2478 | +} | |
2479 | +void texteditor(void){ | |
2480 | +//テキストエディター本体 | |
2481 | + unsigned char k1,k2,sh; | |
2482 | + FSFILE *fp; | |
2483 | + | |
2484 | + editormallocp=RAM; | |
2485 | + TextBuffer=(_tbuf *)editormalloc(sizeof(_tbuf)*TBUFMAXLINE); | |
2486 | + clipboard=editormalloc(WIDTH_XMAX*EDITWIDTHY); | |
2487 | + filebuf=editormalloc(FILEBUFSIZE); | |
2488 | + cwdpath=editormalloc(PATHNAMEMAX); | |
2489 | + filenames=(unsigned char (*)[])editormalloc(MAXFILENUM*13); | |
2490 | + undobuf=editormalloc(UNDOBUFSIZE); | |
2491 | + | |
2492 | +// TextBuffer=(_tbuf *)RAM; | |
2493 | +// clipboard=(unsigned char *)TextBuffer+sizeof(_tbuf)*TBUFMAXLINE; | |
2494 | +// filebuf=clipboard+WIDTH_XMAX*EDITWIDTHY; | |
2495 | +// cwdpath=filebuf+FILEBUFSIZE; | |
2496 | +// filenames=(unsigned char (*)[])(cwdpath+PATHNAMEMAX); | |
2497 | +// undobuf=(unsigned char *)filenames+MAXFILENUM*13; | |
2498 | + | |
2499 | + inittextbuf(); //テキストバッファ初期化 | |
2500 | + currentfile[0]=0; //作業中ファイル名クリア | |
2501 | + cwdpath[0]='\\'; //カレントディレクトリをルートに設定 | |
2502 | + cwdpath[1]=0; | |
2503 | + | |
2504 | + //実行時生成一時ファイルがあった場合は読み込む | |
2505 | + fp=FSfopen(WORKDIRFILE,"r"); | |
2506 | + if(fp!=NULL){ | |
2507 | + FSfread(cwdpath,1,PATHNAMEMAX,fp); | |
2508 | + FSfclose(fp); | |
2509 | + FSchdir(cwdpath); | |
2510 | + if(loadtextfile(TEMPFILENAME)==0){ | |
2511 | + edited=1; | |
2512 | + setcursorcolor(COLOR_ERRORTEXT); | |
2513 | + printstr("Temporary File Loaded\n"); | |
2514 | + printstr("Current Directory is\n"); | |
2515 | + setcursorcolor(COLOR_DIR); | |
2516 | + printstr(cwdpath); | |
2517 | + setcursorcolor(COLOR_ERRORTEXT); | |
2518 | + printstr("\nSave To SD Card If Necessary\n"); | |
2519 | + setcursorcolor(COLOR_NORMALTEXT); | |
2520 | + printstr((unsigned char *)Message1); //Hit Any Key | |
2521 | + inputchar(); //1文字入力待ち | |
2522 | + } | |
2523 | + else{ | |
2524 | + cwdpath[0]='\\'; //カレントディレクトリをルートに設定 | |
2525 | + cwdpath[1]=0; | |
2526 | + } | |
2527 | + } | |
2528 | + cursor_top(); //カーソルをテキストバッファの先頭に移動 | |
2529 | + insertmode=1; //0:上書き、1:挿入 | |
2530 | + clipsize=0; //クリップボードクリア | |
2531 | + blinktimer=0; //カーソル点滅タイマークリア | |
2532 | + | |
2533 | + while(1){ | |
2534 | + redraw();//画面再描画 | |
2535 | + setcursor(cx,cy,COLOR_NORMALTEXT); | |
2536 | + getcursorchar(); //カーソル位置の文字を退避(カーソル点滅用) | |
2537 | + while(1){ | |
2538 | + //キー入力待ちループ | |
2539 | + wait60thsec(1); //60分の1秒ウェイト | |
2540 | + blinkcursorchar(); //カーソル点滅させる | |
2541 | + k1=ps2readkey(); //キーバッファから読み込み、k1:通常文字入力の場合ASCIIコード | |
2542 | + displaybottomline(); //画面最下行にファンクションキー機能表示 | |
2543 | + if(vkey) break; //キーが押された場合ループから抜ける | |
2544 | + if(cursorbp1==NULL) gabagecollect1(); //1バイトガベージコレクション(範囲選択時はしない) | |
2545 | + } | |
2546 | + resetcursorchar(); //カーソルを元の文字表示に戻す | |
2547 | + k2=(unsigned char)vkey; //k2:仮想キーコード | |
2548 | + sh=vkey>>8; //sh:シフト関連キー状態 | |
2549 | + if(k2==VK_RETURN || k2==VK_SEPARATOR) k1='\n'; //Enter押下は単純に改行文字を入力とする | |
2550 | + if(k1) normal_code_process(k1); //通常文字が入力された場合 | |
2551 | + else control_code_process(k2,sh); //制御文字が入力された場合 | |
2552 | + if(cursorbp1!=NULL && cx==cx1 && cy==cy1) cursorbp1=NULL;//選択範囲の開始と終了が重なったら範囲選択モード解除 | |
2553 | + } | |
2554 | +} |
@@ -0,0 +1,90 @@ | ||
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 | +// Megalopa uses I/O statements/functions | |
9 | +#include "io.h" | |
10 | + | |
11 | +#define PERSISTENT_RAM_SIZE (1024*100) | |
12 | + | |
13 | +int readbuttons(); | |
14 | +void scroll(int x, int y); | |
15 | +void usegraphic(int mode); | |
16 | +void videowidth(int width); | |
17 | +int lib_system(int a0, int a1 ,int v0, int a3, int g_gcolor, int g_prev_x, int g_prev_y); | |
18 | +void init_env(void); | |
19 | +void pre_run(void); | |
20 | +void post_run(void); | |
21 | + | |
22 | +// 30 or 40 characters per line for Zoea | |
23 | +#define printcomma() printstr(" "+rem10_32((unsigned int)(cursor-TVRAM))) | |
24 | + | |
25 | +// Check break key or buttons when executing BASIC code. | |
26 | +// In PS/2 mode, detect ctrl-break. | |
27 | +// In button mode, detect pushing four buttons are pushed simultaneously. | |
28 | +#define check_break() \ | |
29 | + if (g_disable_break==0) {\ | |
30 | + if (ps2keystatus[0x03]) err_break();\ | |
31 | + } | |
32 | + | |
33 | +// Megalopa specific lists of statements and functions | |
34 | +#define ADDITIONAL_STATEMENTS \ | |
35 | + "OUT " ,out_statement,\ | |
36 | + "OUT8H " ,out8h_statement,\ | |
37 | + "OUT8L " ,out8l_statement,\ | |
38 | + "OUT16 " ,out16_statement,\ | |
39 | + "PWM " ,pwm_statement,\ | |
40 | + "SERIAL " ,serial_statement,\ | |
41 | + "SERIALOUT ",serialout_statement, | |
42 | + | |
43 | +#define ADDITIONAL_INT_FUNCTIONS \ | |
44 | + "IN(" , in_function,\ | |
45 | + "IN8H(" , in8h_function,\ | |
46 | + "IN8L(" , in8l_function,\ | |
47 | + "IN16(" , in16_function,\ | |
48 | + "ANALOG(" ,analog_function,\ | |
49 | + "SERIALIN(",serialin_function, | |
50 | + | |
51 | +#define ADDITIONAL_STR_FUNCTIONS | |
52 | +#define ADDITIONAL_RESERVED_VAR_NAMES \ | |
53 | + 0x00015045, /*OUT*/ \ | |
54 | + 0x01975e81, /*OUT8H*/ \ | |
55 | + 0x01975e85, /*OUT8L*/ \ | |
56 | + 0x01975d7a, /*OUT16*/ \ | |
57 | + 0x0001015b, /*IN*/ \ | |
58 | + 0x0007dde1, /*IN8H*/ \ | |
59 | + 0x0007dde5, /*IN8L*/ \ | |
60 | + 0x0007dcda, /*IN16*/ \ | |
61 | + 0x05f0a740, /*ANALOG*/ \ | |
62 | + 0x00015596, /*PWM*/ \ | |
63 | + 0x45f58f5d, /*SERIAL*/ \ | |
64 | + 0x000163c6, /*SPI*/ \ | |
65 | + 0x47093355, /*SPIOUT*/ \ | |
66 | + 0x01fa1cff, /*SPIIN*/ | |
67 | + | |
68 | + | |
69 | +#define EXTRA_MASK 0x003F | |
70 | +#define EXTRA_STEP 0x0001 | |
71 | +enum extra{ | |
72 | + EXTRA_SYSTEM =EXTRA_STEP*0, | |
73 | + EXTRA_OUT =EXTRA_STEP*1, | |
74 | + EXTRA_OUT8H =EXTRA_STEP*2, | |
75 | + EXTRA_OUT8L =EXTRA_STEP*3, | |
76 | + EXTRA_OUT16 =EXTRA_STEP*4, | |
77 | + EXTRA_IN =EXTRA_STEP*5, | |
78 | + EXTRA_IN8H =EXTRA_STEP*6, | |
79 | + EXTRA_IN8L =EXTRA_STEP*7, | |
80 | + EXTRA_IN16 =EXTRA_STEP*8, | |
81 | + EXTRA_ANALOG =EXTRA_STEP*9, | |
82 | + EXTRA_PWM =EXTRA_STEP*10, | |
83 | + EXTRA_SERIALOUT =EXTRA_STEP*11, | |
84 | + EXTRA_SERIALIN =EXTRA_STEP*12, | |
85 | + EXTRA_SERIAL =EXTRA_STEP*13, | |
86 | + EXTRA_SPIOUT =EXTRA_STEP*14, | |
87 | + EXTRA_SPIIN =EXTRA_STEP*15, | |
88 | + EXTRA_SPI =EXTRA_STEP*16, | |
89 | + // MAX 63 | |
90 | +}; |
@@ -0,0 +1,152 @@ | ||
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 | + // Clear object area | |
56 | + for(i=0;i<RAMSIZE/4;i++) g_object[i]=0x00000000; | |
57 | + // Initialize SD card file system | |
58 | + err=init_file(buff,appname); | |
59 | + if (err) { | |
60 | + setcursorcolor(COLOR_ERRORTEXT); | |
61 | + printstr("Can't Open "); | |
62 | + printstr(appname); | |
63 | + printchar('\n'); | |
64 | + return -1; | |
65 | + } | |
66 | + | |
67 | + // Initialize parameters | |
68 | + g_pcg_font=0; | |
69 | + g_use_graphic=0; | |
70 | + g_graphic_area=0; | |
71 | + clearscreen(); | |
72 | + setcursor(0,0,7); | |
73 | + g_long_name_var_num=0; | |
74 | + cmpdata_init(); | |
75 | + | |
76 | + // Initialize music system | |
77 | + init_music(); | |
78 | + | |
79 | + printstr("BASIC "BASVER"\n"); | |
80 | + wait60thsec(15); | |
81 | + | |
82 | + printstr("Compiling..."); | |
83 | + | |
84 | + // Compile the file | |
85 | + err=compile_file(); | |
86 | + close_file(); | |
87 | + if (err) { | |
88 | + // Compile error | |
89 | + printstr(err); | |
90 | + printstr("\nAround: '"); | |
91 | + for(i=0;i<5;i++){ | |
92 | + printchar(g_source[g_srcpos-2+i]); | |
93 | + } | |
94 | + printstr("' in line "); | |
95 | + printdec(g_line); | |
96 | + printstr("\n"); | |
97 | + for(i=g_srcpos;0x20<=g_source[i];i++); | |
98 | + g_source[i]=0x00; | |
99 | + for(i=g_srcpos;0x20<=g_source[i];i--); | |
100 | + printstr(g_source+i); | |
101 | + return g_fileline; | |
102 | + } | |
103 | + | |
104 | + // Link | |
105 | + err=link(); | |
106 | + if (err) { | |
107 | + // Link error | |
108 | + printstr(err); | |
109 | + printstr(resolve_label(g_label)); | |
110 | + return -2; | |
111 | + } | |
112 | + | |
113 | + // All done | |
114 | + printstr("done\n"); | |
115 | + if(test) return 0; //コンパイルのみの場合 | |
116 | + wait60thsec(15); | |
117 | + | |
118 | + // Initialize the other parameters | |
119 | + // Random seed | |
120 | + g_rnd_seed=0x92D68CA2; //2463534242 | |
121 | + // Clear variables | |
122 | + for(i=0;i<ALLOC_BLOCK_NUM;i++){ | |
123 | + g_var_mem[i]=0; | |
124 | + g_var_size[i]=0; | |
125 | + } | |
126 | + // Clear key input buffer | |
127 | + for(i=0;i<256;i++){ | |
128 | + ps2keystatus[i]=0; | |
129 | + } | |
130 | + // Reset data/read. | |
131 | + reset_dataread(); | |
132 | + // Initialize file system | |
133 | + lib_file(FUNC_FINIT,0,0,0); | |
134 | + | |
135 | + // Assign memory | |
136 | + set_free_area((void*)(g_object+g_objpos),(void*)(&RAM[RAMSIZE])); | |
137 | + | |
138 | + // Warm up environment | |
139 | + pre_run(); | |
140 | + | |
141 | + // Execute program | |
142 | + // Start program from the beginning of RAM. | |
143 | + // Work area (used for A-Z values) is next to the object code area. | |
144 | + start_program((void*)(&(RAM[0])),(void*)(&g_var_mem[0])); | |
145 | + printstr("\nOK\n"); | |
146 | + | |
147 | + // Cool down environment | |
148 | + post_run(); | |
149 | + lib_file(FUNC_FINIT,0,0,0); | |
150 | + | |
151 | + return 0; | |
152 | +} |
@@ -0,0 +1,245 @@ | ||
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 | +#include "compiler.h" | |
14 | + | |
15 | +/* | |
16 | + Enable following line when debugging binary object. | |
17 | +*/ | |
18 | +//#include "debugdump.h" | |
19 | + | |
20 | + | |
21 | +// Pseudo reading config setting for debug mode | |
22 | +unsigned int g_DEVCFG1=0xFF7F4DDB; | |
23 | + | |
24 | +// Construct jump assembly in boot area. | |
25 | +const unsigned int _debug_boot[] __attribute__((address(0xBFC00000))) ={ | |
26 | + 0x0B401C00,// j 0x9d007000 | |
27 | + 0x00000000,// nop | |
28 | +}; | |
29 | + | |
30 | +// Use DEBUG.HEX as file name of this program. | |
31 | +const unsigned char _debug_filename[] __attribute__((address(FILENAME_FLASH_ADDRESS))) ="DEBUG.HEX"; | |
32 | + | |
33 | +static const char initext[]; | |
34 | +static const char bastext[]; | |
35 | + | |
36 | +static char* readtext; | |
37 | +static int filepos; | |
38 | + | |
39 | +/* | |
40 | + Debug dump | |
41 | + In debugdump.h: | |
42 | + __DEBUGDUMP is defined. | |
43 | + __DEBUGDUMP_FREEAREA is defined as start address of free area (1st argument of set_free_area() function) | |
44 | + const unsigned char dump[] is initialized. | |
45 | +*/ | |
46 | +#ifdef __DEBUGDUMP | |
47 | +int debugDump(){ | |
48 | + int i; | |
49 | + for(i=0;i<sizeof dump;i++){ | |
50 | + RAM[i]=dump[i]; | |
51 | + } | |
52 | + | |
53 | + g_objpos=(__DEBUGDUMP_FREEAREA-(unsigned int)g_object)/4; | |
54 | + | |
55 | + // Initialize parameters | |
56 | + g_pcg_font=0; | |
57 | + g_use_graphic=0; | |
58 | + g_graphic_area=0; | |
59 | + clearscreen(); | |
60 | + setcursor(0,0,7); | |
61 | + | |
62 | + printstr("BASIC "BASVER"\n"); | |
63 | + wait60thsec(15); | |
64 | + | |
65 | + printstr("Compiling..."); | |
66 | + | |
67 | + // Initialize the other parameters | |
68 | + // Random seed | |
69 | + g_rnd_seed=0x92D68CA2; //2463534242 | |
70 | + // Clear variables | |
71 | + for(i=0;i<ALLOC_BLOCK_NUM;i++){ | |
72 | + g_var_mem[i]=0; | |
73 | + g_var_size[i]=0; | |
74 | + } | |
75 | + // Clear key input buffer | |
76 | + for(i=0;i<256;i++){ | |
77 | + ps2keystatus[i]=0; | |
78 | + } | |
79 | + // Reset data/read. | |
80 | + reset_dataread(); | |
81 | + | |
82 | + // Assign memory | |
83 | + set_free_area((void*)(g_object+g_objpos),(void*)(&RAM[RAMSIZE])); | |
84 | + // Execute program | |
85 | + // Start program from the beginning of RAM. | |
86 | + // Work area (used for A-Z values) is next to the object code area. | |
87 | + start_program((void*)(&(RAM[0])),(void*)(&g_var_mem[0])); | |
88 | + printstr("\nOK\n"); | |
89 | + g_use_graphic=0; | |
90 | + | |
91 | + return 1; | |
92 | +} | |
93 | +#else | |
94 | +int debugDump(){ | |
95 | + return 0; | |
96 | +} | |
97 | +#endif | |
98 | + | |
99 | +/* | |
100 | + Override libsdfsio functions. | |
101 | + Here, don't use SD card, but the vertual files | |
102 | + (initext[] and bastext[]) are used. | |
103 | +*/ | |
104 | + | |
105 | +FSFILE fsfile; | |
106 | + | |
107 | +size_t FSfread(void *ptr, size_t size, size_t n, FSFILE *stream){ | |
108 | + char b; | |
109 | + size_t ret=0; | |
110 | + if (!readtext) return 0; | |
111 | + while(b=readtext[filepos]){ | |
112 | + filepos++; | |
113 | + ((char*)ptr)[ret]=b; | |
114 | + ret++; | |
115 | + if (n<=ret) break; | |
116 | + } | |
117 | + return ret; | |
118 | +} | |
119 | +FSFILE* FSfopen(const char * fileName, const char *mode){ | |
120 | + int i; | |
121 | + for(i=0;i<13;i++){ | |
122 | + if (fileName[i]=='.') break; | |
123 | + } | |
124 | + if (i==13) { | |
125 | + // Unknown file name | |
126 | + // Force BAS file | |
127 | + readtext=(char*)&bastext[0]; | |
128 | + } else if (fileName[i+1]=='I' && fileName[i+2]=='N' && fileName[i+3]=='I') { | |
129 | + // INI file | |
130 | + readtext=(char*)&initext[0]; | |
131 | + } else if (fileName[i+1]=='B' && fileName[i+2]=='A' && fileName[i+3]=='S') { | |
132 | + // BAS file | |
133 | + readtext=(char*)&bastext[0]; | |
134 | + // Try debugDump. | |
135 | + if (debugDump()) return 0; | |
136 | + } else { | |
137 | + readtext=0; | |
138 | + return 0; | |
139 | + } | |
140 | + filepos=0; | |
141 | + return &fsfile; | |
142 | +} | |
143 | +int FSfeof( FSFILE * stream ){ | |
144 | + return readtext[filepos]?1:0; | |
145 | +} | |
146 | +int FSfclose(FSFILE *fo){ | |
147 | + return 0; | |
148 | +} | |
149 | +int FSInit(void){ | |
150 | + return 1; | |
151 | +} | |
152 | +int FSremove (const char * fileName){ | |
153 | + return 0; | |
154 | +} | |
155 | +size_t FSfwrite(const void *ptr, size_t size, size_t n, FSFILE *stream){ | |
156 | + return 0; | |
157 | +} | |
158 | + | |
159 | +int FindFirst (const char * fileName, unsigned int attr, SearchRec * rec){ | |
160 | + return 0; | |
161 | +} | |
162 | +int FindNext (SearchRec * rec){ | |
163 | + return 0; | |
164 | +} | |
165 | +int FSmkdir (char * path){ | |
166 | + return 0; | |
167 | +} | |
168 | +char * FSgetcwd (char * path, int numchars){ | |
169 | + return 0; | |
170 | +} | |
171 | +int FSchdir (char * path){ | |
172 | + return 0; | |
173 | +} | |
174 | +long FSftell (FSFILE * fo){ | |
175 | + return 0; | |
176 | +} | |
177 | +int FSfseek(FSFILE *stream, long offset, int whence){ | |
178 | + return 0; | |
179 | +} | |
180 | +/* | |
181 | + ps2init() is not called. | |
182 | + Instead, not_ps2init_but_init_Timer1() is called. | |
183 | + Timer1 is used to update drawcount and drawing gloval variables. | |
184 | +*/ | |
185 | + | |
186 | +int not_ps2init_but_init_Timer1(){ | |
187 | + PR1=0x0FFF; | |
188 | + TMR1=0; | |
189 | + IFS0bits.T1IF=0; | |
190 | + T1CON=0x8000; | |
191 | + // Timer1 interrupt: priority 4 | |
192 | + IPC1bits.T1IP=4; | |
193 | + IPC1bits.T1IS=0; | |
194 | + IEC0bits.T1IE=1; | |
195 | + | |
196 | + return 0; | |
197 | +} | |
198 | + | |
199 | +#pragma interrupt timer1Int IPL4SOFT vector 4 | |
200 | + | |
201 | +void timer1Int(){ | |
202 | + IFS0bits.T1IF=0; | |
203 | + if (drawing) { | |
204 | + drawing=0; | |
205 | + drawcount++; | |
206 | + } else { | |
207 | + drawing=1; | |
208 | + } | |
209 | +} | |
210 | + | |
211 | +/* | |
212 | + initext[] and bastext[] are vertual files | |
213 | + as "MACHIKAN.INI" and "DEBUG.BAS". | |
214 | +*/ | |
215 | + | |
216 | + | |
217 | +static const char initext[]= | |
218 | +"#PRINT\n" | |
219 | +"#PRINT\n"; | |
220 | + | |
221 | + | |
222 | +static const char bastext[]= | |
223 | +"CLS\n" | |
224 | +"print NOT(0);IN(0)\n" | |
225 | +"\n"; | |
226 | + | |
227 | +/* | |
228 | + Test function for constructing assemblies from C codes. | |
229 | +*/ | |
230 | + | |
231 | +int _debug_test(int a0, int a1, int a2, int a3, int param4, int param5){ | |
232 | +// if (a0<0xa0008192) return 0xa0000000; | |
233 | + asm volatile("lw $sp,18($fp)"); | |
234 | + asm volatile("addiu $sp,$sp,2044"); | |
235 | + return a2+a3; | |
236 | +} | |
237 | + | |
238 | +/* | |
239 | + Break point used for debugging object code. | |
240 | + | |
241 | +g_object[g_objpos++]=0x0000000d;// break 0x0 | |
242 | + | |
243 | +*/ | |
244 | + | |
245 | +#endif // __DEBUG |
@@ -0,0 +1,34 @@ | ||
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 | +void lib_out(int pos, int val); | |
9 | +void lib_out8h(int val); | |
10 | +void lib_out8l(int val); | |
11 | +int lib_out16(int val); | |
12 | +int lib_in(int pos); | |
13 | +int lib_in8h(); | |
14 | +int lib_in8l(); | |
15 | +int lib_in16(); | |
16 | +int lib_analog(int pos); | |
17 | +void lib_pwm(int duty, int freq, int num); | |
18 | +void lib_serial(int baud, int parity, int bsize); | |
19 | +void lib_serialout(int data); | |
20 | +int lib_serialin(int mode); | |
21 | + | |
22 | +char* out_statement(); | |
23 | +char* out8h_statement(); | |
24 | +char* out8l_statement(); | |
25 | +char* out16_statement(); | |
26 | +char* pwm_statement(); | |
27 | +char* serial_statement(); | |
28 | +char* serialout_statement(); | |
29 | +char* in_function(); | |
30 | +char* in8h_function(); | |
31 | +char* in8l_function(); | |
32 | +char* in16_function(); | |
33 | +char* analog_function(); | |
34 | +char* serialin_function(); |
@@ -0,0 +1,184 @@ | ||
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 | +} | |
176 | + | |
177 | +int get_permanent_var_num(){ | |
178 | + int i; | |
179 | + for (i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++) { | |
180 | + if (g_var_size[i]==0) return i; | |
181 | + } | |
182 | + err_no_block(); | |
183 | + return 0; | |
184 | +} |
@@ -0,0 +1,228 @@ | ||
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 | + static const int reserved_var_names[]; | |
12 | + This dimension contains var name integers of reserved var names. | |
13 | + To make following structure, execute "reservednames.js" in Windows. | |
14 | +*/ | |
15 | + | |
16 | +static const int reserved_var_names[]={ | |
17 | + 0x000106b8, //ABS | |
18 | + 0x0001f67c, //ACOS | |
19 | + 0x0002414c, //ARGS | |
20 | + 0x0001090c, //ASC | |
21 | + 0x0002469f, //ASIN | |
22 | + 0x00024a8f, //ATAN | |
23 | + 0x002f7c1e, //ATAN2 | |
24 | + 0x0047c31c, //BREAK | |
25 | + 0x00575afe, //CDATA | |
26 | + 0x00036c3d, //CEIL | |
27 | + 0x000111af, //CHR | |
28 | + 0x0cb1b682, //CIRCLE | |
29 | + 0x005d1ea3, //CLEAR | |
30 | + 0x00011240, //CLS | |
31 | + 0x005f66cb, //COLOR | |
32 | + 0x000112ac, //COS | |
33 | + 0x0003a041, //COSH | |
34 | + 0x00616415, //CREAD | |
35 | + 0x0de593fb, //CURSOR | |
36 | + 0x00040fbe, //DATA | |
37 | + 0x00011644, //DEC | |
38 | + 0x000116de, //DIM | |
39 | + 0x000100a8, //DO | |
40 | + 0x0004fd8e, //ELSE | |
41 | + 0x1434a177, //ELSEIF | |
42 | + 0x00011c99, //END | |
43 | + 0x0091c927, //ENDIF | |
44 | + 0x00053854, //EXEC | |
45 | + 0x00011e0d, //EXP | |
46 | + 0x000579c8, //FABS | |
47 | + 0x16e3d4be, //FCLOSE | |
48 | + 0x00058fcf, //FEOF | |
49 | + 0x00059895, //FGET | |
50 | + 0x00a67500, //FGETC | |
51 | + 0x0005a3a2, //FILE | |
52 | + 0x177f0ca5, //FINPUT | |
53 | + 0x0005b1df, //FLEN | |
54 | + 0x00aa3445, //FLOAT | |
55 | + 0x00aa363b, //FLOOR | |
56 | + 0x0005b84d, //FMOD | |
57 | + 0x00ac5c9f, //FOPEN | |
58 | + 0x000121db, //FOR | |
59 | + 0x18352839, //FPRINT | |
60 | + 0x0005c865, //FPUT | |
61 | + 0x00ad2e40, //FPUTC | |
62 | + 0x00aefdec, //FSEEK | |
63 | + 0x00063b90, //GCLS | |
64 | + 0x1a808bcb, //GCOLOR | |
65 | + 0x00c60f03, //GOSUB | |
66 | + 0x0006796c, //GOTO | |
67 | + 0x1bcfcc39, //GPRINT | |
68 | + 0x00012a99, //HEX | |
69 | + 0x00010153, //IF | |
70 | + 0x00f8701a, //INKEY | |
71 | + 0x00f88ba5, //INPUT | |
72 | + 0x000130e9, //INT | |
73 | + 0x00092084, //KEYS | |
74 | + 0x013be43d, //LABEL | |
75 | + 0x00013ecf, //LEN | |
76 | + 0x00013ed5, //LET | |
77 | + 0x0009e96a, //LINE | |
78 | + 0x00014030, //LOG | |
79 | + 0x0145f324, //LOG10 | |
80 | + 0x000a07f9, //LOOP | |
81 | + 0x000abca3, //MODF | |
82 | + 0x016418d4, //MUSIC | |
83 | + 0x000b4321, //NEXT | |
84 | + 0x00014a5d, //NOT | |
85 | + 0x000152c0, //PCG | |
86 | + 0x000cacec, //PEEK | |
87 | + 0x00010252, //PI | |
88 | + 0x01ac8479, //POINT | |
89 | + 0x000ce05e, //POKE | |
90 | + 0x00015480, //POW | |
91 | + 0x01aea739, //PRINT | |
92 | + 0x000cf3d5, //PSET | |
93 | + 0x3cc0fe21, //PUTBMP | |
94 | + 0x000e18d5, //READ | |
95 | + 0x00015d2e, //REM | |
96 | + 0x425c9703, //RETURN | |
97 | + 0x00015e69, //RND | |
98 | + 0x45c26d49, //SCROLL | |
99 | + 0x00016287, //SGN | |
100 | + 0x000162cf, //SIN | |
101 | + 0x000ee52d, //SINH | |
102 | + 0x01f9a429, //SOUND | |
103 | + 0x000f0e49, //SQRT | |
104 | + 0x47f711de, //SYSTEM | |
105 | + 0x000166bf, //TAN | |
106 | + 0x000f72ed, //TANH | |
107 | + 0x02182fee, //TVRAM | |
108 | + 0x022c2a2d, //UNTIL | |
109 | + 0x4e8887d0, //USEPCG | |
110 | + 0x4e88a5f3, //USEVAR | |
111 | + 0x000170dd, //VAL | |
112 | + 0x000170e3, //VAR | |
113 | + 0x00119505, //WAIT | |
114 | + 0x0011a9e9, //WEND | |
115 | + 0x025aef62, //WHILE | |
116 | + 0x025b8d75, //WIDTH | |
117 | + // Additional names follow | |
118 | + ADDITIONAL_RESERVED_VAR_NAMES | |
119 | +}; | |
120 | + | |
121 | +/* | |
122 | + check_var_name(); | |
123 | + This function reads the current position of source code and check if | |
124 | + it contains valid var name, the function returns 0 or plus value. | |
125 | + If not, it returns -1; | |
126 | +*/ | |
127 | + | |
128 | +int check_var_name(){ | |
129 | + char b1; | |
130 | + int j; | |
131 | + int i=0; | |
132 | + int prevpos=g_srcpos; | |
133 | + next_position(); | |
134 | + b1=g_source[g_srcpos]; | |
135 | + if (b1<'A' || 'Z'<b1) return -1; | |
136 | + do { | |
137 | + // First character must be A-Z | |
138 | + // From second, A-Z and 0-9 can be used. | |
139 | + i*=36; | |
140 | + if ('0'<=b1 && b1<='9') { | |
141 | + i+=b1-'0'; | |
142 | + } else if (g_srcpos==prevpos) { | |
143 | + // First character must be A-Z. | |
144 | + // Subtract 9, resulting 1-26 but not 10-35. | |
145 | + // This subtraction is required to maintain | |
146 | + // final number being <0x80000000. | |
147 | + i+=b1-'A'+1; | |
148 | + } else { | |
149 | + i+=b1-'A'+10; | |
150 | + } | |
151 | + g_srcpos++; | |
152 | + b1=g_source[g_srcpos]; | |
153 | + } while ('0'<= b1 && b1<='9' || 'A'<=b1 && b1<='Z'); | |
154 | + // Length of the label must be between 2 and 6. | |
155 | + if (g_srcpos-prevpos<2) { | |
156 | + // One letter var name, A-Z | |
157 | + return i-1; | |
158 | + } | |
159 | + if (6<g_srcpos-prevpos) { | |
160 | + // Too long. This is not var name. | |
161 | + g_srcpos=prevpos; | |
162 | + return -1; | |
163 | + } | |
164 | + i+=65536; | |
165 | + // Check if this is reserved var name. | |
166 | + for(j=0;j<sizeof reserved_var_names/sizeof reserved_var_names[0];j++){ | |
167 | + if (reserved_var_names[j]==i) { | |
168 | + // This var name is reserved as used for function or statement. | |
169 | + g_srcpos=prevpos; | |
170 | + return -1; | |
171 | + } | |
172 | + } | |
173 | + // Reserved var names table was checked. This must be a long var name. | |
174 | + return i; | |
175 | +} | |
176 | + | |
177 | +/* | |
178 | + int get_var_number(); | |
179 | + This function returns variable number that can be used as the index of $s8 | |
180 | +*/ | |
181 | + | |
182 | +int get_var_number(){ | |
183 | + int i; | |
184 | + // This must be a short or long var name. | |
185 | + i=check_var_name(); | |
186 | + if (i<0) return -1; | |
187 | + // If it is a short name, immediately return. | |
188 | + if (i<26) return i; | |
189 | + // Search long var names registered by USEVAR statement. | |
190 | + // If found, returns the value that can be used as the index of $s8 | |
191 | + i=search_var_name(i); | |
192 | + if (i<0) return -1; | |
193 | + // This var name is defined by USEVAR statement. | |
194 | + return i+ALLOC_LNV_BLOCK; | |
195 | + | |
196 | +} | |
197 | + | |
198 | +/* | |
199 | + int search_var_name(int nameint); | |
200 | + This function searchs registered long var name in compile data table. | |
201 | + If not found, this function returns -1. | |
202 | + If found, it retunrs var number, beginning 0. | |
203 | +*/ | |
204 | + | |
205 | +int search_var_name(int nameint){ | |
206 | + int* cmpdata; | |
207 | + cmpdata_reset(); | |
208 | + while(cmpdata=cmpdata_find(CMPDATA_USEVAR)){ | |
209 | + if (cmpdata[1]==nameint) return cmpdata[0]&0x0000ffff; | |
210 | + } | |
211 | + return -1; | |
212 | +} | |
213 | + | |
214 | +/* | |
215 | + char* register_var_name(int nameint); | |
216 | + This function is called when compiler detects "USEVAR" statement. | |
217 | + It registers the long file name in compile data table. | |
218 | +*/ | |
219 | + | |
220 | +char* register_var_name(int nameint){ | |
221 | + // Check if registered before. If did, cause error. | |
222 | + if (search_var_name(nameint)!=-1) return ERR_INVALID_VAR_NAME; | |
223 | + // Number of long var name is restricted | |
224 | + if (ALLOC_LNV_NUM<=g_long_name_var_num) return ERR_INVALID_VAR_NAME; | |
225 | + // Register var name as a compile data | |
226 | + g_temp=nameint; | |
227 | + return cmpdata_insert(CMPDATA_USEVAR,g_long_name_var_num++,&g_temp,1); | |
228 | +} |
@@ -0,0 +1,43 @@ | ||
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 | +#define TBUFMAXLINE 181 //テキストバッファ数 | |
9 | + | |
10 | +#define TBUFSIZE 200 //テキストバッファ1つのサイズ | |
11 | +#define TBUFMAXSIZE (TBUFSIZE*(TBUFMAXLINE-1)) //最大バッファ容量(バッファ1行分空ける) | |
12 | +//#define EDITWIDTHX 36 //エディタ画面横幅 | |
13 | +#define EDITWIDTHY 26 //エディタ画面縦幅 | |
14 | +#define COLOR_NORMALTEXT 7 //通常テキスト色 | |
15 | +#define COLOR_ERRORTEXT 4 //エラーメッセージテキスト色 | |
16 | +#define COLOR_AREASELECTTEXT 4 //範囲選択テキスト色 | |
17 | +#define COLOR_BOTTOMLINE 5 //画面最下行の色 | |
18 | +#define COLOR_DIR 6 //ディレクトリ名表示の色 | |
19 | +#define COLOR_INV 128 //モノクロモード時の反転 | |
20 | +#define FILEBUFSIZE 256 //ファイルアクセス用バッファサイズ | |
21 | +#define MAXFILENUM 200 //利用可能ファイル最大数 | |
22 | +#define PATHNAMEMAX 128 //ワーキングディレクトリパス名の最大値 | |
23 | +#define UNDOBUFSIZE 2048 //アンドゥ用バッファサイズ | |
24 | + | |
25 | +#define ERR_FILETOOBIG -1 | |
26 | +#define ERR_CANTFILEOPEN -2 | |
27 | +#define ERR_CANTWRITEFILE -3 | |
28 | + | |
29 | +#define TEMPFILENAME "~TEMP.BAS" //実行時ソース保存ファイル名 | |
30 | +#define WORKDIRFILE "~WORKDIR.TMP" //実行時パス保存ファイル名 | |
31 | + | |
32 | +#define UNDO_INSERT 1 | |
33 | +#define UNDO_OVERWRITE 2 | |
34 | +#define UNDO_DELETE 3 | |
35 | +#define UNDO_BACKSPACE 4 | |
36 | +#define UNDO_CONTINS 5 | |
37 | +#define UNDO_CONTDEL 6 | |
38 | + | |
39 | +void texteditor(void); //テキストエディタ本体 | |
40 | +int runbasic(char *s,int test); //コンパイルして実行 | |
41 | +extern unsigned char tempfile[13]; | |
42 | +void wait60thsec(unsigned short n); | |
43 | + |
@@ -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 "lib_video_megalopa.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,159 @@ | ||
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 | +/* | |
14 | + Enable following line if memory dump is needed when exception occurs. | |
15 | +*/ | |
16 | + | |
17 | +//#define DUMPFILE "~~MEMORY.DMP" | |
18 | + | |
19 | +#ifdef DUMPFILE | |
20 | +void dumpMemory(){ | |
21 | + unsigned int i; | |
22 | + FSFILE *fp; | |
23 | + printstr("\n"DUMPFILE" "); | |
24 | + if(FSInit()==FALSE){ | |
25 | + printstr("cannot be created.\n"); | |
26 | + return; | |
27 | + } | |
28 | + fp=FSfopen(DUMPFILE,"w"); | |
29 | + if(fp==NULL) { | |
30 | + printstr("not saved.\n"); | |
31 | + return; | |
32 | + } | |
33 | + for(i=0;i<PERSISTENT_RAM_SIZE;i+=512){ | |
34 | + if (FSfwrite(&RAM[i],1,512,fp)<512) break; | |
35 | + } | |
36 | + FSfclose(fp); | |
37 | + printstr("saved.\n"); | |
38 | +} | |
39 | +#else | |
40 | +void dumpMemory(){} | |
41 | +#endif //ifdef DUMPFILE | |
42 | + | |
43 | +void _general_exception_handler (void){ | |
44 | + int i; | |
45 | + // $v1 is g_ex_data | |
46 | + asm volatile("la $v1,%0"::"i"(&g_ex_data[0])); | |
47 | + // Prepare proper stack area before SoftReset | |
48 | + asm volatile("addiu $sp,$v1,0xfff0"); | |
49 | + // g_ex_data[2]=$s6 | |
50 | + asm volatile("sw $s6,8($v1)"); | |
51 | + // g_ex_data[3]=Cause | |
52 | + asm volatile("mfc0 $v0,$13"); | |
53 | + asm volatile("sw $v0,12($v1)"); | |
54 | + // g_ex_data[4]=EPC | |
55 | + asm volatile("mfc0 $v0,$14"); | |
56 | + asm volatile("sw $v0,16($v1)"); | |
57 | + // Exception occured | |
58 | + g_ex_data[0]=1; | |
59 | + // g_s6 | |
60 | + g_ex_data[1]=g_s6; | |
61 | + // Clear 2 MLB bits of EPC | |
62 | + g_ex_data[4]&=0xfffffffc; | |
63 | + // If EPC is within RAM, store data in exception area. | |
64 | + if ((int)(&RAM[0])<=g_ex_data[4] && g_ex_data[4] <(int)(&RAM[RAMSIZE])) { | |
65 | + // g_ex_data[5] - g_ex_data[12]: assembly | |
66 | + for(i=-3;i<=3;i++){ | |
67 | + g_ex_data[i+8]=((int*)g_ex_data[4])[i]; | |
68 | + } | |
69 | + } | |
70 | + // Wait until all buttons are released and reset MachiKania. | |
71 | + #ifdef __DEBUG | |
72 | + asm volatile("j 0xBFC00000"); | |
73 | + #else | |
74 | + for(i=0;i<100000;i++){ | |
75 | + if((readbuttons()&(KEYUP|KEYDOWN|KEYLEFT|KEYRIGHT|KEYSTART|KEYFIRE)) | |
76 | + !=(KEYUP|KEYDOWN|KEYLEFT|KEYRIGHT|KEYSTART|KEYFIRE)) i=0; | |
77 | + } | |
78 | + asm volatile("j SoftReset"); | |
79 | + #endif | |
80 | +} | |
81 | + | |
82 | +void blue_screen(void){ | |
83 | + int i,j,s6,s6g; | |
84 | + unsigned int* opos; | |
85 | + if (RCONbits.POR || RCONbits.EXTR) { | |
86 | + // After power on or reset. Reset flags and return. | |
87 | + RCONbits.POR=0; | |
88 | + RCONbits.EXTR=0; | |
89 | + for(i=0;i<RAMSIZE;i++){ | |
90 | + // Reset all RAM area including g_ex_data[] | |
91 | + RAM[i]=0; | |
92 | + } | |
93 | + return; | |
94 | + } else if (g_ex_data[0]==0) { | |
95 | + // No exception found. | |
96 | + return; | |
97 | + } | |
98 | + // Exception occured before SoftReset(). | |
99 | + // Prepare data | |
100 | + s6=g_ex_data[2]; | |
101 | + s6g=g_ex_data[1]; | |
102 | + s6=s6&0x7fffffff; | |
103 | + s6g=s6g&0x7fffffff; | |
104 | + opos=(int*)g_ex_data[4]; | |
105 | + //set_bgcolor(255,0,0); | |
106 | + printstr("STOP"); | |
107 | + printstr("\nException at "); | |
108 | + printhex32(g_ex_data[4]); | |
109 | + printstr("\n Cause: "); | |
110 | + printhex32(g_ex_data[3]); | |
111 | + printstr("\n "); | |
112 | + switch((g_ex_data[3]>>2)&0x1f){ | |
113 | + case 0: printstr("(Interrupt)"); break; | |
114 | + case 1: printstr("(TLB modification)"); break; | |
115 | + case 2: printstr("(TLB load/fetch)"); break; | |
116 | + case 3: printstr("(TLB store)"); break; | |
117 | + case 4: printstr("(Address load/fetch error )"); break; | |
118 | + case 5: printstr("(Address store error)"); break; | |
119 | + case 6: printstr("(Bus fetch error)"); break; | |
120 | + case 7: printstr("(Bus load/store error)"); break; | |
121 | + case 8: printstr("(Syscall)"); break; | |
122 | + case 9: printstr("(Breakpoint)"); break; | |
123 | + case 10: printstr("(Reserved instruction)"); break; | |
124 | + case 11: printstr("(Coprocessor Unusable)"); break; | |
125 | + case 12: printstr("(Integer Overflow)"); break; | |
126 | + case 13: printstr("(Trap)"); break; | |
127 | + case 23: printstr("(Reference to Watch address)"); break; | |
128 | + case 24: printstr("(Machine check)"); break; | |
129 | + default: printstr("(Unknown)"); break; | |
130 | + } | |
131 | + printstr("\n s6: "); | |
132 | + printstr(resolve_label(s6)); | |
133 | + printstr("\n g_s6: "); | |
134 | + printstr(resolve_label(s6g)); | |
135 | + printstr("\n"); | |
136 | + printstr("Reset MachiKania to contine.\n\n"); | |
137 | + // Show code where the exception happened. | |
138 | + for(i=-3;i<=3;i++){ | |
139 | + printstr("\n "); | |
140 | + printhex32((unsigned int)&opos[i]); | |
141 | + printstr(" "); | |
142 | + if ((unsigned int)&RAM[0]<=(unsigned int)&opos[i] && (unsigned int)&opos[i]<(unsigned int)&RAM[RAMSIZE]) { | |
143 | + // Exception in RAM[RAMSIZE] area | |
144 | + printhex32(g_ex_data[i+8]); | |
145 | + } else if ( 0xA0000000<=(unsigned int)&opos[i] && (unsigned int)&opos[i]<0xA0000000+PIC32MX_RAMSIZE | |
146 | + || 0x9D000000<=(unsigned int)&opos[i] && (unsigned int)&opos[i]<=0x9D000000+PIC32MX_FLASHSIZE) { | |
147 | + // Exception in outside RAM[RAMSIZE] or flash area | |
148 | + printhex32(opos[i]); | |
149 | + } else { | |
150 | + printstr("********"); | |
151 | + } | |
152 | + } | |
153 | + printstr("\n"); | |
154 | + | |
155 | +#ifndef __DEBUG | |
156 | + dumpMemory(); | |
157 | +#endif | |
158 | + while(1) asm("wait"); | |
159 | +} |
@@ -0,0 +1,79 @@ | ||
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 | +unsigned 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 | + | |
72 | +// Parameter-containing block used for library | |
73 | +int* g_libparams; | |
74 | + | |
75 | +// Number of long name variables | |
76 | +int g_long_name_var_num; | |
77 | + | |
78 | +// General purpose integer used for asigning value with pointer | |
79 | +int g_temp; |
@@ -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 | +// Macros for dummy functions | |
172 | +#define ps2mode() (0) | |
173 | +#define buttonmode() (0) | |
174 | +#define inPS2MODE() (1) |
@@ -0,0 +1,42 @@ | ||
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 "lib_video_megalopa.h" | |
36 | +#include "sdfsio370f.h" | |
37 | +#include "ps2keyboard.h" | |
38 | +#include "debug.h" | |
39 | + | |
40 | +// Palette is shared between text and graphic | |
41 | +#define g_set_palette set_palette | |
42 | + |
@@ -0,0 +1,86 @@ | ||
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 | + This file provide functions for handling data used when compiling. | |
12 | + The data is inserted between g_objmax and file cache. | |
13 | + Data format (32 bit): | |
14 | + MSB LSB | |
15 | + +----+----+--------+ | |
16 | + |type|len | data16 | | |
17 | + +----+----+--------+ | |
18 | + where, | |
19 | + type: data type number (unsigned char) | |
20 | + len: length of data area in number of words (unsigned char) | |
21 | + data16: general 16 bit data (short) | |
22 | +*/ | |
23 | + | |
24 | +#define g_cmpdata g_objmax | |
25 | + | |
26 | +static int* g_cmpdata_end; | |
27 | +static int* g_cmpdata_point; | |
28 | + | |
29 | +/* | |
30 | + Initialize routine must be called when starting compiler. | |
31 | +*/ | |
32 | +void cmpdata_init(){ | |
33 | + g_cmpdata_end=g_objmax; | |
34 | + g_cmpdata_point=g_objmax; | |
35 | +} | |
36 | + | |
37 | +/* | |
38 | + Function to insert a data. The data must be defined by a pointer to int array. | |
39 | + unsigned char type: Data type number (0-255) | |
40 | + short data16: 16 bit data. If not required, set 0. | |
41 | + int* data: Pointer to data array. If not requird, set 0. | |
42 | + unsigned char num: Length of above data array. If not required, set 0. | |
43 | +*/ | |
44 | +char* cmpdata_insert(unsigned char type, short data16, int* data, unsigned char num){ | |
45 | + unsigned char i; | |
46 | + g_cmpdata-=num+1; | |
47 | + if (g_cmpdata<g_object+g_objpos) return ERR_NE_BINARY; | |
48 | + g_cmpdata[0]=(type<<24)|(num+1)<<16|data16; | |
49 | + for(i=0;i<num;i++){ | |
50 | + g_cmpdata[i+1]=data[i]; | |
51 | + } | |
52 | + return 0; | |
53 | +} | |
54 | + | |
55 | +/* | |
56 | + Reset data point. Next search will be from the beginning. | |
57 | +*/ | |
58 | + | |
59 | +void cmpdata_reset(){ | |
60 | + g_cmpdata_point=g_cmpdata; | |
61 | +} | |
62 | + | |
63 | +/* | |
64 | + Find the next record with defined type. Return the pointer to the record. | |
65 | +*/ | |
66 | +int* cmpdata_find(unsigned char type){ | |
67 | + int* ret; | |
68 | + while(g_cmpdata_point<g_cmpdata_end){ | |
69 | + // Remember return value | |
70 | + ret=g_cmpdata_point; | |
71 | + // Move the point to next | |
72 | + g_cmpdata_point+=(ret[0]&0x00ff0000)>>16; | |
73 | + // Check if type is the same. If the same, return. | |
74 | + if ((ret[0]>>24)==type) return ret; | |
75 | + } | |
76 | + return 0; | |
77 | +} | |
78 | + | |
79 | +/* | |
80 | + Find the record from beginning. | |
81 | +*/ | |
82 | + | |
83 | +int* cmpdata_findfirst(unsigned char type){ | |
84 | + cmpdata_reset(); | |
85 | + return cmpdata_find(type); | |
86 | +} |
@@ -0,0 +1,143 @@ | ||
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(1); | |
30 | + g_object[g_objpos++]=0x34040000; // ori a0,zero,0 | |
31 | + call_lib_code(LIB_FLOAT | OP_SUB); | |
32 | + } else { | |
33 | + // Main routine of getting float value here | |
34 | + if (b1=='+') g_srcpos++; // Ignore unary '+' operator | |
35 | + next_position(); | |
36 | + b1=g_source[g_srcpos]; | |
37 | + b2=g_source[g_srcpos+1]; | |
38 | + b3=g_source[g_srcpos+2]; | |
39 | + if ('0'<=b1 && b1<='9') { | |
40 | + f=strtof((const char*)&g_source[g_srcpos],&err); | |
41 | + if (&g_source[g_srcpos]==err) return ERR_SYNTAX; | |
42 | + g_srcpos=err-g_source; | |
43 | + i=((int*)(&f))[0]; | |
44 | + if (i&0xFFFF0000) { | |
45 | + // 32 bit | |
46 | + check_obj_space(2); | |
47 | + g_object[g_objpos++]=0x3C020000|((i>>16)&0x0000FFFF); // lui v0,xxxx | |
48 | + g_object[g_objpos++]=0x34420000|(i&0x0000FFFF); // ori v0,v0,xxxx | |
49 | + } else { | |
50 | + // 16 bit | |
51 | + check_obj_space(1); | |
52 | + g_object[g_objpos++]=0x34020000|(i&0x0000FFFF); // ori v0,zero,xxxx | |
53 | + } | |
54 | + } else { | |
55 | + i=get_var_number(); | |
56 | + if (i<0) { | |
57 | + // Must be a function. | |
58 | + return float_function(); | |
59 | + } | |
60 | + if (g_source[g_srcpos]!='#') return ERR_SYNTAX; | |
61 | + g_srcpos++; | |
62 | + if (g_source[g_srcpos]=='(') { | |
63 | + // Dimension | |
64 | + g_srcpos++; | |
65 | + return get_dim_value(i); | |
66 | + } | |
67 | + // Simple value | |
68 | + check_obj_space(1); | |
69 | + g_object[g_objpos++]=0x8FC20000|(i*4); // lw v0,xx(s8) | |
70 | + } | |
71 | + } | |
72 | + // No error | |
73 | + return 0; | |
74 | +} | |
75 | + | |
76 | +char* get_float_sub(int pr){ | |
77 | + char* err; | |
78 | + enum operator op; | |
79 | + char b1,b2,b3; | |
80 | + int prevpos; | |
81 | + // Get a value in $v0. | |
82 | + err=get_simple_float(); | |
83 | + if (err) return err; | |
84 | + while(1){ | |
85 | + // Get the operator in op. If not valid operator, simply return without error. | |
86 | + prevpos=g_srcpos; | |
87 | + err=get_floatOperator(); | |
88 | + if (err) return 0; | |
89 | + op=g_last_op; | |
90 | + // Compair current and previous operators. | |
91 | + // If the previous operator has higher priolity, return. | |
92 | + if (pr>=priority(op)) { | |
93 | + g_srcpos=prevpos; | |
94 | + return 0; | |
95 | + } | |
96 | + // Store $v0 in stack | |
97 | + g_sdepth+=4; | |
98 | + if (g_maxsdepth<g_sdepth) g_maxsdepth=g_sdepth; | |
99 | + check_obj_space(1); | |
100 | + g_object[g_objpos++]=0xAFA20000|g_sdepth; // sw v0,xx(sp) | |
101 | + // Get next value. | |
102 | + err=get_float_sub(priority(op)); | |
103 | + if (err) return err; | |
104 | + // Get value from stack to $a0. | |
105 | + check_obj_space(1); | |
106 | + g_object[g_objpos++]=0x8FA40000|g_sdepth; // lw a0,xx(sp) | |
107 | + g_sdepth-=4; | |
108 | + // Calculation. Result will be in $v0. | |
109 | + err=calculation_float(op); | |
110 | + if (err) return err; | |
111 | + } | |
112 | +} | |
113 | + | |
114 | +char* get_float(){ | |
115 | + // Note that this can be called recursively. | |
116 | + // Value may contain function with a parameter of another value. | |
117 | + char* err; | |
118 | + int prevpos; | |
119 | + if (g_sdepth==0) { | |
120 | + // Initialize stack handler | |
121 | + g_maxsdepth=0; | |
122 | + prevpos=g_objpos; | |
123 | + // Stack decrement command will be filled later | |
124 | + check_obj_space(1); | |
125 | + g_objpos++; | |
126 | + } | |
127 | + err=get_float_sub(priority(OP_VOID)); | |
128 | + if (err) return err; | |
129 | + if (g_sdepth==0) { | |
130 | + if (g_maxsdepth==0) { | |
131 | + // Stack was not used. | |
132 | + shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1); | |
133 | + g_objpos--; | |
134 | + } else { | |
135 | + // Stack was used. | |
136 | + check_obj_space(1); | |
137 | + g_object[prevpos]=0x27BD0000 | (0-g_maxsdepth) & 0x0000FFFF; // addiu sp,sp,-xx | |
138 | + g_object[g_objpos++]=0x27BD0000 | g_maxsdepth & 0x0000FFFF; // addiu sp,sp,xx | |
139 | + } | |
140 | + } | |
141 | + g_lastvar=VAR_FLOAT; | |
142 | + return 0; | |
143 | +} | |
\ No newline at end of file |
@@ -0,0 +1,216 @@ | ||
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') { | |
80 | + i=get_var_number(); | |
81 | + if (i<0) { | |
82 | + // Function | |
83 | + // String would be pointed by $v0 | |
84 | + // Otherwise, it will be assinged in xxx_function() function. | |
85 | + err=str_function(); | |
86 | + if (err) return err; | |
87 | + // Temp area would be used when executing. | |
88 | + g_temp_area_used=1; | |
89 | + return 0; | |
90 | + } | |
91 | + if (g_source[g_srcpos]!='$') return ERR_SYNTAX; | |
92 | + g_srcpos++; | |
93 | + // String variable | |
94 | + next_position(); | |
95 | + if (g_source[g_srcpos]=='(') { | |
96 | + // A part of string | |
97 | + g_srcpos++; | |
98 | + err=get_value(); | |
99 | + if (err) return err; | |
100 | + if (g_source[g_srcpos]==')') { | |
101 | + g_srcpos++; | |
102 | + // Put -1 to $a0 | |
103 | + check_obj_space(1); | |
104 | + g_object[g_objpos++]=0x2404FFFF; // addiu a0,zero,-1 | |
105 | + } else if (g_source[g_srcpos]==',') { | |
106 | + g_srcpos++; | |
107 | + // Store $v0 in stack | |
108 | + g_sdepth+=4; | |
109 | + if (g_maxsdepth<g_sdepth) g_maxsdepth=g_sdepth; | |
110 | + check_obj_space(1); | |
111 | + g_object[g_objpos++]=0xAFA20000|g_sdepth; // sw v0,xx(sp) | |
112 | + // Get next value | |
113 | + err=get_value(); | |
114 | + if (err) return err; | |
115 | + // Copy $v0 to $a0 and get value from stack to $a0. | |
116 | + check_obj_space(2); | |
117 | + g_object[g_objpos++]=0x00402021; // addu a0,v0,zero | |
118 | + g_object[g_objpos++]=0x8FA20000|g_sdepth; // lw v0,xx(sp) | |
119 | + g_sdepth-=4; | |
120 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
121 | + g_srcpos++; | |
122 | + // Temp area will be used when executing. | |
123 | + g_temp_area_used=1; | |
124 | + } else { | |
125 | + return ERR_SYNTAX; | |
126 | + } | |
127 | + // $a1 is var number, $v0 is position, $a0 is length | |
128 | + check_obj_space(1); | |
129 | + g_object[g_objpos++]=0x24050000|(i); // addiu a1,zero,xx | |
130 | + call_lib_code(LIB_MIDSTR); | |
131 | + } else { | |
132 | + // Simple string | |
133 | + check_obj_space(1); | |
134 | + g_object[g_objpos++]=0x8FC20000|(i*4); // lw v0,xx(s8) | |
135 | + // String is pointed by $v0 | |
136 | + } | |
137 | + } else { | |
138 | + return ERR_SYNTAX; | |
139 | + } | |
140 | + return 0; | |
141 | +} | |
142 | + | |
143 | +char* get_string_sub(){ | |
144 | + char* err; | |
145 | + char b1; | |
146 | + // Obtain initial string | |
147 | + err=simple_string(); | |
148 | + if (err) return err; | |
149 | + // Check if connection operator exists | |
150 | + next_position(); | |
151 | + b1=g_source[g_srcpos]; | |
152 | + if (b1!='+' && b1!='&') return 0; // Exit if connection operator does not exist. | |
153 | + g_srcpos++; | |
154 | + // Connection required. | |
155 | + // Prepare one level of stack for handling | |
156 | + g_sdepth+=4; | |
157 | + if (g_maxsdepth<g_sdepth) g_maxsdepth=g_sdepth; | |
158 | + while(1) { | |
159 | + // Store current pointer in stack | |
160 | + check_obj_space(1); | |
161 | + g_object[g_objpos++]=0xAFA20000|g_sdepth; // sw v0,xx(sp) | |
162 | + // Obtain next string (pointer will be in $v0) | |
163 | + err=simple_string(); | |
164 | + if (err) return err; | |
165 | + // Restore previous pointer from stack in $a0 and copy $v0 to $a1 | |
166 | + // Call library | |
167 | + check_obj_space(2); | |
168 | + g_object[g_objpos++]=0x8FA40000|g_sdepth; // lw a0,xx(sp) | |
169 | + call_lib_code(LIB_CONNECT_STRING); | |
170 | + // Temp area will be used when executing. | |
171 | + g_temp_area_used=1; | |
172 | + // Check if further connection operator exists | |
173 | + next_position(); | |
174 | + b1=g_source[g_srcpos]; | |
175 | + if (b1!='+' && b1!='&') break; | |
176 | + g_srcpos++; | |
177 | + } | |
178 | + g_sdepth-=4; | |
179 | + return 0; | |
180 | +} | |
181 | + | |
182 | +char* get_string(){ | |
183 | + // This is only the public function. | |
184 | + // Note that this can be called recursively. | |
185 | + // String may contain a function with a parameter of value | |
186 | + // that is a function with a parameter of string. | |
187 | + // Result will be in $v0 as a pointer. | |
188 | + char* err; | |
189 | + char b1; | |
190 | + int i,prevpos; | |
191 | + if (g_sdepth==0) { | |
192 | + // Initialize stack handler | |
193 | + g_maxsdepth=0; | |
194 | + prevpos=g_objpos; | |
195 | + // Stack decrement command will be filled later | |
196 | + check_obj_space(1); | |
197 | + g_objpos++; | |
198 | + } | |
199 | + err=get_string_sub(); | |
200 | + if (err) return err; | |
201 | + if (g_sdepth==0) { | |
202 | + if (g_maxsdepth==0) { | |
203 | + // Stack was not used. | |
204 | + shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1); | |
205 | + g_objpos--; | |
206 | + } else { | |
207 | + // Stack was used. | |
208 | + check_obj_space(1); | |
209 | + g_object[prevpos]=0x27BD0000 | (0-g_maxsdepth) & 0x0000FFFF; // addiu sp,sp,-xx | |
210 | + g_object[g_objpos++]=0x27BD0000 | g_maxsdepth & 0x0000FFFF; // addiu sp,sp,xx | |
211 | + } | |
212 | + } | |
213 | + g_lastvar=VAR_STRING; | |
214 | + return 0; | |
215 | +} | |
216 | + |
@@ -0,0 +1,267 @@ | ||
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(int i){ | |
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|(i*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 | + // Use a stack | |
30 | + g_sdepth+=4; | |
31 | + if (g_maxsdepth<g_sdepth) g_maxsdepth=g_sdepth; | |
32 | + check_obj_space(1); | |
33 | + do { | |
34 | + g_srcpos++; | |
35 | + g_object[g_objpos++]=0xAFA20000|g_sdepth; // sw v0,xx(sp) | |
36 | + err=get_value_sub(priority(OP_VOID)); | |
37 | + if (err) return err; | |
38 | + check_obj_space(5); | |
39 | + g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
40 | + g_object[g_objpos++]=0x8FA30000|g_sdepth; // lw v1,xx(sp) | |
41 | + g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
42 | + g_object[g_objpos++]=0x8C620000; // lw v0,0(v1) | |
43 | + } while (g_source[g_srcpos]==','); | |
44 | + g_sdepth-=4; | |
45 | + } | |
46 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
47 | + g_srcpos++; | |
48 | + return 0; | |
49 | +} | |
50 | + | |
51 | +char* get_simple_value(void){ | |
52 | + int i; | |
53 | + char* err; | |
54 | + char b1,b2; | |
55 | + next_position(); | |
56 | + b1=g_source[g_srcpos]; | |
57 | + if (b1=='(') { | |
58 | + // (...) | |
59 | + // Parenthesis | |
60 | + g_srcpos++; | |
61 | + next_position(); | |
62 | + err=get_value_sub(priority(OP_VOID)); | |
63 | + if (err) return err; | |
64 | + next_position(); | |
65 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
66 | + g_srcpos++; | |
67 | + } else if (b1=='-') { | |
68 | + // Unary '-' operator | |
69 | + // Note that unary operators ( + and - ) have higher priority than the other operators | |
70 | + g_srcpos++; | |
71 | + err=get_simple_value(); | |
72 | + if (err) return err; | |
73 | + check_obj_space(1); | |
74 | + g_object[g_objpos++]=0x00021023; // subu v0,zero,v0 | |
75 | + g_intconst=-g_intconst; | |
76 | + } else { | |
77 | + // Main routine of getting value here | |
78 | + if (b1=='+') g_srcpos++; // Ignore unary '+' operator | |
79 | + next_position(); | |
80 | + b1=g_source[g_srcpos]; | |
81 | + b2=g_source[g_srcpos+1]; | |
82 | + if (b1=='0' && b2=='X' || b1=='$') { | |
83 | + // Starts with '0x' or '$' | |
84 | + // Hex number | |
85 | + g_srcpos++; | |
86 | + if (b1=='0') g_srcpos++; | |
87 | + i=0; | |
88 | + while(b1=g_source[g_srcpos]) { | |
89 | + if ('0'<=b1 && b1<='9') { | |
90 | + i*=16; | |
91 | + i+=b1-'0'; | |
92 | + } else if ('A'<=b1 && b1<='F') { | |
93 | + i*=16; | |
94 | + i+=b1-'A'+0x0A; | |
95 | + } else { | |
96 | + break; | |
97 | + } | |
98 | + g_srcpos++; | |
99 | + } | |
100 | + g_intconst=i; | |
101 | + if (i&0xFFFF0000) { | |
102 | + // 32 bit | |
103 | + check_obj_space(2); | |
104 | + g_object[g_objpos++]=0x3C020000|((i>>16)&0x0000FFFF); // lui v0,xxxx | |
105 | + g_object[g_objpos++]=0x34420000|(i&0x0000FFFF); // ori v0,v0,xxxx | |
106 | + } else { | |
107 | + // 16 bit | |
108 | + check_obj_space(1); | |
109 | + g_object[g_objpos++]=0x34020000|(i&0x0000FFFF); // ori v0,zero,xxxx | |
110 | + } | |
111 | + } else if ('0'<=b1 && b1<='9') { | |
112 | + // Starts with 0-9 | |
113 | + // Decimal number | |
114 | + i=0; | |
115 | + while(b1=g_source[g_srcpos]) { | |
116 | + if ('0'<=b1 && b1<='9') { | |
117 | + i*=10; | |
118 | + i+=b1-'0'; | |
119 | + } else { | |
120 | + break; | |
121 | + } | |
122 | + g_srcpos++; | |
123 | + } | |
124 | + // The next character should not be '.' or 'E'. | |
125 | + // Or, it must be recognized as a float value. | |
126 | + if (b1=='.' || b1=='E') return ERR_SYNTAX; | |
127 | + g_intconst=i; | |
128 | + if (i&0xFFFF0000) { | |
129 | + // 32 bit | |
130 | + check_obj_space(2); | |
131 | + g_object[g_objpos++]=0x3C020000|((i>>16)&0x0000FFFF); // lui v0,xxxx | |
132 | + g_object[g_objpos++]=0x34420000|(i&0x0000FFFF); // ori v0,v0,xxxx | |
133 | + } else { | |
134 | + // 16 bit | |
135 | + check_obj_space(1); | |
136 | + g_object[g_objpos++]=0x34020000|(i&0x0000FFFF); // ori v0,zero,xxxx | |
137 | + } | |
138 | + } else { | |
139 | + g_valueisconst=0; | |
140 | + i=get_var_number(); | |
141 | + if (i<0) { | |
142 | + // Must be a function. | |
143 | + return function(); | |
144 | + } | |
145 | + if (g_source[g_srcpos]=='(') { | |
146 | + // Dimension | |
147 | + g_srcpos++; | |
148 | + return get_dim_value(i); | |
149 | + } | |
150 | + // Simple value | |
151 | + check_obj_space(1); | |
152 | + g_object[g_objpos++]=0x8FC20000|(i*4); // lw v0,xx(s8) | |
153 | + } | |
154 | + } | |
155 | + // No error | |
156 | + return 0; | |
157 | +} | |
158 | + | |
159 | +char* get_value_sub(int pr){ | |
160 | + char* err; | |
161 | + enum operator op; | |
162 | + char b1,b2,b3; | |
163 | + int prevpos; | |
164 | + // Get a value in $v0. | |
165 | + err=get_simple_value(); | |
166 | + if (err) return err; | |
167 | + while(1){ | |
168 | + // Get the operator in op. If not valid operator, simply return without error. | |
169 | + prevpos=g_srcpos; | |
170 | + err=get_operator(); | |
171 | + if (err) return 0; | |
172 | + op=g_last_op; | |
173 | + // Compair current and previous operators. | |
174 | + // If the previous operator has higher priolity, return. | |
175 | + if (pr>=priority(op)) { | |
176 | + g_srcpos=prevpos; | |
177 | + return 0; | |
178 | + } | |
179 | + // Store $v0 in stack | |
180 | + g_sdepth+=4; | |
181 | + if (g_maxsdepth<g_sdepth) g_maxsdepth=g_sdepth; | |
182 | + check_obj_space(1); | |
183 | + g_object[g_objpos++]=0xAFA20000|g_sdepth; // sw v0,xx(sp) | |
184 | + // Get next value. | |
185 | + err=get_value_sub(priority(op)); | |
186 | + if (err) return err; | |
187 | + // Get value from stack to $v1. | |
188 | + check_obj_space(1); | |
189 | + g_object[g_objpos++]=0x8FA30000|g_sdepth; // lw v1,xx(sp) | |
190 | + g_sdepth-=4; | |
191 | + // Calculation. Result will be in $v0. | |
192 | + err=calculation(op); | |
193 | + if (err) return err; | |
194 | + } | |
195 | +} | |
196 | + | |
197 | +char* get_value(){ | |
198 | + // This is only the public function. | |
199 | + // Note that this can be called recursively. | |
200 | + // Value may contain function with a parameter of another value. | |
201 | + char* err; | |
202 | + int prevpos; | |
203 | + if (g_sdepth==0) { | |
204 | + // Initialize stack handler | |
205 | + g_maxsdepth=0; | |
206 | + prevpos=g_objpos; | |
207 | + // Stack decrement command will be filled later | |
208 | + check_obj_space(1); | |
209 | + g_objpos++; | |
210 | + } | |
211 | + err=get_value_sub(priority(OP_VOID)); | |
212 | + if (err) return err; | |
213 | + if (g_sdepth==0) { | |
214 | + if (g_maxsdepth==0) { | |
215 | + // Stack was not used. | |
216 | + shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1); | |
217 | + g_objpos--; | |
218 | + } else { | |
219 | + // Stack was used. | |
220 | + check_obj_space(1); | |
221 | + g_object[prevpos]=0x27BD0000 | (0-g_maxsdepth) & 0x0000FFFF; // addiu sp,sp,-xx | |
222 | + g_object[g_objpos++]=0x27BD0000 | g_maxsdepth & 0x0000FFFF; // addiu sp,sp,xx | |
223 | + } | |
224 | + } | |
225 | + g_lastvar=VAR_INTEGER; | |
226 | + return 0; | |
227 | +} | |
228 | + | |
229 | +char* get_floatOrValue(){ | |
230 | + char* err; | |
231 | + char b; | |
232 | + int opos,spos,sdpt; | |
233 | + sdpt=g_sdepth; | |
234 | + opos=g_objpos; | |
235 | + spos=g_srcpos; | |
236 | + // First try integer. | |
237 | + // Integer value has the higher priolity than float value. | |
238 | + err=get_value(); | |
239 | + b=g_source[g_srcpos]; | |
240 | + if (err || b=='#') { | |
241 | + // Value is not integer. Let's try float. | |
242 | + g_sdepth=sdpt; | |
243 | + g_objpos=opos; | |
244 | + g_srcpos=spos; | |
245 | + return get_float(); | |
246 | + } else { | |
247 | + // Value was recognized as an integer. | |
248 | + return 0; | |
249 | + } | |
250 | +} | |
251 | + | |
252 | +char* get_stringFloatOrValue(){ | |
253 | + char* err; | |
254 | + int opos,spos; | |
255 | + opos=g_objpos; | |
256 | + spos=g_srcpos; | |
257 | + // First try string, float, then integer. | |
258 | + err=get_string(); | |
259 | + if (err) { | |
260 | + g_objpos=opos; | |
261 | + g_srcpos=spos; | |
262 | + return get_floatOrValue(); | |
263 | + } else { | |
264 | + return 0; | |
265 | + } | |
266 | +} | |
267 | + |
@@ -0,0 +1,151 @@ | ||
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 | + next_position(); | |
82 | + for(len=0;str[len];len++); | |
83 | + if (!strncmp(g_source+g_srcpos,str,len)) { | |
84 | + if ('A'<=str[len-1] && str[len-1]<='Z') { | |
85 | + // When the last character of str is alphabet, | |
86 | + // the next character in source must be space, enter, or ':'. | |
87 | + if (0x20<g_source[g_srcpos+len] && g_source[g_srcpos+len]!=':') return 0; | |
88 | + } | |
89 | + // String matches in the current position in source. | |
90 | + g_srcpos+=len; | |
91 | + return len; | |
92 | + } else { | |
93 | + // String didn't match. | |
94 | + return 0; | |
95 | + } | |
96 | +} | |
97 | + | |
98 | +int endOfStatement(){ | |
99 | + unsigned char b; | |
100 | + next_position(); | |
101 | + b=g_source[g_srcpos]; | |
102 | + return (b<0x20 || b==':') ? 1:0; | |
103 | +} | |
104 | + | |
105 | +char* compile_line(void){ | |
106 | + char b1; | |
107 | + char* err; | |
108 | + g_line++; | |
109 | + g_fileline++; | |
110 | + // Check if line number exists | |
111 | + next_position(); | |
112 | + b1=g_source[g_srcpos]; | |
113 | + if (b1<0x20) { | |
114 | + // The end of line. | |
115 | + // Don't add $s6-setting command. | |
116 | + if (g_source[g_srcpos]==0x0D && g_source[g_srcpos+1]==0x0A) g_srcpos++; | |
117 | + g_srcpos++; | |
118 | + return 0; | |
119 | + } else if ('0'<=b1 && b1<='9') { | |
120 | + // Line number exists | |
121 | + err=get_label(); | |
122 | + if (err) return err; | |
123 | + g_line=g_label; | |
124 | + } | |
125 | + // Store line number in $s6 | |
126 | + if (!(g_line&0xFFFF0000)) { | |
127 | + // Line number must be less than 65536. | |
128 | + // If not, it is invalid number. | |
129 | + // Check existing line with the same number here. | |
130 | + if (search_label(g_line)) { | |
131 | + // Error: duplicate lines | |
132 | + printstr("Line "); | |
133 | + printstr(resolve_label(g_line)); | |
134 | + return ERR_MULTIPLE_LABEL; | |
135 | + } | |
136 | + check_obj_space(1); | |
137 | + g_object[g_objpos++]=0x34160000|g_line; //ori s6,zero,xxxx; | |
138 | + } | |
139 | + while(g_source[g_srcpos]!=0x0D && g_source[g_srcpos]!=0x0A){ | |
140 | + err=statement(); | |
141 | + if (err) return err; | |
142 | + next_position(); | |
143 | + if (g_source[g_srcpos]==':') { | |
144 | + g_srcpos++; | |
145 | + next_position(); | |
146 | + } | |
147 | + } | |
148 | + if (g_source[g_srcpos]==0x0D && g_source[g_srcpos+1]==0x0A) g_srcpos++; | |
149 | + g_srcpos++; | |
150 | + return 0; | |
151 | +} | |
\ 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,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,390 @@ | ||
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 | + } | |
101 | + } | |
102 | + // Line number not found. | |
103 | + return 0; | |
104 | + } else { | |
105 | + // Line number | |
106 | + search1=0x34160000|label; //ori s6,zero,xxxx; | |
107 | + for(i=0;i<g_objpos;i++){ | |
108 | + code=g_object[i]; | |
109 | + if (code==search1) { | |
110 | + // Line number found | |
111 | + return &(g_object[i]); | |
112 | + } | |
113 | + if (code&0xFFFF0000==0x04110000) { | |
114 | + // "bgezal zero," assembly found. Skip following block (strig). | |
115 | + i+=code&0x0000FFFF; | |
116 | + } | |
117 | + } | |
118 | + // Line number not found. | |
119 | + return 0; | |
120 | + } | |
121 | +} | |
122 | + | |
123 | +void* search_breakout(unsigned int start, int* prevcode){ | |
124 | + unsigned int pos,code1,depth; | |
125 | + // Start search from start point where BREAK statement is used. | |
126 | + depth=0; | |
127 | + for(pos=start;pos<g_objpos;pos++){ | |
128 | + code1=g_object[pos]; | |
129 | + switch(code1>>16){ | |
130 | + case 0x0411: | |
131 | + // "bgezal zero," assembly found. Skip following block (strig). | |
132 | + pos+=code1&0x0000FFFF; | |
133 | + break; | |
134 | + case 0x0820: // FOR | |
135 | + case 0x0821: // WHILE | |
136 | + case 0x0822: // DO | |
137 | + depth++; | |
138 | + break; | |
139 | + case 0x0830: // NEXT | |
140 | + case 0x0831: // WEND | |
141 | + case 0x0832: // LOOP | |
142 | + if (0<depth) { | |
143 | + depth--; | |
144 | + break; | |
145 | + } | |
146 | + // Destination found. | |
147 | + // Previous code will be also set if required for CONTINUE statement. | |
148 | + if (prevcode) prevcode[0]=g_object[pos-1]; | |
149 | + return (void*)&g_object[pos]; | |
150 | + default: | |
151 | + break; | |
152 | + } | |
153 | + } | |
154 | + return 0; | |
155 | +} | |
156 | + | |
157 | +void* search_ifout(unsigned int start){ | |
158 | + unsigned int pos,code1,depth; | |
159 | + // Start search from start point where BREAK statement is used. | |
160 | + depth=0; | |
161 | + for(pos=start;pos<g_objpos;pos++){ | |
162 | + code1=g_object[pos]; | |
163 | + switch(code1>>16){ | |
164 | + case 0x0411: | |
165 | + // "bgezal zero," assembly found. Skip following block (strig). | |
166 | + pos+=code1&0x0000FFFF; | |
167 | + break; | |
168 | + case 0x3000: // Block marker | |
169 | + if (code1==0x30008000) { | |
170 | + // end block | |
171 | + if (0<depth) { | |
172 | + depth--; | |
173 | + break; | |
174 | + } | |
175 | + // Destination found. | |
176 | + return (void*)&g_object[pos]; | |
177 | + } else if (code1==0x30000000) { | |
178 | + // begin block | |
179 | + depth++; | |
180 | + break; | |
181 | + } else { | |
182 | + break; | |
183 | + } | |
184 | + default: | |
185 | + break; | |
186 | + } | |
187 | + } | |
188 | + return 0; | |
189 | +} | |
190 | + | |
191 | +/* | |
192 | + Following codes are dedicated to specific use: | |
193 | + 0x0411xxxx: String/data block | |
194 | + Use 0x0413xxxx (bzegall zero,xxxx) for other cases to get PC to $ra | |
195 | + 0x0810xxxx, 0x0811xxxx: GOTO statement | |
196 | + 0x0812xxxx, 0x0813xxxx: GOSUB statement | |
197 | + 0x0814xxxx, 0x0815xxxx: SOUND etc, for setting v0 as pointer to DATA array. | |
198 | + 0x0816xxxx: BREAK statemant and relatives | |
199 | + 0x08160000: BREAK | |
200 | + 0x08160008: CONTINUE | |
201 | + 0x08160100: Jump to next ELSE, ELSEIF or ENDIF | |
202 | + 0x082xyyyy: Begin block (FOR/DO/WHILE) | |
203 | + 0x083xyyyy: End block (NEXT/LOOP/WEND) | |
204 | + 0x00000020, 0x00000021, | |
205 | + 0x00000022, 0x00000023: Marker for begining the DATA region. | |
206 | + MLB 2 bits show skip byte length in DATA. | |
207 | + 0x30000000: Begin block (IF-THEN-ELSEIF-ELSE-ENDIF) | |
208 | + 0x30008000: End block (IF-THEN-ELSEIF-ELSE-ENDIF) | |
209 | + 0x3000Fxxx: General purpose NOP with value 0x0000-0x0FFF. | |
210 | + | |
211 | + IF-THEN-ELSEIF-ELSE-ENDIF is written as follows: | |
212 | + IF-THEN: 0x30000000 0x10400000 0x30000000 | |
213 | + ELSEIF-THEN: 0x08160100 0x30008000 (conditional expression) 0x10400000 0x30000000 | |
214 | + ELSE: 0x08160100 0x30008000 0x30000000 | |
215 | + ENDIF: 0x30008000 0x30008000 | |
216 | + , where "0x10400000 0x30000000" and "0x08160100 0x30008000" will be replaced by | |
217 | + codes jumping to next 0x30008000. The 0x30000000 - 0x30008000 blocks will be skipped. | |
218 | +*/ | |
219 | + | |
220 | +char* link(void){ | |
221 | + int pos; | |
222 | + unsigned int code1,code2,label; | |
223 | + g_fileline=0; | |
224 | + for(pos=0;pos<g_objpos;pos++){ | |
225 | + code1=g_object[pos]; | |
226 | + switch(code1>>16){ | |
227 | + case 0x0411: | |
228 | + // "bgezal zero," assembly found. Skip following block (strig). | |
229 | + pos+=code1&0x0000FFFF; | |
230 | + break; | |
231 | + case 0x3416: | |
232 | + // "ori s6,zero,xxxx" found this is the first word in a line. | |
233 | + g_fileline++; | |
234 | + g_line=code1&0x0000FFFF; | |
235 | + break; | |
236 | + case 0x0810: | |
237 | + // GOTO | |
238 | + code2=g_object[pos+1]; | |
239 | + if ((code2&0xFFFF0000)!=0x08110000) continue; | |
240 | + code1&=0x0000FFFF; | |
241 | + code2&=0x0000FFFF; | |
242 | + label=(code1<<16)|code2; | |
243 | + code1=(int)search_label(label); | |
244 | + g_label=label; | |
245 | + if (!code1) return ERR_LABEL_NF; | |
246 | + code1&=0x0FFFFFFF; | |
247 | + code1>>=2; | |
248 | + code1|=0x08000000; // j xxxx | |
249 | + g_object[pos++]=code1; | |
250 | + g_object[pos]=0x00000000; // nop | |
251 | + break; | |
252 | + case 0x0812: | |
253 | + // GOSUB | |
254 | + code2=g_object[pos+1]; | |
255 | + if ((code2&0xFFFF0000)!=0x08130000) continue; | |
256 | + code1&=0x0000FFFF; | |
257 | + code2&=0x0000FFFF; | |
258 | + label=(code1<<16)|code2; | |
259 | + code2=(int)search_label(label); | |
260 | + g_label=label; | |
261 | + if (!code2) return ERR_LABEL_NF; | |
262 | + code2&=0x0FFFFFFF; | |
263 | + code2>>=2; | |
264 | + code2|=0x08000000; // j xxxx | |
265 | + g_object[pos++]=0x00000000; // nop | |
266 | + g_object[pos]=code2; | |
267 | + break; | |
268 | + case 0x0814: | |
269 | + // SOUND etc, for setting v0 as pointer to label/line | |
270 | + code2=g_object[pos+1]; | |
271 | + if ((code2&0xFFFF0000)!=0x08150000) continue; | |
272 | + code1&=0x0000FFFF; | |
273 | + code2&=0x0000FFFF; | |
274 | + label=(code1<<16)|code2; | |
275 | + code1=(int)search_label(label); | |
276 | + g_label=label; | |
277 | + if (!code1) return ERR_LABEL_NF; | |
278 | + g_object[pos++]=0x3C020000|((code1>>16)&0x0000FFFF); // lui v0,xxxx | |
279 | + g_object[pos] =0x34420000|(code1&0x0000FFFF); // ori v0,v0,xxxx | |
280 | + break; | |
281 | + case 0x0816: | |
282 | + switch(code1&0xFFFF) { | |
283 | + case 0x0000: | |
284 | + // BREAK statement | |
285 | + // Find next the NEXT or WHILE statement and insert jump code after this. | |
286 | + g_label=g_line; | |
287 | + code1=(int)search_breakout(pos,0); | |
288 | + if (!code1) return ERR_INVALID_BREAK; | |
289 | + code1&=0x0FFFFFFF; | |
290 | + code1>>=2; | |
291 | + code1|=0x08000000; // j xxxx | |
292 | + g_object[pos]=code1; | |
293 | + break; | |
294 | + case 0x0008: | |
295 | + // CONTINUE statement | |
296 | + // Find next the NEXT or WHILE statement and insert jump code after this. | |
297 | + g_label=g_line; | |
298 | + code1=(int)search_breakout(pos,&g_temp); | |
299 | + if (!code1) return ERR_INVALID_BREAK; | |
300 | + if (0x3000F000 == (g_temp&0xFFFFF000)) { | |
301 | + // WEND or LOOP statement found | |
302 | + code1-=(g_temp&0x0FFF)<<2; | |
303 | + } else { | |
304 | + // NEXT statement found | |
305 | + code1-=3<<2; | |
306 | + } | |
307 | + code1&=0x0FFFFFFF; | |
308 | + code1>>=2; | |
309 | + code1|=0x08000000; // j xxxx | |
310 | + g_object[pos]=code1; | |
311 | + break; | |
312 | + case 0x0100: | |
313 | + // Jump to next ENDIF | |
314 | + g_label=g_line; | |
315 | + // "pos+2" is for skipping next code (must be 0x30008000) | |
316 | + code1=(int)search_ifout(pos+2); | |
317 | + if (!code1) return ERR_INVALID_ELSEIF; | |
318 | + code1&=0x0FFFFFFF; | |
319 | + code1>>=2; | |
320 | + code1|=0x08000000; // j xxxx | |
321 | + g_object[pos]=code1; | |
322 | + break; | |
323 | + default: | |
324 | + break; | |
325 | + } | |
326 | + break; | |
327 | + case 0x3000: | |
328 | + // Block marker | |
329 | + switch(code1&0xFFFF) { | |
330 | + case 0x0000: | |
331 | + // Begin if block | |
332 | + if (g_object[pos-1]==0x10400000) { // beq v0,zero,xxxx | |
333 | + // IF-THEN or ELSEIF-THEN | |
334 | + // Jump to next ELSE, ELSEIF or ENDIF | |
335 | + g_label=g_line; | |
336 | + // "pos+1" is for skipping current code (0x30000000) | |
337 | + code1=(int)search_ifout(pos+1); | |
338 | + if (!code1) return ERR_INVALID_ELSEIF; | |
339 | + code1-=(int)(&g_object[pos]); | |
340 | + code1>>=2; | |
341 | + code1&=0x0000FFFF; | |
342 | + code1|=0x10400000; // beq v0,zero,xxxx | |
343 | + g_object[pos-1]=code1; | |
344 | + break; | |
345 | + } | |
346 | + break; | |
347 | + default: | |
348 | + break; | |
349 | + } | |
350 | + break; | |
351 | + case 0x0820: // FOR | |
352 | + case 0x0830: // NEXT | |
353 | + case 0x0821: // WHILE | |
354 | + case 0x0831: // WEND | |
355 | + case 0x0822: // DO | |
356 | + case 0x0832: // WHILE | |
357 | + // These are used for detecing the depth of structures. | |
358 | + // Change them to stack increase/decrease commands. | |
359 | + g_object[pos]=0x27BD0000|(code1&0x0000FFFF); //// addiu sp,sp,xx | |
360 | + break; | |
361 | + case 0x2407: // addiu a3,zero,xxxx | |
362 | + if (g_object[pos-1]!=0x02E0F809) break; // jalr ra,s7 | |
363 | + // call_lib_code(x) | |
364 | + switch(code1&0x0000FFFF){ | |
365 | + case LIB_RESTORE: | |
366 | + // Convert label data to pointer if not dynamic | |
367 | + code1=g_object[pos-3]; | |
368 | + code2=g_object[pos-2]; | |
369 | + if ((code1>>16)!=0x3C02) break; // lui v0,xxxx | |
370 | + if ((code2>>16)!=0x3442) break; // ori v0,v0,xxxx | |
371 | + label=(code1<<16)|(code2&0x0000FFFF); | |
372 | + code1=(int)search_label(label); | |
373 | + g_label=label; | |
374 | + if (!code1) return ERR_LABEL_NF; | |
375 | + code2=code1&0x0000FFFF; | |
376 | + code1=code1>>16; | |
377 | + g_object[pos-3]=0x3C020000|code1; // lui v0,xxxx | |
378 | + g_object[pos-2]=0x34420000|code2; // ori v0,v0,xxxx | |
379 | + g_object[pos]=0x24070000|LIB_RESTORE2; // addiu a3,zero,xxxx | |
380 | + break; | |
381 | + default: | |
382 | + break; | |
383 | + } | |
384 | + break; | |
385 | + default: | |
386 | + break; | |
387 | + } | |
388 | + } | |
389 | + return 0; | |
390 | +} | |
\ No newline at end of file |
@@ -0,0 +1,273 @@ | ||
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 | + // All the calculations will be done in library code, lib_float function (see below). | |
217 | + call_lib_code(LIB_FLOAT | op); | |
218 | + return 0; | |
219 | +} | |
220 | + | |
221 | +int lib_float(int ia0,int iv0, enum operator a1){ | |
222 | + // This function was called from _call_library(). | |
223 | + // Variable types must be all int. | |
224 | + // Casting cannot be used. | |
225 | + // Instead, by using pointer, put as int value, get as float value, | |
226 | + // calculate, put as float value, then get as int value for returning. | |
227 | + volatile float a0,v0; | |
228 | + ((int*)(&a0))[0]=ia0; | |
229 | + ((int*)(&v0))[0]=iv0; | |
230 | + switch(a1){ | |
231 | + case OP_EQ: | |
232 | + v0= a0==v0?1:0; | |
233 | + break; | |
234 | + case OP_NEQ: | |
235 | + v0= a0!=v0?1:0; | |
236 | + break; | |
237 | + case OP_LT: | |
238 | + v0= a0<v0?1:0; | |
239 | + break; | |
240 | + case OP_LTE: | |
241 | + v0= a0<=v0?1:0; | |
242 | + break; | |
243 | + case OP_MT: | |
244 | + v0= a0>v0?1:0; | |
245 | + break; | |
246 | + case OP_MTE: | |
247 | + v0= a0>=v0?1:0; | |
248 | + break; | |
249 | + case OP_ADD: | |
250 | + v0= a0+v0; | |
251 | + break; | |
252 | + case OP_SUB: | |
253 | + v0= a0-v0; | |
254 | + break; | |
255 | + case OP_MUL: | |
256 | + v0= a0*v0; | |
257 | + break; | |
258 | + case OP_DIV: | |
259 | + if (v0==0) err_div_zero(); | |
260 | + v0= a0/v0; | |
261 | + break; | |
262 | + case OP_OR: | |
263 | + v0= a0||v0?1:0; | |
264 | + break; | |
265 | + case OP_AND: | |
266 | + v0= a0&&v0?1:0; | |
267 | + break; | |
268 | + default: | |
269 | + err_unknown(); | |
270 | + return 0; | |
271 | + } | |
272 | + return ((int*)(&v0))[0]; | |
273 | +}; | |
\ No newline at end of file |
@@ -0,0 +1,2357 @@ | ||
1 | +// sdfsio370f.h | |
2 | +// PIC32MX370F512HでSPI2接続されたSDカードにアクセスする | |
3 | +// sdfsio370fLib.aを利用するためのヘッダーファイル | |
4 | +// FSIO.h,FSconfig.h,FSDefs.hから抜粋 by K.Tanaka | |
5 | +// | |
6 | +// サポート | |
7 | +// FAT32,書き込み,ファイルサーチ,Dir | |
8 | +// 未サポート | |
9 | +// LongFileName,FSfprintf,format,FSGetDiskProperties | |
10 | +// 同時オープン数 3 | |
11 | + | |
12 | +/****************************************************************************** | |
13 | + * | |
14 | + * Microchip Memory Disk Drive File System | |
15 | + * | |
16 | + ****************************************************************************** | |
17 | + * FileName: FSIO.h | |
18 | + * Dependencies: GenericTypeDefs.h | |
19 | + * FSconfig.h | |
20 | + * FSDefs.h | |
21 | + * stddef.h | |
22 | + * Processor: PIC18/PIC24/dsPIC30/dsPIC33/PIC32 | |
23 | + * Compiler: C18/C30/C32 | |
24 | + * Company: Microchip Technology, Inc. | |
25 | + * Version: 1.3.0 | |
26 | + * | |
27 | + * Software License Agreement | |
28 | + * | |
29 | + * The software supplied herewith by Microchip Technology Incorporated | |
30 | + * (the 鼎ompany・ for its PICmicroョ Microcontroller is intended and | |
31 | + * supplied to you, the Company痴 customer, for use solely and | |
32 | + * exclusively on Microchip PICmicro Microcontroller products. The | |
33 | + * software is owned by the Company and/or its supplier, and is | |
34 | + * protected under applicable copyright laws. All rights are reserved. | |
35 | + * Any use in violation of the foregoing restrictions may subject the | |
36 | + * user to criminal sanctions under applicable laws, as well as to | |
37 | + * civil liability for the breach of the terms and conditions of this | |
38 | + * license. | |
39 | + * | |
40 | + * THIS SOFTWARE IS PROVIDED IN AN 鄭S IS・CONDITION. NO WARRANTIES, | |
41 | + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED | |
42 | + * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | |
43 | + * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, | |
44 | + * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR | |
45 | + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. | |
46 | + * | |
47 | +*****************************************************************************/ | |
48 | + | |
49 | +#ifndef FS_DOT_H | |
50 | +#define FS_DOT_H | |
51 | + | |
52 | +#define MDD_MediaInitialize MDD_SDSPI_MediaInitialize | |
53 | +#define MDD_MediaDetect MDD_SDSPI_MediaDetect | |
54 | +#define MDD_SectorRead MDD_SDSPI_SectorRead | |
55 | +#define MDD_SectorWrite MDD_SDSPI_SectorWrite | |
56 | +#define MDD_InitIO MDD_SDSPI_InitIO | |
57 | +#define MDD_ShutdownMedia MDD_SDSPI_ShutdownMedia | |
58 | +#define MDD_WriteProtectState MDD_SDSPI_WriteProtectState | |
59 | + | |
60 | +#define ALLOW_FILESEARCH | |
61 | +#define ALLOW_WRITES | |
62 | +#define ALLOW_DIRS | |
63 | +#define SUPPORT_FAT32 | |
64 | + | |
65 | +// Summary: An enumeration used for various error codes. | |
66 | +// Description: The CETYPE enumeration is used to indicate different error conditions during device operation. | |
67 | +typedef enum _CETYPE | |
68 | +{ | |
69 | + CE_GOOD = 0, // No error | |
70 | + CE_ERASE_FAIL, // An erase failed | |
71 | + CE_NOT_PRESENT, // No device was present | |
72 | + CE_NOT_FORMATTED, // The disk is of an unsupported format | |
73 | + CE_BAD_PARTITION, // The boot record is bad | |
74 | + CE_UNSUPPORTED_FS, // The file system type is unsupported | |
75 | + CE_INIT_ERROR, // An initialization error has occured | |
76 | + CE_NOT_INIT, // An operation was performed on an uninitialized device | |
77 | + CE_BAD_SECTOR_READ, // A bad read of a sector occured | |
78 | + CE_WRITE_ERROR, // Could not write to a sector | |
79 | + CE_INVALID_CLUSTER, // Invalid cluster value > maxcls | |
80 | + CE_FILE_NOT_FOUND, // Could not find the file on the device | |
81 | + CE_DIR_NOT_FOUND, // Could not find the directory | |
82 | + CE_BAD_FILE, // File is corrupted | |
83 | + CE_DONE, // No more files in this directory | |
84 | + CE_COULD_NOT_GET_CLUSTER, // Could not load/allocate next cluster in file | |
85 | + CE_FILENAME_2_LONG, // A specified file name is too long to use | |
86 | + CE_FILENAME_EXISTS, // A specified filename already exists on the device | |
87 | + CE_INVALID_FILENAME, // Invalid file name | |
88 | + CE_DELETE_DIR, // The user tried to delete a directory with FSremove | |
89 | + CE_DIR_FULL, // All root dir entry are taken | |
90 | + CE_DISK_FULL, // All clusters in partition are taken | |
91 | + CE_DIR_NOT_EMPTY, // This directory is not empty yet, remove files before deleting | |
92 | + CE_NONSUPPORTED_SIZE, // The disk is too big to format as FAT16 | |
93 | + CE_WRITE_PROTECTED, // Card is write protected | |
94 | + CE_FILENOTOPENED, // File not opened for the write | |
95 | + CE_SEEK_ERROR, // File location could not be changed successfully | |
96 | + CE_BADCACHEREAD, // Bad cache read | |
97 | + CE_CARDFAT32, // FAT 32 - card not supported | |
98 | + CE_READONLY, // The file is read-only | |
99 | + CE_WRITEONLY, // The file is write-only | |
100 | + CE_INVALID_ARGUMENT, // Invalid argument | |
101 | + CE_TOO_MANY_FILES_OPEN, // Too many files are already open | |
102 | + CE_UNSUPPORTED_SECTOR_SIZE // Unsupported sector size | |
103 | +} CETYPE; | |
104 | + | |
105 | + | |
106 | +// Summary: A macro indicating a dir entry was found | |
107 | +// Description: The FOUND macro indicates that a directory entry was found in the specified position | |
108 | +#define FOUND 0 | |
109 | + | |
110 | +// Summary: A macro indicating no dir entry was found | |
111 | +// Description: The NOT_FOUND macro indicates that the specified directory entry to load was deleted | |
112 | +#define NOT_FOUND 1 | |
113 | + | |
114 | +// Summary: A macro indicating that no more files were found | |
115 | +// Description: The NO_MORE macro indicates that there are no more directory entries to search for | |
116 | +#define NO_MORE 2 | |
117 | + | |
118 | + | |
119 | + | |
120 | +// Summary: A macro indicating the device is formatted with FAT12 | |
121 | +// Description: The FAT12 macro is used to indicate that the file system on the device being accessed is a FAT12 file system. | |
122 | +#define FAT12 1 | |
123 | + | |
124 | +// Summary: A macro indicating the device is formatted with FAT16 | |
125 | +// Description: The FAT16 macro is used to indicate that the file system on the device being accessed is a FAT16 file system. | |
126 | +#define FAT16 2 | |
127 | + | |
128 | +// Summary: A macro indicating the device is formatted with FAT32 | |
129 | +// Description: The FAT32 macro is used to indicate that the file system on the device being accessed is a FAT32 file system. | |
130 | +#define FAT32 3 | |
131 | + | |
132 | + | |
133 | + | |
134 | +// Summary: A read-only attribute macro | |
135 | +// Description: A macro for the read-only attribute. A file with this attribute should not be written to. Note that this | |
136 | +// attribute will not actually prevent a write to the file; that functionality is operating-system dependant. The | |
137 | +// user should take care not to write to a read-only file. | |
138 | +#define ATTR_READ_ONLY 0x01 | |
139 | + | |
140 | +// Summary: A hidden attribute macro | |
141 | +// Description: A macro for the hidden attribute. A file with this attribute may be hidden from the user, depending on the | |
142 | +// implementation of the operating system. | |
143 | +#define ATTR_HIDDEN 0x02 | |
144 | + | |
145 | +// Summary: A system attribute macro | |
146 | +// Description: A macro for the system attribute. A file with this attribute is used by the operating system, and should not be | |
147 | +// modified. Note that this attribute will not actually prevent a write to the file. | |
148 | +#define ATTR_SYSTEM 0x04 | |
149 | + | |
150 | +// Summary: A volume attribute macro | |
151 | +// Description: A macro for the volume attribute. If the first directory entry in the root directory has the volume attribute set, | |
152 | +// the device will use the name in that directory entry as the volume name. | |
153 | +#define ATTR_VOLUME 0x08 | |
154 | + | |
155 | +// Summary: A macro for the attributes for a long-file name entry | |
156 | +// Description: A macro for the long-name attributes. If a directory entry is used in a long-file name implementation, it will have | |
157 | +// all four lower bits set. This indicates that any software that does not support long file names should ignore that | |
158 | +// entry. | |
159 | +#define ATTR_LONG_NAME 0x0f | |
160 | + | |
161 | +// Summary: A directory attribute macro | |
162 | +// Description: A macro for the directory attribute. If a directory entry has this attribute set, the file it points to is a directory- | |
163 | +// type file, and will contain directory entries that point to additional directories or files. | |
164 | +#define ATTR_DIRECTORY 0x10 | |
165 | + | |
166 | +// Summary: An archive attribute macro | |
167 | +// Description: A macro for the archive attribute. This attribute will indicate to some archiving programs that the file with this | |
168 | +// attribute needs to be backed up. Most operating systems create files with the archive attribute set. | |
169 | +#define ATTR_ARCHIVE 0x20 | |
170 | + | |
171 | +// Summary: A macro for all attributes | |
172 | +// Description: A macro for all attributes. The search functions in this library require an argument that determines which attributes | |
173 | +// 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 | |
174 | +// of its attributes. | |
175 | +#define ATTR_MASK 0x3f | |
176 | + | |
177 | + | |
178 | + | |
179 | +// Summary: A macro to indicate an empty FAT entry | |
180 | +// Description: The CLUSTER_EMPTY value is used to indicate that a FAT entry and it's corresponding cluster are available. | |
181 | +#define CLUSTER_EMPTY 0x0000 | |
182 | + | |
183 | +// Summary: A macro to indicate the last cluster value for FAT12 | |
184 | +// Description: The LAST_CLUSTER_FAT12 macro is used when reading the FAT to indicate that the next FAT12 entry for a file contains | |
185 | +// the end-of-file value. | |
186 | +#define LAST_CLUSTER_FAT12 0xff8 | |
187 | + | |
188 | +// Summary: A macro to indicate the last cluster value for FAT16 | |
189 | +// Description: The LAST_CLUSTER_FAT16 macro is used when reading the FAT to indicate that the next FAT16 entry for a file contains | |
190 | +// the end-of-file value. | |
191 | +#define LAST_CLUSTER_FAT16 0xfff8 | |
192 | + | |
193 | +// Summary: A macro to indicate the last allocatable cluster for FAT12 | |
194 | +// Description: The END_CLUSTER_FAT12 value is used as a comparison in FAT12 to determine that the firmware has reached the end of | |
195 | +// the range of allowed allocatable clusters. | |
196 | +#define END_CLUSTER_FAT12 0xFF7 | |
197 | + | |
198 | +// Summary: A macro to indicate the last allocatable cluster for FAT16 | |
199 | +// Description: The END_CLUSTER_FAT16 value is used as a comparison in FAT16 to determine that the firmware has reached the end of | |
200 | +// the range of allowed allocatable clusters. | |
201 | +#define END_CLUSTER_FAT16 0xFFF7 | |
202 | + | |
203 | +// Summary: A macro to indicate the failure of the ReadFAT function | |
204 | +// Description: The CLUSTER_FAIL_FAT16 macro is used by the ReadFAT function to indicate that an error occured reading a FAT12 or FAT16 | |
205 | +// file allocation table. Note that since '0xFFF8' is used for the last cluster return value in the FAT16 implementation | |
206 | +// the end-of-file value '0xFFFF' can be used to indicate an error condition. | |
207 | +#define CLUSTER_FAIL_FAT16 0xFFFF | |
208 | + | |
209 | + | |
210 | + | |
211 | +#ifdef SUPPORT_FAT32 | |
212 | + // Summary: A macro to indicate the last cluster value for FAT32 | |
213 | + // Description: The LAST_CLUSTER_FAT32 macro is used when reading the FAT to indicate that the next FAT32 entry for a file contains | |
214 | + // the end-of-file value. | |
215 | + #define LAST_CLUSTER_FAT32 0x0FFFFFF8 | |
216 | + | |
217 | + // Summary: A macro to indicate the last allocatable cluster for FAT32 | |
218 | + // Description: The END_CLUSTER_FAT32 value is used as a comparison in FAT32 to determine that the firmware has reached the end of | |
219 | + // the range of allowed allocatable clusters. | |
220 | + #define END_CLUSTER_FAT32 0x0FFFFFF7 | |
221 | + | |
222 | + // Summary: A macro to indicate the failure of the ReadFAT function | |
223 | + // Description: The CLUSTER_FAIL_FAT32 macro is used by the ReadFAT function to indicate that an error occured reading a FAT32 | |
224 | + // file allocation able. | |
225 | + #define CLUSTER_FAIL_FAT32 0x0FFFFFFF | |
226 | + | |
227 | +#endif | |
228 | + | |
229 | +// Summary: A macro indicating the number of bytes in a directory entry. | |
230 | +// Description: The NUMBER_OF_BYTES_IN_DIR_ENTRY macro represents the number of bytes in one directory entry. It is used to calculate | |
231 | +// the number of sectors in the root directory based on information in the boot sector. | |
232 | +#define NUMBER_OF_BYTES_IN_DIR_ENTRY 32 | |
233 | + | |
234 | + | |
235 | + | |
236 | +// Summary: A macro for a deleted dir entry marker. | |
237 | +// Description: The DIR_DEL macro is used to mark a directory entry as deleted. When a file is deleted, this value will replace the | |
238 | +// first character in the file name, and will indicate that the file the entry points to was deleted. | |
239 | +#define DIR_DEL 0xE5 | |
240 | + | |
241 | +// Summary: A macro for the last dir entry marker. | |
242 | +// 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 | |
243 | +// deleted entries start with the DIR_DEL character, a 0 will mark the end of the in-use or previously used group of | |
244 | +// entries in a directory | |
245 | +#define DIR_EMPTY 0 | |
246 | + | |
247 | + | |
248 | + | |
249 | +// Summary: A macro used to indicate the length of an 8.3 file name | |
250 | +// Description: The DIR_NAMESIZE macro is used when validing the name portion of 8.3 filenames | |
251 | +#define DIR_NAMESIZE 8 | |
252 | + | |
253 | +// Summary: A macro used to indicate the length of an 8.3 file extension | |
254 | +// Description: The DIR_EXTENSION macro is used when validating the extension portion of 8.3 filenames | |
255 | +#define DIR_EXTENSION 3 | |
256 | + | |
257 | +// Summary: A macro used to indicate the length of an 8.3 file name and extension | |
258 | +// Description: The DIR_NAMECOMP macro is used when validating 8.3 filenames | |
259 | +#define DIR_NAMECOMP (DIR_NAMESIZE+DIR_EXTENSION) | |
260 | + | |
261 | + | |
262 | + | |
263 | +// Summary: A macro to write a byte to RAM | |
264 | +// Description: The RAMwrite macro is used to write a byte of data to a RAM array | |
265 | +#define RAMwrite( a, f, d) *(a+f) = d | |
266 | + | |
267 | +// Summary: A macro to read a byte from RAM | |
268 | +// Description: The RAMread macro is used to read a byte of data from a RAM array | |
269 | +#define RAMread( a, f) *(a+f) | |
270 | + | |
271 | +// Summary: A macro to read a 16-bit word from RAM | |
272 | +// Description: The RAMreadW macro is used to read two bytes of data from a RAM array | |
273 | +#define RAMreadW( a, f) *(WORD *)(a+f) | |
274 | + | |
275 | +// Summary: A macro to read a 32-bit word from RAM | |
276 | +// Description: The RAMreadD macro is used to read four bytes of data from a RAM array | |
277 | +#define RAMreadD( a, f) *(DWORD *)(a+f) | |
278 | + | |
279 | + | |
280 | + | |
281 | +#ifndef EOF | |
282 | + // Summary: Indicates error conditions or end-of-file conditions | |
283 | + // Description: The EOF macro is used to indicate error conditions in some function calls. It is also used to indicate | |
284 | + // that the end-of-file has been reached. | |
285 | + #define EOF ((int)-1) | |
286 | +#endif | |
287 | + | |
288 | + | |
289 | + | |
290 | +// Summary: A structure containing information about the device. | |
291 | +// Description: The DISK structure contains information about the device being accessed. | |
292 | +typedef struct | |
293 | +{ | |
294 | + BYTE * buffer; // Address of the global data buffer used to read and write file information | |
295 | + DWORD firsts; // Logical block address of the first sector of the FAT partition on the device | |
296 | + DWORD fat; // Logical block address of the FAT | |
297 | + DWORD root; // Logical block address of the root directory | |
298 | + DWORD data; // Logical block address of the data section of the device. | |
299 | + WORD maxroot; // The maximum number of entries in the root directory. | |
300 | + DWORD maxcls; // The maximum number of clusters in the partition. | |
301 | + DWORD sectorSize; // The size of a sector in bytes | |
302 | + DWORD fatsize; // The number of sectors in the FAT | |
303 | + BYTE fatcopy; // The number of copies of the FAT in the partition | |
304 | + BYTE SecPerClus; // The number of sectors per cluster in the data region | |
305 | + BYTE type; // The file system type of the partition (FAT12, FAT16 or FAT32) | |
306 | + BYTE mount; // Device mount flag (TRUE if disk was mounted successfully, FALSE otherwise) | |
307 | +#if defined __PIC32MX__ || defined __C30__ | |
308 | +} __attribute__ ((packed)) DISK; | |
309 | +#else | |
310 | +} DISK; | |
311 | +#endif | |
312 | + | |
313 | + | |
314 | +#ifdef __18CXX | |
315 | + // Summary: A 24-bit data type | |
316 | + // Description: The SWORD macro is used to defined a 24-bit data type. For 16+ bit architectures, this must be represented as | |
317 | + // an array of three bytes. | |
318 | + typedef unsigned short long SWORD; | |
319 | +#else | |
320 | + // Summary: A 24-bit data type | |
321 | + // Description: The SWORD macro is used to defined a 24-bit data type. For 16+ bit architectures, this must be represented as | |
322 | + // an array of three bytes. | |
323 | + typedef struct | |
324 | + { | |
325 | + unsigned char array[3]; | |
326 | +#if defined __PIC32MX__ || defined __C30__ | |
327 | + } __attribute__ ((packed)) SWORD; | |
328 | +#else | |
329 | + } SWORD; | |
330 | +#endif | |
331 | +#endif | |
332 | + | |
333 | + | |
334 | + | |
335 | +// Summary: A structure containing the bios parameter block for a FAT12 file system (in the boot sector) | |
336 | +// Description: The _BPB_FAT12 structure provides a layout of the "bios parameter block" in the boot sector of a FAT12 partition. | |
337 | +typedef struct { | |
338 | + SWORD BootSec_JumpCmd; // Jump Command | |
339 | + BYTE BootSec_OEMName[8]; // OEM name | |
340 | + WORD BootSec_BPS; // Number of bytes per sector | |
341 | + BYTE BootSec_SPC; // Number of sectors per cluster | |
342 | + WORD BootSec_ResrvSec; // Number of reserved sectors at the beginning of the partition | |
343 | + BYTE BootSec_FATCount; // Number of FATs on the partition | |
344 | + WORD BootSec_RootDirEnts; // Number of root directory entries | |
345 | + WORD BootSec_TotSec16; // Total number of sectors | |
346 | + BYTE BootSec_MDesc; // Media descriptor | |
347 | + WORD BootSec_SPF; // Number of sectors per FAT | |
348 | + WORD BootSec_SPT; // Number of sectors per track | |
349 | + WORD BootSec_HeadCnt; // Number of heads | |
350 | + DWORD BootSec_HiddenSecCnt; // Number of hidden sectors | |
351 | + DWORD BootSec_Reserved; // Reserved space | |
352 | + BYTE BootSec_DriveNum; // Drive number | |
353 | + BYTE BootSec_Reserved2; // Reserved space | |
354 | + BYTE BootSec_BootSig; // Boot signature - equal to 0x29 | |
355 | + BYTE BootSec_VolID[4]; // Volume ID | |
356 | + BYTE BootSec_VolLabel[11]; // Volume Label | |
357 | + BYTE BootSec_FSType[8]; // File system type in ASCII. Not used for determination | |
358 | +#if defined __PIC32MX__ || defined __C30__ | |
359 | + } __attribute__ ((packed)) _BPB_FAT12; | |
360 | +#else | |
361 | + } _BPB_FAT12; | |
362 | +#endif | |
363 | + | |
364 | +// Summary: A structure containing the bios parameter block for a FAT16 file system (in the boot sector) | |
365 | +// Description: The _BPB_FAT16 structure provides a layout of the "bios parameter block" in the boot sector of a FAT16 partition. | |
366 | +typedef struct { | |
367 | + SWORD BootSec_JumpCmd; // Jump Command | |
368 | + BYTE BootSec_OEMName[8]; // OEM name | |
369 | + WORD BootSec_BPS; // Number of bytes per sector | |
370 | + BYTE BootSec_SPC; // Number of sectors per cluster | |
371 | + WORD BootSec_ResrvSec; // Number of reserved sectors at the beginning of the partition | |
372 | + BYTE BootSec_FATCount; // Number of FATs on the partition | |
373 | + WORD BootSec_RootDirEnts; // Number of root directory entries | |
374 | + WORD BootSec_TotSec16; // Total number of sectors | |
375 | + BYTE BootSec_MDesc; // Media descriptor | |
376 | + WORD BootSec_SPF; // Number of sectors per FAT | |
377 | + WORD BootSec_SPT; // Number of sectors per track | |
378 | + WORD BootSec_HeadCnt; // Number of heads | |
379 | + DWORD BootSec_HiddenSecCnt; // Number of hidden sectors | |
380 | + DWORD BootSec_TotSec32; // Total sector count (32 bits) | |
381 | + BYTE BootSec_DriveNum; // Drive number | |
382 | + BYTE BootSec_Reserved; // Reserved space | |
383 | + BYTE BootSec_BootSig; // Boot signature - equal to 0x29 | |
384 | + BYTE BootSec_VolID[4]; // Volume ID | |
385 | + BYTE BootSec_VolLabel[11]; // Volume Label | |
386 | + BYTE BootSec_FSType[8]; // File system type in ASCII. Not used for determination | |
387 | +#if defined __PIC32MX__ || defined __C30__ | |
388 | + } __attribute__ ((packed)) _BPB_FAT16; | |
389 | +#else | |
390 | + } _BPB_FAT16; | |
391 | +#endif | |
392 | + | |
393 | +// Summary: A structure containing the bios parameter block for a FAT32 file system (in the boot sector) | |
394 | +// Description: The _BPB_FAT32 structure provides a layout of the "bios parameter block" in the boot sector of a FAT32 partition. | |
395 | +typedef struct { | |
396 | + SWORD BootSec_jmpBoot; // Jump Command | |
397 | + BYTE BootSec_OEMName[8]; // OEM name | |
398 | + WORD BootSec_BytsPerSec; // Number of bytes per sector | |
399 | + BYTE BootSec_SecPerClus; // Number of sectors per cluster | |
400 | + WORD BootSec_RsvdSecCnt; // Number of reserved sectors at the beginning of the partition | |
401 | + BYTE BootSec_NumFATs; // Number of FATs on the partition | |
402 | + WORD BootSec_RootEntCnt; // Number of root directory entries | |
403 | + WORD BootSec_TotSec16; // Total number of sectors | |
404 | + BYTE BootSec_Media; // Media descriptor | |
405 | + WORD BootSec_FATSz16; // Number of sectors per FAT | |
406 | + WORD BootSec_SecPerTrk; // Number of sectors per track | |
407 | + WORD BootSec_NumHeads; // Number of heads | |
408 | + DWORD BootSec_HiddSec; // Number of hidden sectors | |
409 | + DWORD BootSec_TotSec32; // Total sector count (32 bits) | |
410 | + DWORD BootSec_FATSz32; // Sectors per FAT (32 bits) | |
411 | + WORD BootSec_ExtFlags; // Presently active FAT. Defined by bits 0-3 if bit 7 is 1. | |
412 | + WORD BootSec_FSVers; // FAT32 filesystem version. Should be 0:0 | |
413 | + DWORD BootSec_RootClus; // Start cluster of the root directory (should be 2) | |
414 | + WORD BootSec_FSInfo; // File system information | |
415 | + WORD BootSec_BkBootSec; // Backup boot sector address. | |
416 | + BYTE BootSec_Reserved[12]; // Reserved space | |
417 | + BYTE BootSec_DrvNum; // Drive number | |
418 | + BYTE BootSec_Reserved1; // Reserved space | |
419 | + BYTE BootSec_BootSig; // Boot signature - 0x29 | |
420 | + BYTE BootSec_VolID[4]; // Volume ID | |
421 | + BYTE BootSec_VolLab[11]; // Volume Label | |
422 | + BYTE BootSec_FilSysType[8]; // File system type in ASCII. Not used for determination | |
423 | +#if defined __PIC32MX__ || defined __C30__ | |
424 | + } __attribute__ ((packed)) _BPB_FAT32; | |
425 | +#else | |
426 | + } _BPB_FAT32; | |
427 | +#endif | |
428 | + | |
429 | + | |
430 | +// Description: A macro for the boot sector bytes per sector value offset | |
431 | +#define BSI_BPS 11 | |
432 | + | |
433 | +// Description: A macro for the boot sector sector per cluster value offset | |
434 | +#define BSI_SPC 13 | |
435 | + | |
436 | +// Description: A macro for the boot sector reserved sector count value offset | |
437 | +#define BSI_RESRVSEC 14 | |
438 | + | |
439 | +// Description: A macro for the boot sector FAT count value offset | |
440 | +#define BSI_FATCOUNT 16 | |
441 | + | |
442 | +// Description: A macro for the boot sector root directory entry count value offset | |
443 | +#define BSI_ROOTDIRENTS 17 | |
444 | + | |
445 | +// Description: A macro for the boot sector 16-bit total sector count value offset | |
446 | +#define BSI_TOTSEC16 19 | |
447 | + | |
448 | +// Description: A macro for the boot sector sectors per FAT value offset | |
449 | +#define BSI_SPF 22 | |
450 | + | |
451 | +// Description: A macro for the boot sector 32-bit total sector count value offset | |
452 | +#define BSI_TOTSEC32 32 | |
453 | + | |
454 | +// Description: A macro for the boot sector boot signature offset | |
455 | +#define BSI_BOOTSIG 38 | |
456 | + | |
457 | +// Description: A macro for the boot sector file system type string offset | |
458 | +#define BSI_FSTYPE 54 | |
459 | + | |
460 | +// Description: A macro for the boot sector 32-bit sector per FAT value offset | |
461 | +#define BSI_FATSZ32 36 | |
462 | + | |
463 | +// Description: A macro for the boot sector start cluster of root directory value offset | |
464 | +#define BSI_ROOTCLUS 44 | |
465 | + | |
466 | +// Description: A macro for the FAT32 boot sector boot signature offset | |
467 | +#define BSI_FAT32_BOOTSIG 66 | |
468 | + | |
469 | +// Description: A macro for the FAT32 boot sector file system type string offset | |
470 | +#define BSI_FAT32_FSTYPE 82 | |
471 | + | |
472 | + | |
473 | + | |
474 | +// Summary: A partition table entry structure. | |
475 | +// Description: The PTE_MBR structure contains values found in a partition table entry in the MBR of a device. | |
476 | +typedef struct | |
477 | +{ | |
478 | + BYTE PTE_BootDes; // The boot descriptor (should be 0x00 in a non-bootable device) | |
479 | + SWORD PTE_FrstPartSect; // The cylinder-head-sector address of the first sector of the partition | |
480 | + BYTE PTE_FSDesc; // The file system descriptor | |
481 | + SWORD PTE_LstPartSect; // The cylinder-head-sector address of the last sector of the partition | |
482 | + DWORD PTE_FrstSect; // The logical block address of the first sector of the partition | |
483 | + DWORD PTE_NumSect; // The number of sectors in a partition | |
484 | +#if defined __PIC32MX__ || defined __C30__ | |
485 | + } __attribute__ ((packed)) PTE_MBR; | |
486 | +#else | |
487 | + } PTE_MBR; | |
488 | +#endif | |
489 | + | |
490 | + | |
491 | +// Summary: A structure of the organization of a master boot record. | |
492 | +// Description: The _PT_MBR structure has the same form as a master boot record. When the MBR is loaded from the device, it will | |
493 | +// be cast as a _PT_MBR structure so the MBR elements can be accessed. | |
494 | +typedef struct | |
495 | +{ | |
496 | + BYTE ConsChkRtn[446]; // Boot code | |
497 | + PTE_MBR Partition0; // The first partition table entry | |
498 | + PTE_MBR Partition1; // The second partition table entry | |
499 | + PTE_MBR Partition2; // The third partition table entry | |
500 | + PTE_MBR Partition3; // The fourth partition table entry | |
501 | + BYTE Signature0; // MBR signature code - equal to 0x55 | |
502 | + BYTE Signature1; // MBR signature code - equal to 0xAA | |
503 | +#if defined __PIC32MX__ || defined __C30__ | |
504 | +}__attribute__((packed)) _PT_MBR; | |
505 | +#else | |
506 | +}_PT_MBR; | |
507 | +#endif | |
508 | + | |
509 | +// Summary: A pointer to a _PT_MBR structure | |
510 | +// Description: The PT_MBR pointer points to a _PT_MBR structure. | |
511 | +typedef _PT_MBR * PT_MBR; | |
512 | + | |
513 | + | |
514 | + | |
515 | +// Summary: A structure of the organization of a boot sector. | |
516 | +// Description: The _BootSec structure has the same form as a boot sector. When the boot sector is loaded from the device, it will | |
517 | +// be cast as a _BootSec structure so the boot sector elements can be accessed. | |
518 | +typedef struct | |
519 | +{ | |
520 | + // A union of different bios parameter blocks | |
521 | + union | |
522 | + { | |
523 | + _BPB_FAT32 FAT_32; | |
524 | + _BPB_FAT16 FAT_16; | |
525 | + _BPB_FAT12 FAT_12; | |
526 | + }FAT; | |
527 | + BYTE Reserved[512-sizeof(_BPB_FAT32)-2]; // Reserved space | |
528 | + BYTE Signature0; // Boot sector signature code - equal to 0x55 | |
529 | + BYTE Signature1; // Boot sector signature code - equal to 0xAA | |
530 | +#if defined __PIC32MX__ || defined __C30__ | |
531 | + } __attribute__ ((packed)) _BootSec; | |
532 | +#else | |
533 | + } _BootSec; | |
534 | +#endif | |
535 | + | |
536 | +// Summary: A pointer to a _BootSec structure | |
537 | +// Description: The BootSec pointer points to a _BootSec structure. | |
538 | +typedef _BootSec * BootSec; | |
539 | + | |
540 | + | |
541 | + | |
542 | +// Summary: A macro indicating the offset for the master boot record | |
543 | +// Description: FO_MBR is a macro that indicates the addresss of the master boot record on the device. When the device is initialized | |
544 | +// this sector will be read | |
545 | +#define FO_MBR 0L | |
546 | + | |
547 | + | |
548 | + | |
549 | +// Summary: A macro for the first boot sector/MBR signature byte | |
550 | +// 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 | |
551 | +#define FAT_GOOD_SIGN_0 0x55 | |
552 | + | |
553 | +// Summary: A macro for the second boot sector/MBR signature byte | |
554 | +// 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 | |
555 | +#define FAT_GOOD_SIGN_1 0xAA | |
556 | + | |
557 | + | |
558 | +typedef struct | |
559 | +{ | |
560 | + BYTE errorCode; | |
561 | + union | |
562 | + { | |
563 | + BYTE value; | |
564 | + struct | |
565 | + { | |
566 | + BYTE sectorSize : 1; | |
567 | + BYTE maxLUN : 1; | |
568 | + } bits; | |
569 | + } validityFlags; | |
570 | + | |
571 | + WORD sectorSize; | |
572 | + BYTE maxLUN; | |
573 | +} MEDIA_INFORMATION; | |
574 | + | |
575 | +typedef enum | |
576 | +{ | |
577 | + MEDIA_NO_ERROR, // No errors | |
578 | + MEDIA_DEVICE_NOT_PRESENT, // The requested device is not present | |
579 | + MEDIA_CANNOT_INITIALIZE // Cannot initialize media | |
580 | +} MEDIA_ERRORS; | |
581 | + | |
582 | + | |
583 | + | |
584 | + | |
585 | +/*******************************************************************/ | |
586 | +/* Strunctures and defines */ | |
587 | +/*******************************************************************/ | |
588 | + | |
589 | +#ifndef FALSE | |
590 | + // Summary: False value | |
591 | + // Description: This macro will indicate that a condition is false. | |
592 | + #define FALSE 0 | |
593 | +#endif | |
594 | +#ifndef TRUE | |
595 | + // Summary: True value | |
596 | + // Description: This macro will indicate that a condition is true. | |
597 | + #define TRUE !FALSE // True value | |
598 | +#endif | |
599 | + | |
600 | + | |
601 | + | |
602 | + | |
603 | +#ifndef SEEK_SET | |
604 | + // Summary: Macro for the FSfseek SEEK_SET base location. | |
605 | + // Description: Functions as an input for FSfseek that specifies that the position in the file will be changed | |
606 | + // relative to the beginning of the file. | |
607 | + #define SEEK_SET 0 | |
608 | + | |
609 | +#endif | |
610 | +#ifndef SEEK_CUR | |
611 | + | |
612 | + // Summary: Macro for the FSfseek SEEK_CUR base location. | |
613 | + // Description: Functions as an input for FSfseek that specifies that the position in the file will be changed | |
614 | + // relative to the current location of the file | |
615 | + #define SEEK_CUR 1 | |
616 | + | |
617 | +#endif | |
618 | +#ifndef SEEK_END | |
619 | + | |
620 | + // Summary: Macro for the FSfseek SEEK_END base location | |
621 | + // Description: Functions as an input for FSfseek that specifies that the position in the file will be changed | |
622 | + // relative to the end of the file. For this macro, the offset value will be subtracted from | |
623 | + // the end location of the file by default. | |
624 | + #define SEEK_END 2 | |
625 | + | |
626 | +#endif | |
627 | + | |
628 | + | |
629 | + | |
630 | + | |
631 | +// Summary: Macro for the FSfopen FS_APPEND mode | |
632 | +// Description: If this macro is specified as the mode argument in a call of FSfopen, the file being opened will | |
633 | +// be created if it doesn't exist. If it does exist, it's file information will be loaded and the | |
634 | +// current location in the file will be set to the end. The user will then be able to write to the file. | |
635 | +#define FS_APPEND "a" | |
636 | +#define APPEND "a" //deprecated | |
637 | + | |
638 | +// Summary: Macro for the FSfopen FS_WRITE mode | |
639 | +// Description: If this macro is specified as the mode argument in a call of FSfopen, the file being opened will | |
640 | +// be created if it doesn't exist. If it does exist, it will be erased and replaced by an empty file | |
641 | +// of the same name. The user will then be able to write to the file. | |
642 | +#define FS_WRITE "w" | |
643 | +#define WRITE "w" //deprecated | |
644 | + | |
645 | +// Summary: Macro for the FSfopen FS_READ mode | |
646 | +// Description: If this macro is specified as the mode argument in a call of FSfopen, the file information for the | |
647 | +// specified file will be loaded. If the file does not exist, the FSfopen function will fail. The user | |
648 | +// will then be able to read from the file. | |
649 | +#define FS_READ "r" | |
650 | +#if defined(__32MX795F512L__) | |
651 | + #warning FSfopen must use "r" and not READ as input on this device | |
652 | +#else | |
653 | + #define READ "r" //deprecated | |
654 | +#endif | |
655 | + | |
656 | +// Summary: Macro for the FSfopen FS_APPEND+ mode | |
657 | +// Description: If this macro is specified as the mode argument in a call of FSfopen, the file being opened will | |
658 | +// be created if it doesn't exist. If it does exist, it's file information will be loaded and the | |
659 | +// current location in the file will be set to the end. The user will then be able to write to the file | |
660 | +// or read from the file. | |
661 | +#define FS_APPENDPLUS "a+" | |
662 | +#define APPENDPLUS "a+" //deprecated | |
663 | + | |
664 | +// Summary: Macro for the FSfopen FS_WRITE+ mode | |
665 | +// Description: If this macro is specified as the mode argument in a call of FSfopen, the file being opened will | |
666 | +// be created if it doesn't exist. If it does exist, it will be erased and replaced by an empty file | |
667 | +// of the same name. The user will then be able to write to the file or read from the file. | |
668 | +#define FS_WRITEPLUS "w+" | |
669 | +#define WRITEPLUS "w+" //deprecated | |
670 | + | |
671 | +// Summary: Macro for the FSfopen FS_READ+ mode | |
672 | +// Description: If this macro is specified as the mode argument in a call of FSfopen, the file information for the | |
673 | +// specified file will be loaded. If the file does not exist, the FSfopen function will fail. The user | |
674 | +// will then be able to read from the file or write to the file. | |
675 | +#define FS_READPLUS "r+" | |
676 | +#define READPLUS "r+" //deprecated | |
677 | + | |
678 | + | |
679 | + | |
680 | +#ifndef intmax_t | |
681 | + #ifdef __PIC24F__ | |
682 | + // Summary: A data type indicating the maximum integer size in an architecture | |
683 | + // Description: The intmax_t data type refers to the maximum-sized data type on any given architecture. This | |
684 | + // data type can be specified as a format specifier size specification for the FSfprintf function. | |
685 | + #define intmax_t long long | |
686 | + #elif defined __PIC24H__ | |
687 | + #define intmax_t long long | |
688 | + #elif defined __dsPIC30F__ | |
689 | + #define intmax_t long long | |
690 | + #elif defined __dsPIC33F__ | |
691 | + #define intmax_t long long | |
692 | + #endif | |
693 | +#endif | |
694 | + | |
695 | + | |
696 | + | |
697 | +// Summary: Indicates flag conditions for a file object | |
698 | +// Description: The FILEFLAGS structure is used to indicate conditions in a file. It contains three flags: 'write' indicates | |
699 | +// that the file was opened in a mode that allows writes, 'read' indicates that the file was opened in a mode | |
700 | +// that allows reads, and 'FileWriteEOF' indicates that additional data that is written to the file will increase | |
701 | +// the file size. | |
702 | +typedef struct | |
703 | +{ | |
704 | + unsigned write :1; // Indicates a file was opened in a mode that allows writes | |
705 | + unsigned read :1; // Indicates a file was opened in a mode that allows reads | |
706 | + unsigned FileWriteEOF :1; // Indicates the current position in a file is at the end of the file | |
707 | +}FILEFLAGS; | |
708 | + | |
709 | + | |
710 | + | |
711 | +// Summary: Indicates how to search for file entries in the FILEfind function | |
712 | +// Description: The values in the SEARCH_TYPE enumeration are used internally by the library to indicate how the FILEfind function | |
713 | +// how to perform a search. The 'LOOK_FOR_EMPTY_ENTRY' value indicates that FILEfind should search for an empty file entry. | |
714 | +// The 'LOOK_FOR_MATCHING_ENTRY' value indicates that FILEfind should search for an entry that matches the FSFILE object | |
715 | +// that was passed into the FILEfind function. | |
716 | +typedef enum{ | |
717 | + LOOK_FOR_EMPTY_ENTRY = 0, | |
718 | + LOOK_FOR_MATCHING_ENTRY | |
719 | +} SEARCH_TYPE; | |
720 | + | |
721 | + | |
722 | + | |
723 | +// Summary: Macro indicating the length of a 8.3 file name | |
724 | +// Description: The TOTAL_FILE_SIZE_8P3 macro indicates the maximum number of characters in an 8.3 file name. This value includes | |
725 | +// 8 characters for the name, three for the extentsion, and 1 for the radix ('.') | |
726 | +#define TOTAL_FILE_SIZE_8P3 (8+3+1) | |
727 | +#define TOTAL_FILE_SIZE TOTAL_FILE_SIZE_8P3 | |
728 | + | |
729 | +// Summary: Macro indicating the max length of a LFN file name | |
730 | +// Description: The MAX_FILE_NAME_LENGTH_LFN macro indicates the maximum number of characters in an LFN file name. | |
731 | +#define MAX_FILE_NAME_LENGTH_LFN 256 | |
732 | + | |
733 | +// Summary: A mask that indicates the limit of directory entries in a sector | |
734 | +// Description: The MASK_MAX_FILE_ENTRY_LIMIT_BITS is used to indicate to the Cache_File_Entry function that a new sector needs to | |
735 | +// be loaded. | |
736 | +#define MASK_MAX_FILE_ENTRY_LIMIT_BITS 0x0f | |
737 | + | |
738 | +// Summary: Value used for shift operations to calculate the sector offset in a directory | |
739 | +// Description: The VALUE_BASED_ON_ENTRIES_PER_CLUSTER macro is used to calculate sector offsets for directories. The position of the | |
740 | +// entry is shifted by 4 bits (divided by 16, since there are 16 entries in a sector) to calculate how many sectors a | |
741 | +// specified entry is offset from the beginning of the directory. | |
742 | +#define VALUE_BASED_ON_ENTRIES_PER_CLUSTER 4 | |
743 | + | |
744 | +// Summary: A value that will indicate that a dotdot directory entry points to the root. | |
745 | +// Description: The VALUE_DOTDOT_CLUSTER_VALUE_FOR_ROOT macro is used as an absolute address when writing information to a dotdot entry | |
746 | +// in a newly created directory. If a dotdot entry points to the root directory, it's cluster value must be set to 0, | |
747 | +// regardless of the actual cluster number of the root directory. | |
748 | +#define VALUE_DOTDOT_CLUSTER_VALUE_FOR_ROOT 0 | |
749 | + | |
750 | +// Summary: MAcro indicating the length of an 8.3 file name in a directory entry | |
751 | +// Description: The FILE_NAME_SIZE_8P3 macro indicates the number of characters that an 8.3 file name will take up when packed in | |
752 | +// a directory entry. This value includes 8 characters for the name and 3 for the extension. Note that the radix is not | |
753 | +// stored in the directory entry. | |
754 | +#define FILE_NAME_SIZE_8P3 11 | |
755 | +#define FILE_NAME_SIZE FILE_NAME_SIZE_8P3 | |
756 | + | |
757 | + | |
758 | +// Summary: Contains file information and is used to indicate which file to access. | |
759 | +// Description: The FSFILE structure is used to hold file information for an open file as it's being modified or accessed. A pointer to | |
760 | +// an open file's FSFILE structure will be passeed to any library function that will modify that file. | |
761 | +typedef struct | |
762 | +{ | |
763 | + DISK * dsk; // Pointer to a DISK structure | |
764 | + DWORD cluster; // The first cluster of the file | |
765 | + DWORD ccls; // The current cluster of the file | |
766 | + WORD sec; // The current sector in the current cluster of the file | |
767 | + WORD pos; // The position in the current sector | |
768 | + DWORD seek; // The absolute position in the file | |
769 | + DWORD size; // The size of the file | |
770 | + FILEFLAGS flags; // A structure containing file flags | |
771 | + WORD time; // The file's last update time | |
772 | + WORD date; // The file's last update date | |
773 | + char name[FILE_NAME_SIZE_8P3]; // The short name of the file | |
774 | + #ifdef SUPPORT_LFN | |
775 | + BOOL AsciiEncodingType; // Ascii file name or Non-Ascii file name indicator | |
776 | + unsigned short int *utf16LFNptr; // Pointer to long file name in UTF16 format | |
777 | + unsigned short int utf16LFNlength; // LFN length in terms of words including the NULL word at the last. | |
778 | + #endif | |
779 | + WORD entry; // The position of the file's directory entry in it's directory | |
780 | + WORD chk; // File structure checksum | |
781 | + WORD attributes; // The file attributes | |
782 | + DWORD dirclus; // The base cluster of the file's directory | |
783 | + DWORD dirccls; // The current cluster of the file's directory | |
784 | +} FSFILE; | |
785 | + | |
786 | +/* Summary: Possible results of the FSGetDiskProperties() function. | |
787 | +** Description: See the FSGetDiskProperties() function for more information. | |
788 | +*/ | |
789 | +typedef enum | |
790 | +{ | |
791 | + FS_GET_PROPERTIES_NO_ERRORS = 0, | |
792 | + FS_GET_PROPERTIES_DISK_NOT_MOUNTED, | |
793 | + FS_GET_PROPERTIES_CLUSTER_FAILURE, | |
794 | + FS_GET_PROPERTIES_STILL_WORKING = 0xFF | |
795 | +} FS_DISK_ERRORS; | |
796 | + | |
797 | + | |
798 | +/* Summary: Contains the disk search information, intermediate values, and results | |
799 | +** Description: This structure is used in conjunction with the FSGetDiskProperties() | |
800 | +** function. See that function for more information about the usage. | |
801 | +*/ | |
802 | +typedef struct | |
803 | +{ | |
804 | + DISK * disk; /* pointer to the disk we are searching */ | |
805 | + BOOL new_request; /* is this a new request or a continued request */ | |
806 | + FS_DISK_ERRORS properties_status; /* status of the last call of the function */ | |
807 | + | |
808 | + struct | |
809 | + { | |
810 | + BYTE disk_format; /* disk format: FAT12, FAT16, FAT32 */ | |
811 | + WORD sector_size; /* sector size of the drive */ | |
812 | + BYTE sectors_per_cluster; /* number of sectors per cluster */ | |
813 | + DWORD total_clusters; /* the number of total clusters on the drive */ | |
814 | + DWORD free_clusters; /* the number of free (unused) clusters on drive */ | |
815 | + } results; /* the results of the current search */ | |
816 | + | |
817 | + struct | |
818 | + { | |
819 | + DWORD c; | |
820 | + DWORD curcls; | |
821 | + DWORD EndClusterLimit; | |
822 | + DWORD ClusterFailValue; | |
823 | + } private; /* intermediate values used to continue searches. This | |
824 | + member should be used only by the FSGetDiskProperties() | |
825 | + function */ | |
826 | + | |
827 | +} FS_DISK_PROPERTIES; | |
828 | + | |
829 | +// Summary: A structure used for searching for files on a device. | |
830 | +// Description: The SearchRec structure is used when searching for file on a device. It contains parameters that will be loaded with | |
831 | +// file information when a file is found. It also contains the parameters that the user searched for, allowing further | |
832 | +// searches to be perfomed in the same directory for additional files that meet the specified criteria. | |
833 | +typedef struct | |
834 | +{ | |
835 | + char filename[FILE_NAME_SIZE_8P3 + 2]; // The name of the file that has been found | |
836 | + unsigned char attributes; // The attributes of the file that has been found | |
837 | + unsigned long filesize; // The size of the file that has been found | |
838 | + unsigned long timestamp; // The last modified time of the file that has been found (create time for directories) | |
839 | + #ifdef SUPPORT_LFN | |
840 | + BOOL AsciiEncodingType; // Ascii file name or Non-Ascii file name indicator | |
841 | + unsigned short int *utf16LFNfound; // Pointer to long file name found in UTF16 format | |
842 | + unsigned short int utf16LFNfoundLength; // LFN Found length in terms of words including the NULL word at the last. | |
843 | + #endif | |
844 | + unsigned int entry; // The directory entry of the last file found that matches the specified attributes. (Internal use only) | |
845 | + char searchname[FILE_NAME_SIZE_8P3 + 2]; // The 8.3 format name specified when the user began the search. (Internal use only) | |
846 | + unsigned char searchattr; // The attributes specified when the user began the search. (Internal use only) | |
847 | + unsigned long cwdclus; // The directory that this search was performed in. (Internal use only) | |
848 | + unsigned char initialized; // Check to determine if the structure was initialized by FindFirst (Internal use only) | |
849 | +} SearchRec; | |
850 | + | |
851 | + | |
852 | +/*************************************************************************** | |
853 | +* Prototypes * | |
854 | +***************************************************************************/ | |
855 | + | |
856 | + | |
857 | + | |
858 | + | |
859 | +/************************************************************************* | |
860 | + Function: | |
861 | + int FSInit(void) | |
862 | + Summary: | |
863 | + Function to initialize the device. | |
864 | + Conditions: | |
865 | + The physical device should be connected to the microcontroller. | |
866 | + Input: | |
867 | + None | |
868 | + Return Values: | |
869 | + TRUE - Initialization successful | |
870 | + FALSE - Initialization unsuccessful | |
871 | + Side Effects: | |
872 | + The FSerrno variable will be changed. | |
873 | + Description: | |
874 | + Initializes the static or dynamic memory slots for holding file | |
875 | + structures. Initializes the device with the DISKmount function. Loads | |
876 | + MBR and boot sector information. Initializes the current working | |
877 | + directory to the root directory for the device if directory support | |
878 | + is enabled. | |
879 | + Remarks: | |
880 | + None | |
881 | + *************************************************************************/ | |
882 | + | |
883 | +int FSInit(void); | |
884 | + | |
885 | + | |
886 | +/********************************************************************* | |
887 | + Function: | |
888 | + FSFILE * FSfopen (const char * fileName, const char *mode) | |
889 | + Summary: | |
890 | + Open a Ascii file | |
891 | + Conditions: | |
892 | + For read modes, file exists; FSInit performed | |
893 | + Input: | |
894 | + fileName - The name of the file to open | |
895 | + mode - | |
896 | + - WRITE - Create a new file or replace an existing file | |
897 | + - READ - Read data from an existing file | |
898 | + - APPEND - Append data to an existing file | |
899 | + - WRITEPLUS - Create a new file or replace an existing file (reads also enabled) | |
900 | + - READPLUS - Read data from an existing file (writes also enabled) | |
901 | + - APPENDPLUS - Append data to an existing file (reads also enabled) | |
902 | + Return Values: | |
903 | + FSFILE * - The pointer to the file object | |
904 | + NULL - The file could not be opened | |
905 | + Side Effects: | |
906 | + The FSerrno variable will be changed. | |
907 | + Description: | |
908 | + This function will open a file or directory. First, RAM in the | |
909 | + dynamic heap or static array will be allocated to a new FSFILE object. | |
910 | + Then, the specified file name will be formatted to ensure that it's | |
911 | + in 8.3 format or LFN format. Next, the FILEfind function will be used | |
912 | + to search for the specified file name. If the name is found, one of three | |
913 | + things will happen: if the file was opened in read mode, its file | |
914 | + info will be loaded using the FILEopen function; if it was opened in | |
915 | + write mode, it will be erased, and a new file will be constructed in | |
916 | + its place; if it was opened in append mode, its file info will be | |
917 | + loaded with FILEopen and the current location will be moved to the | |
918 | + end of the file using the FSfseek function. If the file was not | |
919 | + found by FILEfind, a new file will be created if the mode was specified as | |
920 | + a write or append mode. In these cases, a pointer to the heap or | |
921 | + static FSFILE object array will be returned. If the file was not | |
922 | + found and the mode was specified as a read mode, the memory | |
923 | + allocated to the file will be freed and the NULL pointer value | |
924 | + will be returned. | |
925 | + Remarks: | |
926 | + None. | |
927 | + *********************************************************************/ | |
928 | + | |
929 | +FSFILE * FSfopen(const char * fileName, const char *mode); | |
930 | + | |
931 | +#ifdef SUPPORT_LFN | |
932 | +/********************************************************************* | |
933 | + Function: | |
934 | + FSFILE * wFSfopen (const unsigned short int * fileName, const char *mode) | |
935 | + Summary: | |
936 | + Open a UTF16 file. | |
937 | + Conditions: | |
938 | + For read modes, file exists; FSInit performed | |
939 | + Input: | |
940 | + fileName - The name of the file to open | |
941 | + mode - | |
942 | + - WRITE - Create a new file or replace an existing file | |
943 | + - READ - Read data from an existing file | |
944 | + - APPEND - Append data to an existing file | |
945 | + - WRITEPLUS - Create a new file or replace an existing file (reads also enabled) | |
946 | + - READPLUS - Read data from an existing file (writes also enabled) | |
947 | + - APPENDPLUS - Append data to an existing file (reads also enabled) | |
948 | + Return Values: | |
949 | + FSFILE * - The pointer to the file object | |
950 | + NULL - The file could not be opened | |
951 | + Side Effects: | |
952 | + The FSerrno variable will be changed. | |
953 | + Description: | |
954 | + This function will open a file or directory. First, RAM in the | |
955 | + dynamic heap or static array will be allocated to a new FSFILE object. | |
956 | + Then, the specified file name will be formatted to ensure that it's | |
957 | + in 8.3 format or LFN format. Next, the FILEfind function will be used | |
958 | + to search for the specified file name. If the name is found, one of three | |
959 | + things will happen: if the file was opened in read mode, its file | |
960 | + info will be loaded using the FILEopen function; if it was opened in | |
961 | + write mode, it will be erased, and a new file will be constructed in | |
962 | + its place; if it was opened in append mode, its file info will be | |
963 | + loaded with FILEopen and the current location will be moved to the | |
964 | + end of the file using the FSfseek function. If the file was not | |
965 | + found by FILEfind, a new file will be created if the mode was specified as | |
966 | + a write or append mode. In these cases, a pointer to the heap or | |
967 | + static FSFILE object array will be returned. If the file was not | |
968 | + found and the mode was specified as a read mode, the memory | |
969 | + allocated to the file will be freed and the NULL pointer value | |
970 | + will be returned. | |
971 | + Remarks: | |
972 | + None. | |
973 | + *********************************************************************/ | |
974 | + | |
975 | +FSFILE * wFSfopen(const unsigned short int * fileName, const char *mode); | |
976 | +#endif | |
977 | + | |
978 | +#ifdef ALLOW_PGMFUNCTIONS | |
979 | + | |
980 | +/****************************************************************************** | |
981 | + Function: | |
982 | + FSFILE * FSfopenpgm(const rom char * fileName, const rom char *mode) | |
983 | + Summary: | |
984 | + Open a Ascii file named with a ROM string on PIC18 | |
985 | + Conditions: | |
986 | + For read modes, file exists; FSInit performed | |
987 | + Input: | |
988 | + fileName - The name of the file to be opened (ROM) | |
989 | + mode - The mode the file will be opened in (ROM) | |
990 | + Return Values: | |
991 | + FSFILE * - A pointer to the file object | |
992 | + NULL - File could not be opened | |
993 | + Side Effects: | |
994 | + The FSerrno variable will be changed. | |
995 | + Description: | |
996 | + The FSfopenpgm function will copy a PIC18 ROM fileName and mode argument | |
997 | + into RAM arrays, and then pass those arrays to the FSfopen function. | |
998 | + Remarks: | |
999 | + This function is for use with PIC18 when passing arguments in ROM. | |
1000 | + ******************************************************************************/ | |
1001 | + | |
1002 | + FSFILE * FSfopenpgm(const rom char * fileName, const rom char *mode); | |
1003 | + | |
1004 | + | |
1005 | +/************************************************************************************** | |
1006 | + Function: | |
1007 | + int FindFirstpgm (const char * fileName, unsigned int attr, SearchRec * rec) | |
1008 | + Summary: | |
1009 | + Find a file named with a ROM string on PIC18 | |
1010 | + Conditions: | |
1011 | + None | |
1012 | + Input: | |
1013 | + fileName - The name of the file to be found (ROM) | |
1014 | + attr - The attributes of the file to be found | |
1015 | + rec - Pointer to a search record to store the file info in | |
1016 | + Return Values: | |
1017 | + 0 - File was found | |
1018 | + -1 - No file matching the given parameters was found | |
1019 | + Side Effects: | |
1020 | + Search criteria from previous FindFirstpgm call on passed SearchRec object | |
1021 | + will be lost.The FSerrno variable will be changed. | |
1022 | + Description: | |
1023 | + The FindFirstpgm function will copy a PIC18 ROM fileName argument | |
1024 | + into a RAM array, and then pass that array to the FindFirst function. | |
1025 | + Remarks: | |
1026 | + Call FindFirstpgm or FindFirst before calling FindNext. | |
1027 | + This function is for use with PIC18 when passing arguments in ROM. | |
1028 | + **************************************************************************************/ | |
1029 | + | |
1030 | + int FindFirstpgm (const rom char * fileName, unsigned int attr, SearchRec * rec); | |
1031 | + | |
1032 | + | |
1033 | +/************************************************************************** | |
1034 | + Function: | |
1035 | + int FSchdirpgm (const rom char * path) | |
1036 | + Summary: | |
1037 | + Changed the CWD with a path in ROM on PIC18 | |
1038 | + Conditions: | |
1039 | + None | |
1040 | + Input: | |
1041 | + path - The path of the directory to change to (ROM) | |
1042 | + Return Values: | |
1043 | + 0 - The current working directory was changed successfully | |
1044 | + EOF - The current working directory could not be changed | |
1045 | + Side Effects: | |
1046 | + The current working directory may be changed. The FSerrno variable will | |
1047 | + be changed. | |
1048 | + Description: | |
1049 | + The FSchdirpgm function passes a PIC18 ROM path pointer to the | |
1050 | + chdirhelper function. | |
1051 | + Remarks: | |
1052 | + This function is for use with PIC18 when passing arguments in ROM | |
1053 | + **************************************************************************/ | |
1054 | + | |
1055 | + int FSchdirpgm (const rom char * path); | |
1056 | + | |
1057 | + #ifdef ALLOW_WRITES | |
1058 | + | |
1059 | + | |
1060 | +/************************************************************* | |
1061 | + Function: | |
1062 | + int FSremovepgm (const rom char * fileName) | |
1063 | + Summary: | |
1064 | + Delete a file named with a ROM string on PIC18 | |
1065 | + Conditions: | |
1066 | + File not opened; file exists | |
1067 | + Input: | |
1068 | + fileName - The name of the file to be deleted (ROM) | |
1069 | + Return Values: | |
1070 | + 0 - File was removed successfully | |
1071 | + -1 - File could not be removed | |
1072 | + Side Effects: | |
1073 | + The FSerrno variable will be changed. | |
1074 | + Description: | |
1075 | + The FSremovepgm function will copy a PIC18 ROM fileName argument | |
1076 | + into a RAM array, and then pass that array to the FSremove function. | |
1077 | + Remarks: | |
1078 | + This function is for use with PIC18 when passing arguments in ROM. | |
1079 | + *************************************************************/ | |
1080 | + | |
1081 | + int FSremovepgm (const rom char * fileName); | |
1082 | + | |
1083 | + | |
1084 | +/************************************************************************** | |
1085 | + Function: | |
1086 | + int FSmkdirpgm (const rom char * path) | |
1087 | + Summary: | |
1088 | + Create a directory with a path in ROM on PIC18 | |
1089 | + Conditions: | |
1090 | + None | |
1091 | + Input: | |
1092 | + path - The path of directories to create (ROM) | |
1093 | + Return Values: | |
1094 | + 0 - The specified directory was created successfully | |
1095 | + EOF - The specified directory could not be created | |
1096 | + Side Effects: | |
1097 | + Will create all non-existent directories in the path. The FSerrno | |
1098 | + variable will be changed. | |
1099 | + Description: | |
1100 | + The FSmkdirpgm function passes a PIC18 ROM path pointer to the | |
1101 | + mkdirhelper function. | |
1102 | + Remarks: | |
1103 | + This function is for use with PIC18 when passing arugments in ROM | |
1104 | + **************************************************************************/ | |
1105 | + | |
1106 | + int FSmkdirpgm (const rom char * path); | |
1107 | + | |
1108 | + | |
1109 | +/************************************************************************** | |
1110 | + Function: | |
1111 | + int FSrmdirpgm (const rom char * path) | |
1112 | + Summary: | |
1113 | + Delete a directory with a path in ROM on PIC18 | |
1114 | + Conditions: | |
1115 | + None. | |
1116 | + Input: | |
1117 | + path - The path of the directory to remove (ROM) | |
1118 | + rmsubdirs - | |
1119 | + - TRUE - All sub-dirs and files in the target dir will be removed | |
1120 | + - FALSE - FSrmdir will not remove non-empty directories | |
1121 | + Return Values: | |
1122 | + 0 - The specified directory was deleted successfully | |
1123 | + EOF - The specified directory could not be deleted | |
1124 | + Side Effects: | |
1125 | + The FSerrno variable will be changed. | |
1126 | + Description: | |
1127 | + The FSrmdirpgm function passes a PIC18 ROM path pointer to the | |
1128 | + rmdirhelper function. | |
1129 | + Remarks: | |
1130 | + This function is for use with PIC18 when passing arguments in ROM. | |
1131 | + **************************************************************************/ | |
1132 | + | |
1133 | + int FSrmdirpgm (const rom char * path, unsigned char rmsubdirs); | |
1134 | + | |
1135 | + | |
1136 | +/***************************************************************** | |
1137 | + Function: | |
1138 | + int FSrenamepgm(const rom char * fileName, FSFILE * fo) | |
1139 | + Summary: | |
1140 | + Rename a file named with a ROM string on PIC18 | |
1141 | + Conditions: | |
1142 | + File opened. | |
1143 | + Input: | |
1144 | + fileName - The new name of the file (in ROM) | |
1145 | + fo - The file to rename | |
1146 | + Return Values: | |
1147 | + 0 - File renamed successfully | |
1148 | + -1 - File could not be renamed | |
1149 | + Side Effects: | |
1150 | + The FSerrno variable will be changed. | |
1151 | + Description: | |
1152 | + The Fsrenamepgm function will copy the rom fileName specified | |
1153 | + by the user into a RAM array and pass that array into the | |
1154 | + FSrename function. | |
1155 | + Remarks: | |
1156 | + This function is for use with PIC18 when passing arguments in ROM. | |
1157 | + *****************************************************************/ | |
1158 | + | |
1159 | + int FSrenamepgm (const rom char * fileName, FSFILE * fo); | |
1160 | + #endif | |
1161 | +#endif | |
1162 | + | |
1163 | + | |
1164 | +/************************************************************ | |
1165 | + Function: | |
1166 | + int FSfclose(FSFILE *fo) | |
1167 | + Summary: | |
1168 | + Update file information and free FSFILE objects | |
1169 | + Conditions: | |
1170 | + File opened | |
1171 | + Input: | |
1172 | + fo - Pointer to the file to close | |
1173 | + Return Values: | |
1174 | + 0 - File closed successfully | |
1175 | + EOF - Error closing the file | |
1176 | + Side Effects: | |
1177 | + The FSerrno variable will be changed. | |
1178 | + Description: | |
1179 | + This function will update the directory entry for the | |
1180 | + file pointed to by 'fo' with the information contained | |
1181 | + in 'fo,' including the new file size and attributes. | |
1182 | + Timestamp information will also be loaded based on the | |
1183 | + method selected by the user and written to the entry | |
1184 | + as the last modified time and date. The file entry will | |
1185 | + then be written to the device. Finally, the memory | |
1186 | + used for the specified file object will be freed from | |
1187 | + the dynamic heap or the array of FSFILE objects. | |
1188 | + Remarks: | |
1189 | + A function to flush data to the device without closing the | |
1190 | + file can be created by removing the portion of this | |
1191 | + function that frees the memory and the line that clears | |
1192 | + the write flag. | |
1193 | + ************************************************************/ | |
1194 | + | |
1195 | +int FSfclose(FSFILE *fo); | |
1196 | + | |
1197 | + | |
1198 | +/********************************************************* | |
1199 | + Function: | |
1200 | + void FSrewind (FSFILE * fo) | |
1201 | + Summary: | |
1202 | + Set the current position in a file to the beginning | |
1203 | + Conditions: | |
1204 | + File opened. | |
1205 | + Input: | |
1206 | + fo - Pointer to file structure | |
1207 | + Return Values: | |
1208 | + None | |
1209 | + Side Effects: | |
1210 | + None. | |
1211 | + Description: | |
1212 | + The FSrewind funciton will reset the position of the | |
1213 | + specified file to the beginning of the file. This | |
1214 | + functionality is faster than using FSfseek to reset | |
1215 | + the position in the file. | |
1216 | + Remarks: | |
1217 | + None. | |
1218 | + *********************************************************/ | |
1219 | + | |
1220 | +void FSrewind (FSFILE *fo); | |
1221 | + | |
1222 | + | |
1223 | +/************************************************************************** | |
1224 | + Function: | |
1225 | + size_t FSfread(void *ptr, size_t size, size_t n, FSFILE *stream) | |
1226 | + Summary: | |
1227 | + Read data from a file | |
1228 | + Conditions: | |
1229 | + File is opened in a read mode | |
1230 | + Input: | |
1231 | + ptr - Destination buffer for read bytes | |
1232 | + size - Size of units in bytes | |
1233 | + n - Number of units to be read | |
1234 | + stream - File to be read from | |
1235 | + Return: | |
1236 | + size_t - number of units read | |
1237 | + Side Effects: | |
1238 | + The FSerrno variable will be changed. | |
1239 | + Description: | |
1240 | + The FSfread function will read data from the specified file. First, | |
1241 | + the appropriate sector of the file is loaded. Then, data is read into | |
1242 | + the specified buffer until the specified number of bytes have been read. | |
1243 | + When a cluster boundary is reached, a new cluster will be loaded. The | |
1244 | + parameters 'size' and 'n' indicate how much data to read. 'Size' | |
1245 | + refers to the size of one object to read (in bytes), and 'n' will refer | |
1246 | + to the number of these objects to read. The value returned will be equal | |
1247 | + to 'n' unless an error occured or the user tried to read beyond the end | |
1248 | + of the file. | |
1249 | + Remarks: | |
1250 | + None. | |
1251 | + **************************************************************************/ | |
1252 | + | |
1253 | +size_t FSfread(void *ptr, size_t size, size_t n, FSFILE *stream); | |
1254 | + | |
1255 | + | |
1256 | +/********************************************************************** | |
1257 | + Function: | |
1258 | + int FSfseek(FSFILE *stream, long offset, int whence) | |
1259 | + Summary: | |
1260 | + Change the current position in a file | |
1261 | + Conditions: | |
1262 | + File opened | |
1263 | + Input: | |
1264 | + stream - Pointer to file structure | |
1265 | + offset - Offset from base location | |
1266 | + whence - | |
1267 | + - SEEK_SET - Seek from start of file | |
1268 | + - SEEK_CUR - Seek from current location | |
1269 | + - SEEK_END - Seek from end of file (subtract offset) | |
1270 | + Return Values: | |
1271 | + 0 - Operation successful | |
1272 | + -1 - Operation unsuccesful | |
1273 | + Side Effects: | |
1274 | + The FSerrno variable will be changed. | |
1275 | + Description: | |
1276 | + The FSfseek function will change the current position in the file to | |
1277 | + one specified by the user. First, an absolute offset is calculated | |
1278 | + using the offset and base location passed in by the user. Then, the | |
1279 | + position variables are updated, and the sector number that corresponds | |
1280 | + to the new location. That sector is then loaded. If the offset | |
1281 | + falls exactly on a cluster boundary, a new cluster will be allocated | |
1282 | + to the file and the position will be set to the first byte of that | |
1283 | + cluster. | |
1284 | + Remarks: | |
1285 | + None | |
1286 | + **********************************************************************/ | |
1287 | + | |
1288 | +int FSfseek(FSFILE *stream, long offset, int whence); | |
1289 | + | |
1290 | + | |
1291 | +/******************************************************************* | |
1292 | + Function: | |
1293 | + long FSftell (FSFILE * fo) | |
1294 | + Summary: | |
1295 | + Determine the current location in a file | |
1296 | + Conditions: | |
1297 | + File opened | |
1298 | + Input: | |
1299 | + fo - Pointer to file structure | |
1300 | + Return: Current location in the file | |
1301 | + Side Effects: | |
1302 | + The FSerrno variable will be changed | |
1303 | + Description: | |
1304 | + The FSftell function will return the current position in the | |
1305 | + file pointed to by 'fo' by returning the 'seek' variable in the | |
1306 | + FSFILE object, which is used to keep track of the absolute | |
1307 | + location of the current position in the file. | |
1308 | + Remarks: | |
1309 | + None | |
1310 | + *******************************************************************/ | |
1311 | + | |
1312 | +long FSftell(FSFILE *fo); | |
1313 | + | |
1314 | + | |
1315 | +/**************************************************** | |
1316 | + Function: | |
1317 | + int FSfeof( FSFILE * stream ) | |
1318 | + Summary: | |
1319 | + Indicate whether the current file position is at the end | |
1320 | + Conditions: | |
1321 | + File is open in a read mode | |
1322 | + Input: | |
1323 | + stream - Pointer to the target file | |
1324 | + Return Values: | |
1325 | + Non-Zero - EOF reached | |
1326 | + 0 - Not at end of File | |
1327 | + Side Effects: | |
1328 | + The FSerrno variable will be changed. | |
1329 | + Description: | |
1330 | + The FSfeof function will indicate that the end-of- | |
1331 | + file has been reached for the specified file by | |
1332 | + comparing the absolute location in the file to the | |
1333 | + size of the file. | |
1334 | + Remarks: | |
1335 | + None. | |
1336 | + ****************************************************/ | |
1337 | + | |
1338 | +int FSfeof( FSFILE * stream ); | |
1339 | + | |
1340 | + | |
1341 | +#ifdef ALLOW_FORMATS | |
1342 | +/******************************************************************* | |
1343 | + Function: | |
1344 | + int FSformat (char mode, long int serialNumber, char * volumeID) | |
1345 | + Summary: | |
1346 | + Formats a device | |
1347 | + Conditions: | |
1348 | + The device must possess a valid master boot record. | |
1349 | + Input: | |
1350 | + mode - - 0 - Just erase the FAT and root | |
1351 | + - 1 - Create a new boot sector | |
1352 | + serialNumber - Serial number to write to the card | |
1353 | + volumeID - Name of the card | |
1354 | + Return Values: | |
1355 | + 0 - Format was successful | |
1356 | + EOF - Format was unsuccessful | |
1357 | + Side Effects: | |
1358 | + The FSerrno variable will be changed. | |
1359 | + Description: | |
1360 | + The FSformat function can be used to create a new boot sector | |
1361 | + on a device, based on the information in the master boot record. | |
1362 | + This function will first initialize the I/O pins and the device, | |
1363 | + and then attempts to read the master boot record. If the MBR | |
1364 | + cannot be loaded successfully, the function will fail. Next, if | |
1365 | + the 'mode' argument is specified as '0' the existing boot sector | |
1366 | + information will be loaded. If the 'mode' argument is '1' an | |
1367 | + entirely new boot sector will be constructed using the disk | |
1368 | + values from the master boot record. Once the boot sector has | |
1369 | + been successfully loaded/created, the locations of the FAT and | |
1370 | + root will be loaded from it, and they will be completely | |
1371 | + erased. If the user has specified a volumeID parameter, a | |
1372 | + VOLUME attribute entry will be created in the root directory | |
1373 | + to name the device. | |
1374 | + | |
1375 | + FAT12, FAT16 and FAT32 formatting are supported. | |
1376 | + | |
1377 | + Based on the number of sectors, the format function automatically | |
1378 | + compute the smallest possible value for the cluster size in order to | |
1379 | + accommodate the physical size of the media. In this case, if a media | |
1380 | + with a big capacity is formatted, the format function may take a very | |
1381 | + long time to write all the FAT tables. | |
1382 | + | |
1383 | + Therefore, the FORMAT_SECTORS_PER_CLUSTER macro may be used to | |
1384 | + specify the exact cluster size (in multiples of sector size). This | |
1385 | + macro can be defined in FSconfig.h | |
1386 | + | |
1387 | + Remarks: | |
1388 | + Only devices with a sector size of 512 bytes are supported by the | |
1389 | + format function | |
1390 | + *******************************************************************/ | |
1391 | + | |
1392 | +int FSformat (char mode, long int serialNumber, char * volumeID); | |
1393 | +#endif | |
1394 | + | |
1395 | + | |
1396 | +#ifdef ALLOW_WRITES | |
1397 | +/*************************************************************************** | |
1398 | + Function: | |
1399 | + int FSattrib (FSFILE * file, unsigned char attributes) | |
1400 | + Summary: | |
1401 | + Change the attributes of a file | |
1402 | + Conditions: | |
1403 | + File opened | |
1404 | + Input: | |
1405 | + file - Pointer to file structure | |
1406 | + attributes - The attributes to set for the file | |
1407 | + - Attribute - Value - Indications | |
1408 | + - ATTR_READ_ONLY - 0x01 - The read-only attribute | |
1409 | + - ATTR_HIDDEN - 0x02 - The hidden attribute | |
1410 | + - ATTR_SYSTEM - 0x04 - The system attribute | |
1411 | + - ATTR_ARCHIVE - 0x20 - The archive attribute | |
1412 | + Return Values: | |
1413 | + 0 - Attribute change was successful | |
1414 | + -1 - Attribute change was unsuccessful | |
1415 | + Side Effects: | |
1416 | + The FSerrno variable will be changed. | |
1417 | + Description: | |
1418 | + The FSattrib funciton will set the attributes of the specified file | |
1419 | + to the attributes passed in by the user. This function will load the | |
1420 | + file entry, replace the attributes with the ones specified, and write | |
1421 | + the attributes back. If the specified file is a directory, the | |
1422 | + directory attribute will be preserved. | |
1423 | + Remarks: | |
1424 | + None | |
1425 | + ***************************************************************************/ | |
1426 | + | |
1427 | +int FSattrib (FSFILE * file, unsigned char attributes); | |
1428 | + | |
1429 | + | |
1430 | +/*************************************************************** | |
1431 | + Function: | |
1432 | + int FSrename (const rom char * fileName, FSFILE * fo) | |
1433 | + Summary: | |
1434 | + Change the Ascii name of a file or directory | |
1435 | + Conditions: | |
1436 | + File opened. | |
1437 | + Input: | |
1438 | + fileName - The new name of the file | |
1439 | + fo - The file to rename | |
1440 | + Return Values: | |
1441 | + 0 - File was renamed successfully | |
1442 | + EOF - File was not renamed | |
1443 | + Side Effects: | |
1444 | + The FSerrno variable will be changed. | |
1445 | + Description: | |
1446 | + The FSrename function will rename a file. First, it will | |
1447 | + search through the current working directory to ensure the | |
1448 | + specified new filename is not already in use. If it isn't, | |
1449 | + the new filename will be written to the file entry of the | |
1450 | + file pointed to by 'fo.' | |
1451 | + Remarks: | |
1452 | + None | |
1453 | + ***************************************************************/ | |
1454 | + | |
1455 | +int FSrename (const char * fileName, FSFILE * fo); | |
1456 | + | |
1457 | +#ifdef SUPPORT_LFN | |
1458 | +/*************************************************************** | |
1459 | + Function: | |
1460 | + int wFSrename (const rom unsigned short int * fileName, FSFILE * fo) | |
1461 | + Summary: | |
1462 | + Change the name of a file or directory to the UTF16 input fileName | |
1463 | + Conditions: | |
1464 | + File opened. | |
1465 | + Input: | |
1466 | + fileName - The new name of the file | |
1467 | + fo - The file to rename | |
1468 | + Return Values: | |
1469 | + 0 - File was renamed successfully | |
1470 | + EOF - File was not renamed | |
1471 | + Side Effects: | |
1472 | + The FSerrno variable will be changed. | |
1473 | + Description: | |
1474 | + The wFSrename function will rename a file. First, it will | |
1475 | + search through the current working directory to ensure the | |
1476 | + specified new UTF16 filename is not already in use. If it isn't, | |
1477 | + the new filename will be written to the file entry of the | |
1478 | + file pointed to by 'fo.' | |
1479 | + Remarks: | |
1480 | + None | |
1481 | + ***************************************************************/ | |
1482 | + | |
1483 | +int wFSrename (const unsigned short int * fileName, FSFILE * fo); | |
1484 | +#endif | |
1485 | + | |
1486 | +/********************************************************************* | |
1487 | + Function: | |
1488 | + int FSremove (const char * fileName) | |
1489 | + Summary: | |
1490 | + Delete a Ascii file | |
1491 | + Conditions: | |
1492 | + File not opened, file exists | |
1493 | + Input: | |
1494 | + fileName - Name of the file to erase | |
1495 | + Return Values: | |
1496 | + 0 - File removed | |
1497 | + EOF - File was not removed | |
1498 | + Side Effects: | |
1499 | + The FSerrno variable will be changed. | |
1500 | + Description: | |
1501 | + The FSremove function will attempt to find the specified file with | |
1502 | + the FILEfind function. If the file is found, it will be erased | |
1503 | + using the FILEerase function.The user can also provide ascii alias name | |
1504 | + of the ascii long file name as the input to this function to get it erased | |
1505 | + from the memory. | |
1506 | + Remarks: | |
1507 | + None | |
1508 | + **********************************************************************/ | |
1509 | + | |
1510 | +int FSremove (const char * fileName); | |
1511 | + | |
1512 | +#ifdef SUPPORT_LFN | |
1513 | +/********************************************************************* | |
1514 | + Function: | |
1515 | + int wFSremove (const unsigned short int * fileName) | |
1516 | + Summary: | |
1517 | + Delete a UTF16 file | |
1518 | + Conditions: | |
1519 | + File not opened, file exists | |
1520 | + Input: | |
1521 | + fileName - Name of the file to erase | |
1522 | + Return Values: | |
1523 | + 0 - File removed | |
1524 | + EOF - File was not removed | |
1525 | + Side Effects: | |
1526 | + The FSerrno variable will be changed. | |
1527 | + Description: | |
1528 | + The wFSremove function will attempt to find the specified UTF16 file | |
1529 | + name with the FILEfind function. If the file is found, it will be erased | |
1530 | + using the FILEerase function. | |
1531 | + Remarks: | |
1532 | + None | |
1533 | + **********************************************************************/ | |
1534 | + | |
1535 | +int wFSremove (const unsigned short int * fileName); | |
1536 | +#endif | |
1537 | + | |
1538 | +/********************************************************************************* | |
1539 | + Function: | |
1540 | + size_t FSfwrite(const void *data_to_write, size_t size, size_t n, FSFILE *stream) | |
1541 | + Summary: | |
1542 | + Write data to a file | |
1543 | + Conditions: | |
1544 | + File opened in WRITE, APPEND, WRITE+, APPEND+, READ+ mode | |
1545 | + Input: | |
1546 | + data_to_write - Pointer to source buffer | |
1547 | + size - Size of units in bytes | |
1548 | + n - Number of units to transfer | |
1549 | + stream - Pointer to file structure | |
1550 | + Return: | |
1551 | + size_t - number of units written | |
1552 | + Side Effects: | |
1553 | + The FSerrno variable will be changed. | |
1554 | + Description: | |
1555 | + The FSfwrite function will write data to a file. First, the sector that | |
1556 | + corresponds to the current position in the file will be loaded (if it hasn't | |
1557 | + already been cached in the global data buffer). Data will then be written to | |
1558 | + the device from the specified buffer until the specified amount has been written. | |
1559 | + If the end of a cluster is reached, the next cluster will be loaded, unless | |
1560 | + the end-of-file flag for the specified file has been set. If it has, a new | |
1561 | + cluster will be allocated to the file. Finally, the new position and filesize | |
1562 | + will be stored in the FSFILE object. The parameters 'size' and 'n' indicate how | |
1563 | + much data to write. 'Size' refers to the size of one object to write (in bytes), | |
1564 | + and 'n' will refer to the number of these objects to write. The value returned | |
1565 | + will be equal to 'n' unless an error occured. | |
1566 | + Remarks: | |
1567 | + None. | |
1568 | + *********************************************************************************/ | |
1569 | + | |
1570 | +size_t FSfwrite(const void *data_to_write, size_t size, size_t n, FSFILE *stream); | |
1571 | + | |
1572 | +#endif | |
1573 | + | |
1574 | +#ifdef ALLOW_DIRS | |
1575 | + | |
1576 | + | |
1577 | +/************************************************************************** | |
1578 | + Function: | |
1579 | + int FSchdir (char * path) | |
1580 | + Summary: | |
1581 | + Change the current working directory as per the path specified in Ascii format | |
1582 | + Conditions: | |
1583 | + None | |
1584 | + Input: | |
1585 | + path - The path of the directory to change to. | |
1586 | + Return Values: | |
1587 | + 0 - The current working directory was changed successfully | |
1588 | + EOF - The current working directory could not be changed | |
1589 | + Side Effects: | |
1590 | + The current working directory may be changed. The FSerrno variable will | |
1591 | + be changed. | |
1592 | + Description: | |
1593 | + The FSchdir function passes a RAM pointer to the path to the | |
1594 | + chdirhelper function. | |
1595 | + Remarks: | |
1596 | + None | |
1597 | + **************************************************************************/ | |
1598 | + | |
1599 | +int FSchdir (char * path); | |
1600 | + | |
1601 | +#ifdef SUPPORT_LFN | |
1602 | +/************************************************************************** | |
1603 | + Function: | |
1604 | + int wFSchdir (unsigned short int * path) | |
1605 | + Summary: | |
1606 | + Change the current working directory as per the path specified in UTF16 format | |
1607 | + Conditions: | |
1608 | + None | |
1609 | + Input: | |
1610 | + path - The path of the directory to change to. | |
1611 | + Return Values: | |
1612 | + 0 - The current working directory was changed successfully | |
1613 | + EOF - The current working directory could not be changed | |
1614 | + Side Effects: | |
1615 | + The current working directory may be changed. The FSerrno variable will | |
1616 | + be changed. | |
1617 | + Description: | |
1618 | + The FSchdir function passes a RAM pointer to the path to the | |
1619 | + chdirhelper function. | |
1620 | + Remarks: | |
1621 | + None | |
1622 | + **************************************************************************/ | |
1623 | + | |
1624 | +int wFSchdir (unsigned short int * path); | |
1625 | +#endif | |
1626 | + | |
1627 | +/************************************************************** | |
1628 | + Function: | |
1629 | + char * FSgetcwd (char * path, int numchars) | |
1630 | + Summary: | |
1631 | + Get the current working directory path in Ascii format | |
1632 | + Conditions: | |
1633 | + None | |
1634 | + Input: | |
1635 | + path - Pointer to the array to return the cwd name in | |
1636 | + numchars - Number of chars in the path | |
1637 | + Return Values: | |
1638 | + char * - The cwd name string pointer (path or defaultArray) | |
1639 | + NULL - The current working directory name could not be loaded. | |
1640 | + Side Effects: | |
1641 | + The FSerrno variable will be changed | |
1642 | + Description: | |
1643 | + The FSgetcwd function will get the name of the current | |
1644 | + working directory and return it to the user. The name | |
1645 | + will be copied into the buffer pointed to by 'path,' | |
1646 | + starting at the root directory and copying as many chars | |
1647 | + as possible before the end of the buffer. The buffer | |
1648 | + size is indicated by the 'numchars' argument. The first | |
1649 | + thing this function will do is load the name of the current | |
1650 | + working directory, if it isn't already present. This could | |
1651 | + occur if the user switched to the dotdot entry of a | |
1652 | + subdirectory immediately before calling this function. The | |
1653 | + function will then copy the current working directory name | |
1654 | + into the buffer backwards, and insert a backslash character. | |
1655 | + Next, the function will continuously switch to the previous | |
1656 | + directories and copy their names backwards into the buffer | |
1657 | + until it reaches the root. If the buffer overflows, it | |
1658 | + will be treated as a circular buffer, and data will be | |
1659 | + copied over existing characters, starting at the beginning. | |
1660 | + Once the root directory is reached, the text in the buffer | |
1661 | + will be swapped, so that the buffer contains as much of the | |
1662 | + current working directory name as possible, starting at the | |
1663 | + root. | |
1664 | + Remarks: | |
1665 | + None | |
1666 | + **************************************************************/ | |
1667 | + | |
1668 | +char * FSgetcwd (char * path, int numbchars); | |
1669 | + | |
1670 | +#ifdef SUPPORT_LFN | |
1671 | +/************************************************************** | |
1672 | + Function: | |
1673 | + char * wFSgetcwd (unsigned short int * path, int numchars) | |
1674 | + Summary: | |
1675 | + Get the current working directory path in UTF16 format | |
1676 | + Conditions: | |
1677 | + None | |
1678 | + Input: | |
1679 | + path - Pointer to the array to return the cwd name in | |
1680 | + numchars - Number of chars in the path | |
1681 | + Return Values: | |
1682 | + char * - The cwd name string pointer (path or defaultArray) | |
1683 | + NULL - The current working directory name could not be loaded. | |
1684 | + Side Effects: | |
1685 | + The FSerrno variable will be changed | |
1686 | + Description: | |
1687 | + The FSgetcwd function will get the name of the current | |
1688 | + working directory and return it to the user. The name | |
1689 | + will be copied into the buffer pointed to by 'path,' | |
1690 | + starting at the root directory and copying as many chars | |
1691 | + as possible before the end of the buffer. The buffer | |
1692 | + size is indicated by the 'numchars' argument. The first | |
1693 | + thing this function will do is load the name of the current | |
1694 | + working directory, if it isn't already present. This could | |
1695 | + occur if the user switched to the dotdot entry of a | |
1696 | + subdirectory immediately before calling this function. The | |
1697 | + function will then copy the current working directory name | |
1698 | + into the buffer backwards, and insert a backslash character. | |
1699 | + Next, the function will continuously switch to the previous | |
1700 | + directories and copy their names backwards into the buffer | |
1701 | + until it reaches the root. If the buffer overflows, it | |
1702 | + will be treated as a circular buffer, and data will be | |
1703 | + copied over existing characters, starting at the beginning. | |
1704 | + Once the root directory is reached, the text in the buffer | |
1705 | + will be swapped, so that the buffer contains as much of the | |
1706 | + current working directory name as possible, starting at the | |
1707 | + root. | |
1708 | + Remarks: | |
1709 | + None | |
1710 | + **************************************************************/ | |
1711 | + | |
1712 | +char * wFSgetcwd (unsigned short int * path, int numbchars); | |
1713 | +#endif | |
1714 | + | |
1715 | +#ifdef ALLOW_WRITES | |
1716 | + | |
1717 | +/************************************************************************** | |
1718 | + Function: | |
1719 | + int FSmkdir (char * path) | |
1720 | + Summary: | |
1721 | + Create a directory as per the Ascii input path | |
1722 | + Conditions: | |
1723 | + None | |
1724 | + Input: | |
1725 | + path - The path of directories to create. | |
1726 | + Return Values: | |
1727 | + 0 - The specified directory was created successfully | |
1728 | + EOF - The specified directory could not be created | |
1729 | + Side Effects: | |
1730 | + Will create all non-existent directories in the path. The FSerrno | |
1731 | + variable will be changed. | |
1732 | + Description: | |
1733 | + The FSmkdir function passes a RAM pointer to the path to the | |
1734 | + mkdirhelper function. | |
1735 | + Remarks: | |
1736 | + None | |
1737 | + **************************************************************************/ | |
1738 | + | |
1739 | +int FSmkdir (char * path); | |
1740 | + | |
1741 | +#ifdef SUPPORT_LFN | |
1742 | +/************************************************************************** | |
1743 | + Function: | |
1744 | + int wFSmkdir (unsigned short int * path) | |
1745 | + Summary: | |
1746 | + Create a directory as per the UTF16 input path | |
1747 | + Conditions: | |
1748 | + None | |
1749 | + Input: | |
1750 | + path - The path of directories to create. | |
1751 | + Return Values: | |
1752 | + 0 - The specified directory was created successfully | |
1753 | + EOF - The specified directory could not be created | |
1754 | + Side Effects: | |
1755 | + Will create all non-existent directories in the path. The FSerrno | |
1756 | + variable will be changed. | |
1757 | + Description: | |
1758 | + The wFSmkdir function passes a RAM pointer to the path to the | |
1759 | + mkdirhelper function. | |
1760 | + Remarks: | |
1761 | + None | |
1762 | + **************************************************************************/ | |
1763 | + | |
1764 | +int wFSmkdir (unsigned short int * path); | |
1765 | +#endif | |
1766 | + | |
1767 | +/************************************************************************** | |
1768 | + Function: | |
1769 | + int FSrmdir (char * path) | |
1770 | + Summary: | |
1771 | + Delete a directory as per the Ascii input path | |
1772 | + Conditions: | |
1773 | + None | |
1774 | + Input: | |
1775 | + path - The path of the directory to remove | |
1776 | + rmsubdirs - | |
1777 | + - TRUE - All sub-dirs and files in the target dir will be removed | |
1778 | + - FALSE - FSrmdir will not remove non-empty directories | |
1779 | + Return Values: | |
1780 | + 0 - The specified directory was deleted successfully | |
1781 | + EOF - The specified directory could not be deleted | |
1782 | + Side Effects: | |
1783 | + The FSerrno variable will be changed. | |
1784 | + Description: | |
1785 | + The FSrmdir function passes a RAM pointer to the path to the | |
1786 | + rmdirhelper function. | |
1787 | + Remarks: | |
1788 | + None. | |
1789 | + **************************************************************************/ | |
1790 | + | |
1791 | +int FSrmdir (char * path, unsigned char rmsubdirs); | |
1792 | + | |
1793 | +#ifdef SUPPORT_LFN | |
1794 | +/************************************************************************** | |
1795 | + Function: | |
1796 | + int wFSrmdir (unsigned short int * path, unsigned char rmsubdirs) | |
1797 | + Summary: | |
1798 | + Delete a directory as per the UTF16 input path | |
1799 | + Conditions: | |
1800 | + None | |
1801 | + Input: | |
1802 | + path - The path of the directory to remove | |
1803 | + rmsubdirs - | |
1804 | + - TRUE - All sub-dirs and files in the target dir will be removed | |
1805 | + - FALSE - FSrmdir will not remove non-empty directories | |
1806 | + Return Values: | |
1807 | + 0 - The specified directory was deleted successfully | |
1808 | + EOF - The specified directory could not be deleted | |
1809 | + Side Effects: | |
1810 | + The FSerrno variable will be changed. | |
1811 | + Description: | |
1812 | + The wFSrmdir function passes a RAM pointer to the path to the | |
1813 | + rmdirhelper function. | |
1814 | + Remarks: | |
1815 | + None. | |
1816 | + **************************************************************************/ | |
1817 | + | |
1818 | +int wFSrmdir (unsigned short int * path, unsigned char rmsubdirs); | |
1819 | +#endif | |
1820 | + | |
1821 | +#endif | |
1822 | + | |
1823 | +#endif | |
1824 | + | |
1825 | +#ifdef USERDEFINEDCLOCK | |
1826 | + | |
1827 | + | |
1828 | +/*********************************************************************************************************** | |
1829 | + Function: | |
1830 | + int SetClockVars (unsigned int year, unsigned char month, unsigned char day, unsigned char hour, unsigned char minute, unsigned char second) | |
1831 | + Summary: | |
1832 | + Manually set timestamp variables | |
1833 | + Conditions: | |
1834 | + USERDEFINEDCLOCK macro defined in FSconfig.h. | |
1835 | + Input: | |
1836 | + year - The year (1980\-2107) | |
1837 | + month - The month (1\-12) | |
1838 | + day - The day of the month (1\-31) | |
1839 | + hour - The hour (0\-23) | |
1840 | + minute - The minute (0\-59) | |
1841 | + second - The second (0\-59) | |
1842 | + Return Values: | |
1843 | + None | |
1844 | + Side Effects: | |
1845 | + Modifies global timing variables | |
1846 | + Description: | |
1847 | + Lets the user manually set the timing variables. The values passed in will be converted to the format | |
1848 | + used by the FAT timestamps. | |
1849 | + Remarks: | |
1850 | + Call this before creating a file or directory (set create time) and | |
1851 | + before closing a file (set last access time, last modified time) | |
1852 | + ***********************************************************************************************************/ | |
1853 | + | |
1854 | +int SetClockVars (unsigned int year, unsigned char month, unsigned char day, unsigned char hour, unsigned char minute, unsigned char second); | |
1855 | +#endif | |
1856 | + | |
1857 | + | |
1858 | +#ifdef ALLOW_FILESEARCH | |
1859 | + | |
1860 | +/*********************************************************************************** | |
1861 | + Function: | |
1862 | + int FindFirst (const char * fileName, unsigned int attr, SearchRec * rec) | |
1863 | + Summary: | |
1864 | + Initial search function for the input Ascii fileName | |
1865 | + Conditions: | |
1866 | + None | |
1867 | + Input: | |
1868 | + fileName - The name to search for | |
1869 | + - Parital string search characters | |
1870 | + - * - Indicates the rest of the filename or extension can vary (e.g. FILE.*) | |
1871 | + - ? - Indicates that one character in a filename can vary (e.g. F?LE.T?T) | |
1872 | + attr - The attributes that a found file may have | |
1873 | + - ATTR_READ_ONLY - File may be read only | |
1874 | + - ATTR_HIDDEN - File may be a hidden file | |
1875 | + - ATTR_SYSTEM - File may be a system file | |
1876 | + - ATTR_VOLUME - Entry may be a volume label | |
1877 | + - ATTR_DIRECTORY - File may be a directory | |
1878 | + - ATTR_ARCHIVE - File may have archive attribute | |
1879 | + - ATTR_MASK - All attributes | |
1880 | + rec - pointer to a structure to put the file information in | |
1881 | + Return Values: | |
1882 | + 0 - File was found | |
1883 | + -1 - No file matching the specified criteria was found | |
1884 | + Side Effects: | |
1885 | + Search criteria from previous FindFirst call on passed SearchRec object | |
1886 | + will be lost. "utf16LFNfound" is overwritten after subsequent FindFirst/FindNext | |
1887 | + operations.It is the responsibility of the application to read the "utf16LFNfound" | |
1888 | + before it is lost.The FSerrno variable will be changed. | |
1889 | + Description: | |
1890 | + The FindFirst function will search for a file based on parameters passed in | |
1891 | + by the user. This function will use the FILEfind function to parse through | |
1892 | + the current working directory searching for entries that match the specified | |
1893 | + parameters. If a file is found, its parameters are copied into the SearchRec | |
1894 | + structure, as are the initial parameters passed in by the user and the position | |
1895 | + of the file entry in the current working directory.If the return value of the | |
1896 | + function is 0 then "utf16LFNfoundLength" indicates whether the file found was | |
1897 | + long file name or short file name(8P3 format). The "utf16LFNfoundLength" is non-zero | |
1898 | + for long file name and is zero for 8P3 format."utf16LFNfound" points to the | |
1899 | + address of long file name if found during the operation. | |
1900 | + Remarks: | |
1901 | + Call FindFirst or FindFirstpgm before calling FindNext | |
1902 | + ***********************************************************************************/ | |
1903 | + | |
1904 | +int FindFirst (const char * fileName, unsigned int attr, SearchRec * rec); | |
1905 | + | |
1906 | +#ifdef SUPPORT_LFN | |
1907 | +/*********************************************************************************** | |
1908 | + Function: | |
1909 | + int wFindFirst (const unsigned short int * fileName, unsigned int attr, SearchRec * rec) | |
1910 | + Summary: | |
1911 | + Initial search function for the input UTF16 fileName | |
1912 | + Conditions: | |
1913 | + None | |
1914 | + Input: | |
1915 | + fileName - The name to search for | |
1916 | + - Parital string search characters | |
1917 | + - * - Indicates the rest of the filename or extension can vary (e.g. FILE.*) | |
1918 | + - ? - Indicates that one character in a filename can vary (e.g. F?LE.T?T) | |
1919 | + attr - The attributes that a found file may have | |
1920 | + - ATTR_READ_ONLY - File may be read only | |
1921 | + - ATTR_HIDDEN - File may be a hidden file | |
1922 | + - ATTR_SYSTEM - File may be a system file | |
1923 | + - ATTR_VOLUME - Entry may be a volume label | |
1924 | + - ATTR_DIRECTORY - File may be a directory | |
1925 | + - ATTR_ARCHIVE - File may have archive attribute | |
1926 | + - ATTR_MASK - All attributes | |
1927 | + rec - pointer to a structure to put the file information in | |
1928 | + Return Values: | |
1929 | + 0 - File was found | |
1930 | + -1 - No file matching the specified criteria was found | |
1931 | + Side Effects: | |
1932 | + Search criteria from previous wFindFirst call on passed SearchRec object | |
1933 | + will be lost. "utf16LFNfound" is overwritten after subsequent wFindFirst/FindNext | |
1934 | + operations.It is the responsibility of the application to read the "utf16LFNfound" | |
1935 | + before it is lost.The FSerrno variable will be changed. | |
1936 | + Description: | |
1937 | + The wFindFirst function will search for a file based on parameters passed in | |
1938 | + by the user. This function will use the FILEfind function to parse through | |
1939 | + the current working directory searching for entries that match the specified | |
1940 | + parameters. If a file is found, its parameters are copied into the SearchRec | |
1941 | + structure, as are the initial parameters passed in by the user and the position | |
1942 | + of the file entry in the current working directory.If the return value of the | |
1943 | + function is 0 then "utf16LFNfoundLength" indicates whether the file found was | |
1944 | + long file name or short file name(8P3 format). The "utf16LFNfoundLength" is non-zero | |
1945 | + for long file name and is zero for 8P3 format."utf16LFNfound" points to the | |
1946 | + address of long file name if found during the operation. | |
1947 | + Remarks: | |
1948 | + Call FindFirst or FindFirstpgm before calling FindNext | |
1949 | + ***********************************************************************************/ | |
1950 | + | |
1951 | +int wFindFirst (const unsigned short int * fileName, unsigned int attr, SearchRec * rec); | |
1952 | +#endif | |
1953 | + | |
1954 | +/********************************************************************** | |
1955 | + Function: | |
1956 | + int FindNext (SearchRec * rec) | |
1957 | + Summary: | |
1958 | + Sequential search function | |
1959 | + Conditions: | |
1960 | + None | |
1961 | + Input: | |
1962 | + rec - The structure to store the file information in | |
1963 | + Return Values: | |
1964 | + 0 - File was found | |
1965 | + -1 - No additional files matching the specified criteria were found | |
1966 | + Side Effects: | |
1967 | + Search criteria from previous FindNext call on passed SearchRec object | |
1968 | + will be lost. "utf16LFNfound" is overwritten after subsequent FindFirst/FindNext | |
1969 | + operations.It is the responsibility of the application to read the "utf16LFNfound" | |
1970 | + before it is lost.The FSerrno variable will be changed. | |
1971 | + Description: | |
1972 | + The FindNext function performs the same function as the FindFirst | |
1973 | + funciton, except it does not copy any search parameters into the | |
1974 | + SearchRec structure (only info about found files) and it begins | |
1975 | + searching at the last directory entry offset at which a file was | |
1976 | + found, rather than at the beginning of the current working | |
1977 | + directory.If the return value of the function is 0 then "utf16LFNfoundLength" | |
1978 | + indicates whether the file found was long file name or short file | |
1979 | + name(8P3 format). The "utf16LFNfoundLength" is non-zero for long file name | |
1980 | + and is zero for 8P3 format."utf16LFNfound" points to the address of long | |
1981 | + file name if found during the operation. | |
1982 | + Remarks: | |
1983 | + Call FindFirst or FindFirstpgm before calling this function | |
1984 | + **********************************************************************/ | |
1985 | + | |
1986 | +int FindNext (SearchRec * rec); | |
1987 | +#endif | |
1988 | + | |
1989 | + | |
1990 | +/********************************************************************** | |
1991 | + Function: | |
1992 | + // PIC24/30/33/32 | |
1993 | + int FSfprintf (FSFILE * fptr, const char * fmt, ...) | |
1994 | + // PIC18 | |
1995 | + int FSfpritnf (FSFILE * fptr, const rom char * fmt, ...) | |
1996 | + Summary: | |
1997 | + Function to write formatted strings to a file | |
1998 | + Conditions: | |
1999 | + For PIC18, integer promotion must be enabled in the project build | |
2000 | + options menu. File opened in a write mode. | |
2001 | + Input: | |
2002 | + fptr - A pointer to the file to write to. | |
2003 | + fmt - A string of characters and format specifiers to write to | |
2004 | + the file | |
2005 | + ... - Additional arguments inserted in the string by format | |
2006 | + specifiers | |
2007 | + Returns: | |
2008 | + The number of characters written to the file | |
2009 | + Side Effects: | |
2010 | + The FSerrno variable will be changed. | |
2011 | + Description: | |
2012 | + Writes a specially formatted string to a file. | |
2013 | + Remarks: | |
2014 | + Consult AN1045 for a full description of how to use format | |
2015 | + specifiers. | |
2016 | + **********************************************************************/ | |
2017 | + | |
2018 | +#ifdef ALLOW_FSFPRINTF | |
2019 | + #ifdef __18CXX | |
2020 | + int FSfprintf (FSFILE *fptr, const rom char *fmt, ...); | |
2021 | + #else | |
2022 | + int FSfprintf (FSFILE *fptr, const char * fmt, ...); | |
2023 | + #endif | |
2024 | +#endif | |
2025 | + | |
2026 | + | |
2027 | +/************************************************************************** | |
2028 | + Function: | |
2029 | + int FSerror (void) | |
2030 | + Summary: | |
2031 | + Return an error code for the last function call | |
2032 | + Conditions: | |
2033 | + The return value depends on the last function called. | |
2034 | + Input: | |
2035 | + None | |
2036 | + Side Effects: | |
2037 | + None. | |
2038 | + Return Values: | |
2039 | + FSInit - | |
2040 | + - CE_GOOD ・ No Error | |
2041 | + - CE_INIT_ERROR ・ The physical media could not be initialized | |
2042 | + - CE_BAD_SECTOR_READ ・ The MBR or the boot sector could not be | |
2043 | + read correctly | |
2044 | + - CE_BAD_PARITION ・ The MBR signature code was incorrect. | |
2045 | + - CE_NOT_FORMATTED ・ The boot sector signature code was incorrect or | |
2046 | + indicates an invalid number of bytes per sector. | |
2047 | + - CE_CARDFAT32 ・ The physical media is FAT32 type (only an error | |
2048 | + when FAT32 support is disabled). | |
2049 | + - CE_UNSUPPORTED_FS ・ The device is formatted with an unsupported file | |
2050 | + system (not FAT12 or 16). | |
2051 | + FSfopen - | |
2052 | + - CE_GOOD ・ No Error | |
2053 | + - CE_NOT_INIT ・ The device has not been initialized. | |
2054 | + - CE_TOO_MANY_FILES_OPEN ・ The function could not allocate any | |
2055 | + additional file information to the array | |
2056 | + of FSFILE structures or the heap. | |
2057 | + - CE_INVALID_FILENAME ・ The file name argument was invalid. | |
2058 | + - CE_INVALID_ARGUMENT ・ The user attempted to open a directory in a | |
2059 | + write mode or specified an invalid mode argument. | |
2060 | + - CE_FILE_NOT_FOUND ・ The specified file (which was to be opened in read | |
2061 | + mode) does not exist on the device. | |
2062 | + - CE_BADCACHEREAD ・ A read from the device failed. | |
2063 | + - CE_ERASE_FAIL ・ The existing file could not be erased (when opening | |
2064 | + a file in WRITE mode). | |
2065 | + - CE_DIR_FULL ・ The directory is full. | |
2066 | + - CE_DISK_FULL・ The data memory section is full. | |
2067 | + - CE_WRITE_ERROR ・ A write to the device failed. | |
2068 | + - CE_SEEK_ERROR ・ The current position in the file could not be set to | |
2069 | + the end (when the file was opened in APPEND mode). | |
2070 | + FSfclose - | |
2071 | + - CE_GOOD ・ No Error | |
2072 | + - CE_WRITE_ERROR ・ The existing data in the data buffer or the new file | |
2073 | + entry information could not be written to the device. | |
2074 | + - CE_BADCACHEREAD ・ The file entry information could not be cached | |
2075 | + FSfread - | |
2076 | + - CE_GOOD ・ No Error | |
2077 | + - CE_WRITEONLY ・ The file was opened in a write-only mode. | |
2078 | + - CE_WRITE_ERROR ・ The existing data in the data buffer could not be | |
2079 | + written to the device. | |
2080 | + - CE_BAD_SECTOR_READ ・ The data sector could not be read. | |
2081 | + - CE_EOF ・ The end of the file was reached. | |
2082 | + - CE_COULD_NOT_GET_CLUSTER ・Additional clusters in the file could not be loaded. | |
2083 | + FSfwrite - | |
2084 | + - CE_GOOD ・ No Error | |
2085 | + - CE_READONLY ・ The file was opened in a read-only mode. | |
2086 | + - CE_WRITE_PROTECTED ・ The device write-protect check function indicated | |
2087 | + that the device has been write-protected. | |
2088 | + - CE_WRITE_ERROR ・ There was an error writing data to the device. | |
2089 | + - CE_BADCACHEREAD ・ The data sector to be modified could not be read from | |
2090 | + the device. | |
2091 | + - CE_DISK_FULL ・ All data clusters on the device are in use. | |
2092 | + FSfseek - | |
2093 | + - CE_GOOD ・ No Error | |
2094 | + - CE_WRITE_ERROR ・ The existing data in the data buffer could not be | |
2095 | + written to the device. | |
2096 | + - CE_INVALID_ARGUMENT ・ The specified offset exceeds the size of the file. | |
2097 | + - CE_BADCACHEREAD ・ The sector that contains the new current position | |
2098 | + could not be loaded. | |
2099 | + - CE_COULD_NOT_GET_CLUSTER ・Additional clusters in the file could not be | |
2100 | + loaded/allocated. | |
2101 | + FSftell - | |
2102 | + - CE_GOOD ・ No Error | |
2103 | + FSattrib - | |
2104 | + - CE_GOOD ・ No Error | |
2105 | + - CE_INVALID_ARGUMENT ・ The attribute argument was invalid. | |
2106 | + - CE_BADCACHEREAD ・ The existing file entry information could not be | |
2107 | + loaded. | |
2108 | + - CE_WRITE_ERROR ・ The file entry information could not be written to | |
2109 | + the device. | |
2110 | + FSrename - | |
2111 | + - CE_GOOD ・ No Error | |
2112 | + - CE_FILENOTOPENED ・ A null file pointer was passed into the function. | |
2113 | + - CE_INVALID_FILENAME ・ The file name passed into the function was invalid. | |
2114 | + - CE_BADCACHEREAD ・ A read from the device failed. | |
2115 | + - CE_FILENAME_EXISTS ・ A file with the specified name already exists. | |
2116 | + - CE_WRITE_ERROR ・ The new file entry data could not be written to the | |
2117 | + device. | |
2118 | + FSfeof - | |
2119 | + - CE_GOOD ・ No Error | |
2120 | + FSformat - | |
2121 | + - CE_GOOD ・ No Error | |
2122 | + - CE_INIT_ERROR ・ The device could not be initialized. | |
2123 | + - CE_BADCACHEREAD ・ The master boot record or boot sector could not be | |
2124 | + loaded successfully. | |
2125 | + - CE_INVALID_ARGUMENT ・ The user selected to create their own boot sector on | |
2126 | + a device that has no master boot record, or the mode | |
2127 | + argument was invalid. | |
2128 | + - CE_WRITE_ERROR ・ The updated MBR/Boot sector could not be written to | |
2129 | + the device. | |
2130 | + - CE_BAD_PARTITION ・ The calculated number of sectors per clusters was | |
2131 | + invalid. | |
2132 | + - CE_NONSUPPORTED_SIZE ・ The card has too many sectors to be formatted as | |
2133 | + FAT12 or FAT16. | |
2134 | + FSremove - | |
2135 | + - CE_GOOD ・ No Error | |
2136 | + - CE_WRITE_PROTECTED ・ The device write-protect check function indicated | |
2137 | + that the device has been write-protected. | |
2138 | + - CE_INVALID_FILENAME ・ The specified filename was invalid. | |
2139 | + - CE_FILE_NOT_FOUND ・ The specified file could not be found. | |
2140 | + - CE_ERASE_FAIL ・ The file could not be erased. | |
2141 | + FSchdir - | |
2142 | + - CE_GOOD ・ No Error | |
2143 | + - CE_INVALID_ARGUMENT ・ The path string was mis-formed or the user tried to | |
2144 | + change to a non-directory file. | |
2145 | + - CE_BADCACHEREAD ・ A directory entry could not be cached. | |
2146 | + - CE_DIR_NOT_FOUND ・ Could not find a directory in the path. | |
2147 | + FSgetcwd - | |
2148 | + - CE_GOOD ・ No Error | |
2149 | + - CE_INVALID_ARGUMENT ・ The user passed a 0-length buffer into the function. | |
2150 | + - CE_BADCACHEREAD ・ A directory entry could not be cached. | |
2151 | + - CE_BAD_SECTOR_READ ・ The function could not determine a previous directory | |
2152 | + of the current working directory. | |
2153 | + FSmkdir - | |
2154 | + - CE_GOOD ・ No Error | |
2155 | + - CE_WRITE_PROTECTED ・ The device write-protect check function indicated | |
2156 | + that the device has been write-protected. | |
2157 | + - CE_INVALID_ARGUMENT ・ The path string was mis-formed. | |
2158 | + - CE_BADCACHEREAD ・ Could not successfully change to a recently created | |
2159 | + directory to store its dir entry information, or | |
2160 | + could not cache directory entry information. | |
2161 | + - CE_INVALID_FILENAME ・ One or more of the directory names has an invalid | |
2162 | + format. | |
2163 | + - CE_WRITE_ERROR ・ The existing data in the data buffer could not be | |
2164 | + written to the device or the dot/dotdot entries could | |
2165 | + not be written to a newly created directory. | |
2166 | + - CE_DIR_FULL ・ There are no available dir entries in the CWD. | |
2167 | + - CE_DISK_FULL ・ There are no available clusters in the data region of | |
2168 | + the device. | |
2169 | + FSrmdir - | |
2170 | + - CE_GOOD ・ No Error | |
2171 | + - CE_DIR_NOT_FOUND ・ The directory specified could not be found or the | |
2172 | + function could not change to a subdirectory within | |
2173 | + the directory to be deleted (when recursive delete is | |
2174 | + enabled). | |
2175 | + - CE_INVALID_ARGUMENT ・ The user tried to remove the CWD or root directory. | |
2176 | + - CE_BADCACHEREAD ・ A directory entry could not be cached. | |
2177 | + - CE_DIR_NOT_EMPTY ・ The directory to be deleted was not empty and | |
2178 | + recursive subdirectory removal was disabled. | |
2179 | + - CE_ERASE_FAIL ・ The directory or one of the directories or files | |
2180 | + within it could not be deleted. | |
2181 | + - CE_BAD_SECTOR_READ ・ The function could not determine a previous directory | |
2182 | + of the CWD. | |
2183 | + SetClockVars - | |
2184 | + - CE_GOOD ・ No Error | |
2185 | + - CE_INVALID_ARGUMENT ・ The time values passed into the function were | |
2186 | + invalid. | |
2187 | + FindFirst - | |
2188 | + - CE_GOOD ・ No Error | |
2189 | + - CE_INVALID_FILENAME ・ The specified filename was invalid. | |
2190 | + - CE_FILE_NOT_FOUND ・ No file matching the specified criteria was found. | |
2191 | + - CE_BADCACHEREAD ・ The file information for the file that was found | |
2192 | + could not be cached. | |
2193 | + FindNext - | |
2194 | + - CE_GOOD ・ No Error | |
2195 | + - CE_NOT_INIT ・ The SearchRec object was not initialized by a call to | |
2196 | + FindFirst. | |
2197 | + - CE_INVALID_ARGUMENT ・ The SearchRec object was initialized in a different | |
2198 | + directory from the CWD. | |
2199 | + - CE_INVALID_FILENAME ・ The filename is invalid. | |
2200 | + - CE_FILE_NOT_FOUND ・ No file matching the specified criteria was found. | |
2201 | + FSfprintf - | |
2202 | + - CE_GOOD ・ No Error | |
2203 | + - CE_WRITE_ERROR ・ Characters could not be written to the file. | |
2204 | + Description: | |
2205 | + The FSerror function will return the FSerrno variable. This global | |
2206 | + variable will have been set to an error value during the last call of a | |
2207 | + library function. | |
2208 | + Remarks: | |
2209 | + None | |
2210 | + **************************************************************************/ | |
2211 | + | |
2212 | +int FSerror (void); | |
2213 | + | |
2214 | + | |
2215 | +/********************************************************************************* | |
2216 | + Function: | |
2217 | + int FSCreateMBR (unsigned long firstSector, unsigned long numSectors) | |
2218 | + Summary: | |
2219 | + Creates a master boot record | |
2220 | + Conditions: | |
2221 | + The I/O pins for the device have been initialized by the InitIO function. | |
2222 | + Input: | |
2223 | + firstSector - The first sector of the partition on the device (cannot | |
2224 | + be 0; that's the MBR) | |
2225 | + numSectors - The number of sectors available in memory (including the | |
2226 | + MBR) | |
2227 | + Return Values: | |
2228 | + 0 - MBR was created successfully | |
2229 | + EOF - MBR could not be created | |
2230 | + Side Effects: | |
2231 | + None | |
2232 | + Description: | |
2233 | + This function can be used to create a master boot record for a device. Note | |
2234 | + that this function should not be used on a device that is already formatted | |
2235 | + with a master boot record (i.e. most SD cards, CF cards, USB keys). This | |
2236 | + function will fill the global data buffer with appropriate partition information | |
2237 | + for a FAT partition with a type determined by the number of sectors available | |
2238 | + to the partition. It will then write the MBR information to the first sector | |
2239 | + on the device. This function should be followed by a call to FSformat, which | |
2240 | + will create a boot sector, root dir, and FAT appropriate the the information | |
2241 | + contained in the new master boot record. Note that FSformat only supports | |
2242 | + FAT12 and FAT16 formatting at this time, and so cannot be used to format a | |
2243 | + device with more than 0x3FFD5F sectors. | |
2244 | + Remarks: | |
2245 | + This function can damage the device being used, and should not be called | |
2246 | + unless the user is sure about the size of the device and the first sector value. | |
2247 | + *********************************************************************************/ | |
2248 | + | |
2249 | +int FSCreateMBR (unsigned long firstSector, unsigned long numSectors); | |
2250 | + | |
2251 | + | |
2252 | +#ifdef ALLOW_GET_DISK_PROPERTIES | |
2253 | +/********************************************************************************* | |
2254 | + Function: | |
2255 | + void FSGetDiskProperties(FS_DISK_PROPERTIES* properties) | |
2256 | + Summary: | |
2257 | + Allows user to get the disk properties (size of disk, free space, etc) | |
2258 | + Conditions: | |
2259 | + 1) ALLOW_GET_DISK_PROPERTIES must be defined in FSconfig.h | |
2260 | + 2) a FS_DISK_PROPERTIES object must be created before the function is called | |
2261 | + 3) the new_request member of the FS_DISK_PROPERTIES object must be set before | |
2262 | + calling the function for the first time. This will start a new search. | |
2263 | + 4) this function should not be called while there is a file open. Close all | |
2264 | + files before calling this function. | |
2265 | + Input: | |
2266 | + properties - a pointer to a FS_DISK_PROPERTIES object where the results should | |
2267 | + be stored. | |
2268 | + Return Values: | |
2269 | + This function returns void. The properties_status of the previous call of | |
2270 | + this function is located in the properties.status field. This field has | |
2271 | + the following possible values: | |
2272 | + | |
2273 | + FS_GET_PROPERTIES_NO_ERRORS - operation completed without error. Results | |
2274 | + are in the properties object passed into the function. | |
2275 | + FS_GET_PROPERTIES_DISK_NOT_MOUNTED - there is no mounted disk. Results in | |
2276 | + properties object is not valid | |
2277 | + FS_GET_PROPERTIES_CLUSTER_FAILURE - there was a failure trying to read a | |
2278 | + cluster from the drive. The results in the properties object is a partial | |
2279 | + result up until the point of the failure. | |
2280 | + FS_GET_PROPERTIES_STILL_WORKING - the search for free sectors is still in | |
2281 | + process. Continue calling this function with the same properties pointer | |
2282 | + until either the function completes or until the partial results meets the | |
2283 | + application needs. The properties object contains the partial results of | |
2284 | + the search and can be used by the application. | |
2285 | + Side Effects: | |
2286 | + Can cause errors if called when files are open. Close all files before | |
2287 | + calling this function. | |
2288 | + | |
2289 | + Calling this function without setting the new_request member on the first | |
2290 | + call can result in undefined behavior and results. | |
2291 | + | |
2292 | + Calling this function after a result is returned other than | |
2293 | + FS_GET_PROPERTIES_STILL_WORKING can result in undefined behavior and results. | |
2294 | + Description: | |
2295 | + This function returns the information about the mounted drive. The results | |
2296 | + member of the properties object passed into the function is populated with | |
2297 | + the information about the drive. | |
2298 | + | |
2299 | + Before starting a new request, the new_request member of the properties | |
2300 | + input parameter should be set to TRUE. This will initiate a new search | |
2301 | + request. | |
2302 | + | |
2303 | + This function will return before the search is complete with partial results. | |
2304 | + All of the results except the free_clusters will be correct after the first | |
2305 | + call. The free_clusters will contain the number of free clusters found up | |
2306 | + until that point, thus the free_clusters result will continue to grow until | |
2307 | + the entire drive is searched. If an application only needs to know that a | |
2308 | + certain number of bytes is available and doesn't need to know the total free | |
2309 | + size, then this function can be called until the required free size is | |
2310 | + verified. To continue a search, pass a pointer to the same FS_DISK_PROPERTIES | |
2311 | + object that was passed in to create the search. | |
2312 | + | |
2313 | + A new search request sould be made once this function has returned a value | |
2314 | + other than FS_GET_PROPERTIES_STILL_WORKING. Continuing a completed search | |
2315 | + can result in undefined behavior or results. | |
2316 | + | |
2317 | + Typical Usage: | |
2318 | + <code> | |
2319 | + FS_DISK_PROPERTIES disk_properties; | |
2320 | + | |
2321 | + disk_properties.new_request = TRUE; | |
2322 | + | |
2323 | + do | |
2324 | + { | |
2325 | + FSGetDiskProperties(&disk_properties); | |
2326 | + } while (disk_properties.properties_status == FS_GET_PROPERTIES_STILL_WORKING); | |
2327 | + </code> | |
2328 | + | |
2329 | + results.disk_format - contains the format of the drive. Valid results are | |
2330 | + FAT12(1), FAT16(2), or FAT32(3). | |
2331 | + | |
2332 | + results.sector_size - the sector size of the mounted drive. Valid values are | |
2333 | + 512, 1024, 2048, and 4096. | |
2334 | + | |
2335 | + results.sectors_per_cluster - the number sectors per cluster. | |
2336 | + | |
2337 | + results.total_clusters - the number of total clusters on the drive. This | |
2338 | + can be used to calculate the total disk size (total_clusters * | |
2339 | + sectors_per_cluster * sector_size = total size of drive in bytes) | |
2340 | + | |
2341 | + results.free_clusters - the number of free (unallocated) clusters on the drive. | |
2342 | + This can be used to calculate the total free disk size (free_clusters * | |
2343 | + sectors_per_cluster * sector_size = total size of drive in bytes) | |
2344 | + | |
2345 | + Remarks: | |
2346 | + PIC24F size estimates: | |
2347 | + Flash - 400 bytes (-Os setting) | |
2348 | + | |
2349 | + PIC24F speed estimates: | |
2350 | + Search takes approximately 7 seconds per Gigabyte of drive space. Speed | |
2351 | + will vary based on the number of sectors per cluster and the sector size. | |
2352 | + *********************************************************************************/ | |
2353 | +void FSGetDiskProperties(FS_DISK_PROPERTIES* properties); | |
2354 | +#endif | |
2355 | + | |
2356 | + | |
2357 | +#endif |