BASIC compiler/interpreter for PIC32MX/MZ-80K
Revision | 763a11a56ff57be184c7e6a19ab61205c86c3ffb (tree) |
---|---|
Zeit | 2019-04-07 08:59:25 |
Autor | Katsumi <kmorimatsu@sour...> |
Commiter | Katsumi |
Megalopa update for TIMER, INTERRUPT, and OPTION
@@ -157,7 +157,8 @@ char* resolve_unresolved(int class){ | ||
157 | 157 | break; |
158 | 158 | default: |
159 | 159 | return ERR_UNKNOWN; |
160 | - } } | |
160 | + } | |
161 | + } | |
161 | 162 | return 0; |
162 | 163 | } |
163 | 164 |
@@ -194,6 +195,15 @@ char* update_class_info(int class){ | ||
194 | 195 | cstruct[z+1]: public method pointer |
195 | 196 | */ |
196 | 197 | |
198 | +/* | |
199 | + Object structure: | |
200 | + object[0]: pointer to class structure | |
201 | + object[1]: field value | |
202 | + ... | |
203 | + object[n]: field value | |
204 | + (according to class structure; public field(s) first, then private field(s)) | |
205 | +*/ | |
206 | + | |
197 | 207 | char* construct_class_structure(int class){ |
198 | 208 | int* record; |
199 | 209 | int i; |
@@ -110,8 +110,9 @@ int nextCodeIs(char* str){ | ||
110 | 110 | if (!strncmp(g_source+g_srcpos,str,len)) { |
111 | 111 | if ('A'<=str[len-1] && str[len-1]<='Z') { |
112 | 112 | // When the last character of str is alphabet, |
113 | - // the next character in source must be space, enter, or ':'. | |
114 | - if (0x20<g_source[g_srcpos+len] && g_source[g_srcpos+len]!=':') return 0; | |
113 | + // the next character in source must be space, enter, ',', or ':'. | |
114 | + if (0x20<g_source[g_srcpos+len] && | |
115 | + g_source[g_srcpos+len]!=':' && g_source[g_srcpos+len]!=',') return 0; | |
115 | 116 | } |
116 | 117 | // String matches in the current position in source. |
117 | 118 | g_srcpos+=len; |
@@ -160,8 +161,10 @@ char* compile_line(void){ | ||
160 | 161 | printstr(resolve_label(g_line)); |
161 | 162 | return ERR_MULTIPLE_LABEL; |
162 | 163 | } |
163 | - check_obj_space(1); | |
164 | - g_object[g_objpos++]=0x34160000|g_line; //ori s6,zero,xxxx; | |
164 | + if (!g_nolinenum) { | |
165 | + check_obj_space(1); | |
166 | + g_object[g_objpos++]=0x34160000|g_line; //ori s6,zero,xxxx; | |
167 | + } | |
165 | 168 | } |
166 | 169 | while(g_source[g_srcpos]!=0x0D && g_source[g_srcpos]!=0x0A){ |
167 | 170 | err=statement(); |
@@ -213,6 +213,7 @@ extern int g_var_mem[ALLOC_BLOCK_NUM]; | ||
213 | 213 | extern unsigned short g_var_pointer[ALLOC_BLOCK_NUM]; |
214 | 214 | extern unsigned short g_var_size[ALLOC_BLOCK_NUM]; |
215 | 215 | extern char g_temp_area_used; |
216 | +extern char g_nolinenum; | |
216 | 217 | extern int* g_heap_mem; |
217 | 218 | extern int g_max_mem; |
218 | 219 | extern char g_disable_break; |
@@ -221,6 +222,7 @@ extern char g_use_graphic; | ||
221 | 222 | extern unsigned short* g_graphic_area; |
222 | 223 | extern int* g_libparams; |
223 | 224 | extern int g_long_name_var_num; |
225 | +extern char g_music_active; | |
224 | 226 | extern int g_class; |
225 | 227 | extern int g_compiling_class; |
226 | 228 | extern int g_temp; |
@@ -260,6 +262,7 @@ void err_not_field(int fieldname, int classname); | ||
260 | 262 | void err_str(char* str); |
261 | 263 | char* resolve_label(int s6); |
262 | 264 | |
265 | +void musicint(); | |
263 | 266 | void set_sound(unsigned long* data, int flagsLR); |
264 | 267 | int musicRemaining(int flagsLR); |
265 | 268 | int waveRemaining(int mode); |
@@ -367,6 +370,13 @@ char* static_statement(); | ||
367 | 370 | char* static_method(char type); |
368 | 371 | char* resolve_unresolved(int class); |
369 | 372 | |
373 | +void init_timer(); | |
374 | +void stop_timer(); | |
375 | +char* usetimer_statement(); | |
376 | +char* timer_statement(); | |
377 | +char* timer_function(); | |
378 | +char* interrupt_statement(); | |
379 | + | |
370 | 380 | /* Error messages */ |
371 | 381 | #define ERR_SYNTAX (char*)(g_err_str[0]) |
372 | 382 | #define ERR_NE_BINARY (char*)(g_err_str[1]) |
@@ -474,6 +484,25 @@ char* resolve_unresolved(int class); | ||
474 | 484 | #define ASM_LW_A0_XXXX_S8 0x8FC40000 |
475 | 485 | #define ASM_LW_A0_XXXX_S5 0x8EA40000 |
476 | 486 | |
487 | +// Interrupt macros | |
488 | +// 32 different type interruptions are possible | |
489 | +// See also envspecific.h for additional interruptions | |
490 | +#define INTERRUPT_TIMER 0 | |
491 | +#define INTERRUPT_DRAWCOUNT 1 | |
492 | +#define INTERRUPT_KEYS 2 | |
493 | +#define INTERRUPT_INKEY 3 | |
494 | +#define INTERRUPT_MUSIC 4 | |
495 | +#define INTERRUPT_WAVE 5 | |
496 | + | |
497 | +extern int g_interrupt_flags; | |
498 | +extern int g_int_vector[]; | |
499 | +#define raise_interrupt_flag(x) do {\ | |
500 | + if (g_int_vector[x]) {\ | |
501 | + IFS0bits.CS1IF=1;\ | |
502 | + g_interrupt_flags|=(1<<(x));\ | |
503 | + }\ | |
504 | +} while(0) | |
505 | + | |
477 | 506 | // Division macro for unsigned long |
478 | 507 | // Valid for 31 bits for all cases and 32 bits for some cases |
479 | 508 | #define div32(x,y,z) ((((unsigned long long)((unsigned long)(x)))*((unsigned long long)((unsigned long)(y))))>>(z)) |
@@ -228,11 +228,14 @@ static const char initext[]= | ||
228 | 228 | "#PRINT\n"; |
229 | 229 | |
230 | 230 | static const char bastext[]= |
231 | -"print getdir$()\n" | |
232 | -"end\n" | |
233 | -"\n" | |
231 | +"I=1:WHILE I<=10\n" | |
232 | +"I=I+1:WEND\n" | |
234 | 233 | "\n" |
234 | +"I=1:DO\n" | |
235 | +"I=I+1:LOOP UNTIL I=11\n" | |
235 | 236 | "\n" |
237 | +"FOR I=1 TO 10\n" | |
238 | +"NEXT\n" | |
236 | 239 | "\n" |
237 | 240 | "\n" |
238 | 241 | "\n"; |
@@ -268,12 +271,10 @@ static const void* debugjumptable[]={ | ||
268 | 271 | FSfopen, |
269 | 272 | }; |
270 | 273 | |
274 | +#define for2(x,y,z) for(x=y;x<=z;x++) | |
275 | + | |
271 | 276 | int _debug_test(int a0, int a1, int a2, int a3, int param4, int param5){ |
272 | 277 | asm volatile(".set noreorder"); |
273 | - asm volatile("lw $a0,4($s5)"); | |
274 | - asm volatile("lw $a1,8($s5)"); | |
275 | - asm volatile("lw $a2,12($s5)"); | |
276 | - asm volatile("lw $a3,16($s5)"); | |
277 | 278 | asm volatile("nop"); |
278 | 279 | asm volatile("nop"); |
279 | 280 | asm volatile("nop"); |
@@ -281,6 +282,12 @@ int _debug_test(int a0, int a1, int a2, int a3, int param4, int param5){ | ||
281 | 282 | asm volatile("nop"); |
282 | 283 | asm volatile("nop"); |
283 | 284 | asm volatile("nop"); |
285 | + asm volatile("nop"); | |
286 | + asm volatile("nop"); | |
287 | + asm volatile("nop"); | |
288 | + asm volatile("nop"); | |
289 | + asm volatile("nop"); | |
290 | + a2&=0xFFFFFFFC; | |
284 | 291 | return a2+a3; |
285 | 292 | } |
286 | 293 |
@@ -8,6 +8,7 @@ | ||
8 | 8 | // Megalopa uses I/O statements/functions |
9 | 9 | #include "io.h" |
10 | 10 | |
11 | +#define CPU_CLOCK_HZ 95454533 | |
11 | 12 | #define PERSISTENT_RAM_SIZE (1024*100) |
12 | 13 | |
13 | 14 | int readbuttons(); |
@@ -108,3 +109,5 @@ enum extra{ | ||
108 | 109 | EXTRA_SPISWAPDATA =EXTRA_STEP*25, |
109 | 110 | // MAX 63 |
110 | 111 | }; |
112 | + | |
113 | +#define ADDITIONAL_INTERRUPT_FUNCTIONS |
@@ -44,7 +44,12 @@ void dumpMemory(){ | ||
44 | 44 | void dumpMemory(){} |
45 | 45 | #endif //ifdef DUMPFILE |
46 | 46 | |
47 | +void _general_exception_handler_main (void); | |
47 | 48 | void _general_exception_handler (void){ |
49 | + asm volatile("la $sp,%0"::"i"(&RAM[RAMSIZE-4])); | |
50 | + asm volatile("j _general_exception_handler_main"); | |
51 | +} | |
52 | +void _general_exception_handler_main (void){ | |
48 | 53 | int i; |
49 | 54 | // $v1 is g_ex_data |
50 | 55 | asm volatile("la $v1,%0"::"i"(&g_ex_data[0])); |
@@ -79,7 +84,9 @@ void _general_exception_handler (void){ | ||
79 | 84 | if((readbuttons()&(KEYUP|KEYDOWN|KEYLEFT|KEYRIGHT|KEYSTART|KEYFIRE)) |
80 | 85 | !=(KEYUP|KEYDOWN|KEYLEFT|KEYRIGHT|KEYSTART|KEYFIRE)) i=0; |
81 | 86 | } |
82 | - asm volatile("j SoftReset"); | |
87 | + RCONbits.POR=0; | |
88 | + RCONbits.EXTR=0; | |
89 | + asm volatile("j 0x9FC00000"); | |
83 | 90 | #endif |
84 | 91 | } |
85 | 92 |
@@ -122,7 +122,10 @@ int compile_and_link_file(char* buff,char* appname){ | ||
122 | 122 | printchar('\n'); |
123 | 123 | return -1; |
124 | 124 | } |
125 | - | |
125 | + | |
126 | + // Option initialization(s) | |
127 | + g_nolinenum=0; | |
128 | + | |
126 | 129 | // Compile the file |
127 | 130 | err=compile_file(); |
128 | 131 | close_file(); |
@@ -157,7 +157,6 @@ char* rnd_function(){ | ||
157 | 157 | return 0; |
158 | 158 | } |
159 | 159 | |
160 | - | |
161 | 160 | char* chr_function(void){ |
162 | 161 | char* err; |
163 | 162 | err=get_value(); |
@@ -597,6 +596,7 @@ static const void* int_func_list[]={ | ||
597 | 596 | "PLAYWAVE(",playwave_function, |
598 | 597 | "NEW(",new_function, |
599 | 598 | "SETDIR(",setdir_function, |
599 | + "TIMER(",timer_function, | |
600 | 600 | // Additional functions follow |
601 | 601 | ADDITIONAL_INT_FUNCTIONS |
602 | 602 | }; |
@@ -55,6 +55,9 @@ unsigned short g_var_size[ALLOC_BLOCK_NUM]; | ||
55 | 55 | // Flag to use temporary area when compiling |
56 | 56 | char g_temp_area_used; |
57 | 57 | |
58 | +// Flag to use option nolinenum | |
59 | +char g_nolinenum; | |
60 | + | |
58 | 61 | // Heap area |
59 | 62 | int* g_heap_mem; |
60 | 63 | int g_max_mem; |
@@ -80,6 +83,9 @@ int* g_libparams; | ||
80 | 83 | // Number of long name variables |
81 | 84 | int g_long_name_var_num; |
82 | 85 | |
86 | +// Flag for active music/sound/wave function | |
87 | +char g_music_active; | |
88 | + | |
83 | 89 | // Class name being compiled |
84 | 90 | int g_class; |
85 | 91 | // Flag to compile class file |
@@ -71,6 +71,7 @@ file_043=. | ||
71 | 71 | file_044=. |
72 | 72 | file_045=. |
73 | 73 | file_046=. |
74 | +file_047=. | |
74 | 75 | [GENERATED_FILES] |
75 | 76 | file_000=no |
76 | 77 | file_001=no |
@@ -119,6 +120,7 @@ file_043=no | ||
119 | 120 | file_044=no |
120 | 121 | file_045=no |
121 | 122 | file_046=no |
123 | +file_047=no | |
122 | 124 | [OTHER_FILES] |
123 | 125 | file_000=no |
124 | 126 | file_001=no |
@@ -163,10 +165,11 @@ file_039=no | ||
163 | 165 | file_040=no |
164 | 166 | file_041=no |
165 | 167 | file_042=no |
166 | -file_043=yes | |
168 | +file_043=no | |
167 | 169 | file_044=yes |
168 | 170 | file_045=yes |
169 | 171 | file_046=yes |
172 | +file_047=yes | |
170 | 173 | [FILE_INFO] |
171 | 174 | file_000=compiler.c |
172 | 175 | file_001=debug.c |
@@ -196,25 +199,26 @@ file_024=spi.c | ||
196 | 199 | file_025=class.c |
197 | 200 | file_026=args.c |
198 | 201 | file_027=interface\keyinput.c |
199 | -file_028=api.h | |
200 | -file_029=compiler.h | |
201 | -file_030=debug.h | |
202 | -file_031=editor.h | |
203 | -file_032=main.h | |
204 | -file_033=envspecific.h | |
205 | -file_034=io.h | |
206 | -file_035=interface\keyinput.h | |
207 | -file_036=interface\lib_video_megalopa.h | |
208 | -file_037=interface\ps2keyboard.h | |
209 | -file_038=interface\sdfsio370f.h | |
210 | -file_039=interface\lib_videoout_megalopa.X.a | |
211 | -file_040=interface\ps2keyboard370f.X.a | |
212 | -file_041=interface\sdfsio370fLib.X.a | |
213 | -file_042=app_p32MX370F512H.ld | |
214 | -file_043=help.txt | |
215 | -file_044=reservednames.js | |
216 | -file_045=class.txt | |
217 | -file_046=sharedfiles.js | |
202 | +file_028=timer.c | |
203 | +file_029=api.h | |
204 | +file_030=compiler.h | |
205 | +file_031=debug.h | |
206 | +file_032=editor.h | |
207 | +file_033=main.h | |
208 | +file_034=envspecific.h | |
209 | +file_035=io.h | |
210 | +file_036=interface\keyinput.h | |
211 | +file_037=interface\lib_video_megalopa.h | |
212 | +file_038=interface\ps2keyboard.h | |
213 | +file_039=interface\sdfsio370f.h | |
214 | +file_040=interface\lib_videoout_megalopa.X.a | |
215 | +file_041=interface\ps2keyboard370f.X.a | |
216 | +file_042=interface\sdfsio370fLib.X.a | |
217 | +file_043=app_p32MX370F512H.ld | |
218 | +file_044=help.txt | |
219 | +file_045=reservednames.js | |
220 | +file_046=class.txt | |
221 | +file_047=sharedfiles.js | |
218 | 222 | [SUITE_INFO] |
219 | 223 | suite_guid={62D235D8-2DB2-49CD-AF24-5489A6015337} |
220 | 224 | suite_state= |
@@ -142,7 +142,6 @@ int waveRemaining(int mode){ | ||
142 | 142 | return ret; |
143 | 143 | } |
144 | 144 | |
145 | -#pragma interrupt musicint IPL2SOFT vector 1 | |
146 | 145 | void musicint(){ |
147 | 146 | static unsigned short wavtable_pos; |
148 | 147 | static int music_freq_L=0; |
@@ -151,7 +150,6 @@ void musicint(){ | ||
151 | 150 | static int music_timer_R=0; |
152 | 151 | unsigned int i,j; |
153 | 152 | // This function is called every 1/60 sec. |
154 | - IFS0bits.CS0IF=0; | |
155 | 153 | switch(g_sound_mode){ |
156 | 154 | case SOUND_MODE_WAVE: |
157 | 155 | // Initialize parameters |
@@ -169,6 +167,8 @@ void musicint(){ | ||
169 | 167 | g_fhandle=0; |
170 | 168 | g_sound_mode=SOUND_MODE_NONE; |
171 | 169 | stop_music(); |
170 | + // Raise WAVE interrupt flag | |
171 | + raise_interrupt_flag(INTERRUPT_WAVE); | |
172 | 172 | break; |
173 | 173 | } |
174 | 174 | // Continue to MUSIC sound mode |
@@ -197,6 +197,10 @@ void musicint(){ | ||
197 | 197 | g_musicstartL++; |
198 | 198 | g_musicstartL&=31; |
199 | 199 | g_musicwaitL=g_musiclenL[g_musicstartL]; |
200 | + if (((g_musicstartL+1)&31)==g_musicendL) { | |
201 | + // Raise MUSIC interrupt flag | |
202 | + raise_interrupt_flag(INTERRUPT_MUSIC); | |
203 | + } | |
200 | 204 | } |
201 | 205 | } |
202 | 206 | } else if (g_musicstartL!=g_musicendL) { |
@@ -206,6 +210,10 @@ void musicint(){ | ||
206 | 210 | g_musicstartL++; |
207 | 211 | g_musicstartL&=31; |
208 | 212 | g_musicwaitL=g_musiclenL[g_musicstartL]; |
213 | + if (((g_musicstartL+1)&31)==g_musicendL) { | |
214 | + // Raise MUSIC interrupt flag | |
215 | + raise_interrupt_flag(INTERRUPT_MUSIC); | |
216 | + } | |
209 | 217 | } |
210 | 218 | } else { |
211 | 219 | music_freq_L=0; |
@@ -234,6 +242,10 @@ void musicint(){ | ||
234 | 242 | g_musicstartR++; |
235 | 243 | g_musicstartR&=31; |
236 | 244 | g_musicwaitR=g_musiclenR[g_musicstartR]; |
245 | + if (((g_musicstartR+1)&31)==g_musicendR) { | |
246 | + // Raise MUSIC interrupt flag | |
247 | + raise_interrupt_flag(INTERRUPT_MUSIC); | |
248 | + } | |
237 | 249 | } |
238 | 250 | } |
239 | 251 | } else if (g_musicstartR!=g_musicendR) { |
@@ -243,6 +255,10 @@ void musicint(){ | ||
243 | 255 | g_musicstartR++; |
244 | 256 | g_musicstartR&=31; |
245 | 257 | g_musicwaitR=g_musiclenR[g_musicstartR]; |
258 | + if (((g_musicstartR+1)&31)==g_musicendR) { | |
259 | + // Raise MUSIC interrupt flag | |
260 | + raise_interrupt_flag(INTERRUPT_MUSIC); | |
261 | + } | |
246 | 262 | } |
247 | 263 | } else { |
248 | 264 | music_freq_R=0; |
@@ -420,11 +436,6 @@ void init_music(){ | ||
420 | 436 | |
421 | 437 | // Move OC4RS and OC3 RS from 0x00 to 0x80 |
422 | 438 | 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 | 439 | } |
429 | 440 | |
430 | 441 | void musicSetL(){ |
@@ -629,6 +640,7 @@ void set_sound(unsigned long* data, int flagsLR){ | ||
629 | 640 | if (flagsLR & MFLAG_L) g_soundwaitL=g_soundlenL[0]; |
630 | 641 | if (flagsLR & MFLAG_R) g_soundwaitR=g_soundlenR[0]; |
631 | 642 | IEC0bits.CS0IE=1; // Restart interrupt. |
643 | + g_music_active=1;// Activate music system | |
632 | 644 | } |
633 | 645 | |
634 | 646 | void set_music(char* str, int flagsLR){ |
@@ -741,6 +753,7 @@ void set_music(char* str, int flagsLR){ | ||
741 | 753 | // Go to next character |
742 | 754 | while(0<g_mstr[g_mspos] && g_mstr[g_mspos]<=0x20 || g_mstr[g_mspos]=='|') g_mspos++; |
743 | 755 | } |
756 | + g_music_active=1;// Activate music system | |
744 | 757 | } |
745 | 758 | |
746 | 759 | /* |
@@ -886,6 +899,7 @@ void play_wave(char* filename, int start){ | ||
886 | 899 | // Enable intterupt |
887 | 900 | IFS0bits.CS0IF=0; |
888 | 901 | IEC0bits.CS0IE=1; |
902 | + g_music_active=1;// Activate music system | |
889 | 903 | } |
890 | 904 | |
891 | 905 | void stop_music(){ |
@@ -899,4 +913,6 @@ void stop_music(){ | ||
899 | 913 | FSfclose(g_fhandle); |
900 | 914 | g_fhandle=0; |
901 | 915 | } |
916 | + // Inactive music | |
917 | + g_music_active=0; | |
902 | 918 | } |
@@ -110,6 +110,7 @@ var namearray=[ | ||
110 | 110 | 'NEXT', |
111 | 111 | 'NEW', |
112 | 112 | 'NOT', |
113 | + 'OPTION', | |
113 | 114 | 'PCG', |
114 | 115 | 'PEEK', |
115 | 116 | 'PEEK16', |
@@ -138,6 +139,7 @@ var namearray=[ | ||
138 | 139 | 'SYSTEM', |
139 | 140 | 'TAN', |
140 | 141 | 'TANH', |
142 | + 'TIMER', | |
141 | 143 | 'TVRAM', |
142 | 144 | 'UNTIL', |
143 | 145 | 'USEPCG', |
@@ -116,6 +116,7 @@ int runbasic(char *appname,int test){ | ||
116 | 116 | |
117 | 117 | // Warm up environment |
118 | 118 | pre_run(); |
119 | + init_timer(); | |
119 | 120 | |
120 | 121 | // Execute program |
121 | 122 | // Start program from the beginning of RAM. |
@@ -126,6 +127,7 @@ int runbasic(char *appname,int test){ | ||
126 | 127 | // Cool down environment |
127 | 128 | post_run(); |
128 | 129 | lib_file(FUNC_FINIT,0,0,0); |
130 | + stop_timer(); | |
129 | 131 | |
130 | 132 | return 0; |
131 | 133 | } |
@@ -28,6 +28,7 @@ var filearray=[ | ||
28 | 28 | 'run.c', |
29 | 29 | 'string.c', |
30 | 30 | 'statement.c', |
31 | + 'timer.c', | |
31 | 32 | 'value.c', |
32 | 33 | 'varname.c', |
33 | 34 | 'compiler.h', |
@@ -1550,6 +1550,24 @@ char* setdir_statement(){ | ||
1550 | 1550 | return 0; |
1551 | 1551 | } |
1552 | 1552 | |
1553 | +char* option_statement(){ | |
1554 | + while(1){ | |
1555 | + next_position(); | |
1556 | + if (nextCodeIs("NOLINENUM")) { | |
1557 | + g_nolinenum=1; | |
1558 | + } else { | |
1559 | + return ERR_SYNTAX; | |
1560 | + } | |
1561 | + next_position(); | |
1562 | + if (g_source[g_srcpos]==',') { | |
1563 | + g_srcpos++; | |
1564 | + } else { | |
1565 | + break; | |
1566 | + } | |
1567 | + } | |
1568 | + return 0; | |
1569 | +} | |
1570 | + | |
1553 | 1571 | #ifdef __DEBUG |
1554 | 1572 | char* debug_statement(){ |
1555 | 1573 | call_lib_code(LIB_DEBUG); |
@@ -1698,6 +1716,10 @@ static const void* statement_list[]={ | ||
1698 | 1716 | "CALL ",call_statement, |
1699 | 1717 | "STATIC ",static_statement, |
1700 | 1718 | "SETDIR ",setdir_statement, |
1719 | + "OPTION ",option_statement, | |
1720 | + "USETIMER ",usetimer_statement, | |
1721 | + "TIMER ",timer_statement, | |
1722 | + "INTERRUPT ",interrupt_statement, | |
1701 | 1723 | // List of additional statements follows |
1702 | 1724 | ADDITIONAL_STATEMENTS |
1703 | 1725 | }; |
@@ -0,0 +1,326 @@ | ||
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 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
12 | +#include <xc.h> | |
13 | +#include "compiler.h" | |
14 | +#include "api.h" | |
15 | + | |
16 | +/* | |
17 | + 32 different type interruptions are possible. | |
18 | + See definition in compiler.h like: | |
19 | + #define INTERRUPT_TIMER 0 | |
20 | + extern int g_interrupt_flags; | |
21 | + extern int g_int_vector[]; | |
22 | + #define raise_interrupt_flag(x) do {\ | |
23 | +*/ | |
24 | + | |
25 | +// Timer value that increments every timer event | |
26 | +static int g_timer; | |
27 | + | |
28 | +// Interrupt types | |
29 | +static const void* interrupt_list[]={ | |
30 | + "TIMER", (void*)INTERRUPT_TIMER, | |
31 | + "DRAWCOUNT",(void*)INTERRUPT_DRAWCOUNT, | |
32 | + "KEYS", (void*)INTERRUPT_KEYS, | |
33 | + "INKEY", (void*)INTERRUPT_INKEY, | |
34 | + "MUSIC", (void*)INTERRUPT_MUSIC, | |
35 | + "WAVE", (void*)INTERRUPT_WAVE, | |
36 | + ADDITIONAL_INTERRUPT_FUNCTIONS | |
37 | +}; | |
38 | +#define NUM_INTERRUPT_TYPES ((sizeof(interrupt_list)/sizeof(interrupt_list[0]))/2) | |
39 | +// Flags for interrupt | |
40 | +int g_interrupt_flags; | |
41 | +// Jump address when interrupt | |
42 | +int g_int_vector[NUM_INTERRUPT_TYPES]; | |
43 | + | |
44 | +/* | |
45 | + Initialize and termination | |
46 | +*/ | |
47 | + | |
48 | +void init_timer(){ | |
49 | + int i; | |
50 | + // Stop timer, first | |
51 | + T1CON=0x0000; | |
52 | + IEC0bits.T1IE=0; | |
53 | + TMR1=0; | |
54 | + PR1=0xffff; | |
55 | + g_timer=0; | |
56 | + // Disable interrupt | |
57 | + IEC0bits.CS1IE=0; | |
58 | + for(i=0;i<NUM_INTERRUPT_TYPES;i++) g_int_vector[i]=0; | |
59 | + // CS0 interrupt every 1/60 sec (triggered by Timer2) | |
60 | + IPC0bits.CS0IP=3; | |
61 | + IPC0bits.CS0IS=0; | |
62 | + IFS0bits.CS0IF=0; | |
63 | + IEC0bits.CS0IE=1; | |
64 | +} | |
65 | + | |
66 | +void stop_timer(){ | |
67 | + // Stop timer | |
68 | + T1CON=0x0000; | |
69 | + IEC0bits.T1IE=0; | |
70 | + // Disable interrupt | |
71 | + IEC0bits.CS1IE=0; | |
72 | +} | |
73 | + | |
74 | +/* | |
75 | + Timer interprtation | |
76 | +*/ | |
77 | + | |
78 | +// Interrupt handler | |
79 | +#ifndef __DEBUG | |
80 | + // Timer1 is also used for debug mode | |
81 | + #pragma interrupt T1Handler IPL2SOFT vector 4 | |
82 | +#endif | |
83 | +void T1Handler(void){ | |
84 | + g_timer++; | |
85 | + // Clear Timer1 interrupt flag | |
86 | + IFS0bits.T1IF=0; | |
87 | + // Raise TIMER interrupt flag | |
88 | + raise_interrupt_flag(INTERRUPT_TIMER); | |
89 | +} | |
90 | + | |
91 | +void lib_usetimer(int hz){ | |
92 | + int temppr1; | |
93 | + // Stop timer, first | |
94 | + T1CON=0x0000; | |
95 | + IEC0bits.T1IE=0; | |
96 | + TMR1=0; | |
97 | + PR1=0xffff; | |
98 | + if (!hz) { | |
99 | + return; | |
100 | + } | |
101 | + // PR1 setting | |
102 | + temppr1=CPU_CLOCK_HZ/hz; | |
103 | + if (temppr1<=65536) { | |
104 | + // no prescaler | |
105 | + T1CON=0x0000; | |
106 | + PR1=temppr1-1; | |
107 | + } else if ((temppr1>>3)<=65536) { | |
108 | + // 1/8 prescaler | |
109 | + T1CON=0x0010; | |
110 | + PR1=(temppr1>>3)-1; | |
111 | + } else if ((temppr1>>6)<=65536) { | |
112 | + // 1/64 prescaler | |
113 | + T1CON=0x0020; | |
114 | + PR1=(temppr1>>6)-1; | |
115 | + } else if ((temppr1>>8)<=65536) { | |
116 | + // 1/256 prescaler | |
117 | + T1CON=0x0030; | |
118 | + PR1=(temppr1>>8)-1; | |
119 | + } else { | |
120 | + err_invalid_param(); | |
121 | + } | |
122 | + // Timer1 interrupt: priority 2 | |
123 | + IPC1bits.T1IP=2; | |
124 | + IPC1bits.T1IS=0; | |
125 | + IEC0bits.T1IE=1; | |
126 | + // Start timer | |
127 | + T1CONbits.ON=1; | |
128 | +} | |
129 | + | |
130 | +char* usetimer_statement(){ | |
131 | + char* err; | |
132 | + err=get_value(); | |
133 | + if (err) return err; | |
134 | + call_quicklib_code(lib_usetimer,ASM_ADDU_A0_V0_ZERO); | |
135 | + return 0; | |
136 | +} | |
137 | + | |
138 | +char* timer_statement(){ | |
139 | + int i; | |
140 | + char* err; | |
141 | + err=get_value(); | |
142 | + if (err) return err; | |
143 | + i=(int)(&g_timer); | |
144 | + check_obj_space(3); | |
145 | + g_object[g_objpos++]=0x3C030000|((i>>16)&0x0000FFFF); // lui v1,xxxx | |
146 | + g_object[g_objpos++]=0x34630000|(i&0x0000FFFF); // ori v1,v1,xxxx | |
147 | + g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
148 | + return 0; | |
149 | +} | |
150 | + | |
151 | +char* timer_function(){ | |
152 | + int i; | |
153 | + i=(int)(&g_timer); | |
154 | + check_obj_space(3); | |
155 | + g_object[g_objpos++]=0x3C020000|((i>>16)&0x0000FFFF); // lui v0,xxxx | |
156 | + g_object[g_objpos++]=0x34420000|(i&0x0000FFFF); // ori v0,v0,xxxx | |
157 | + g_object[g_objpos++]=0x8C420000; // lw v0,0(v0) | |
158 | + return 0; | |
159 | +} | |
160 | + | |
161 | +/* | |
162 | + Interrupt interprtation | |
163 | + To cause interruption, use raise_interrupt_flag() macro | |
164 | + For example, | |
165 | + raise_interrupt_flag(INTERRUPT_TIMER); | |
166 | + | |
167 | +*/ | |
168 | + | |
169 | +void BasicInt(int addr){ | |
170 | + // Note that $s0-$s7 values must be set again here. | |
171 | + asm volatile(".set noreorder"); | |
172 | + // Set s5 for initial_s5_stack | |
173 | + asm volatile("la $s5,%0"::"i"(&g_initial_s5_stack[2])); | |
174 | + // Set s7 for easy calling call_library() | |
175 | + asm volatile("la $s7,%0"::"i"(&call_library)); | |
176 | + // $a0 is the address in BASIC code | |
177 | + asm volatile("jr $a0"); | |
178 | + asm volatile("nop"); | |
179 | +} | |
180 | +#pragma interrupt CS1Handler IPL1SOFT vector 2 | |
181 | +void CS1Handler(void){ | |
182 | + int i; | |
183 | + // Store s0-s7, fp, and ra in stacks | |
184 | + asm volatile("#":::"s0"); | |
185 | + asm volatile("#":::"s1"); | |
186 | + asm volatile("#":::"s2"); | |
187 | + asm volatile("#":::"s3"); | |
188 | + asm volatile("#":::"s4"); | |
189 | + asm volatile("#":::"s5"); | |
190 | + asm volatile("#":::"s6"); | |
191 | + asm volatile("#":::"s7"); | |
192 | + asm volatile("#":::"fp"); | |
193 | + asm volatile("#":::"ra"); | |
194 | + while(g_interrupt_flags){ | |
195 | + for(i=0;i<NUM_INTERRUPT_TYPES;i++){ | |
196 | + if (g_interrupt_flags & (1<<i)) { | |
197 | + if (g_int_vector[i]) BasicInt(g_int_vector[i]); | |
198 | + g_interrupt_flags &= (1<<i)^0xffff; | |
199 | + } | |
200 | + } | |
201 | + } | |
202 | + IFS0bits.CS1IF=0; | |
203 | +} | |
204 | + | |
205 | +void lib_interrupt_main(int itype, int address){ | |
206 | + // Set address | |
207 | + g_int_vector[itype]=address; | |
208 | + // CS1 interrupt: priority 1 | |
209 | + IPC0bits.CS1IP=1; | |
210 | + IPC0bits.CS1IS=0; | |
211 | + IEC0bits.CS1IE=1; | |
212 | +} | |
213 | + | |
214 | +void lib_interrupt(int itype){ | |
215 | + // $ra contains the address for interrupt | |
216 | + // $ra is 2 word before the interrupt address | |
217 | + asm volatile("addiu $a1,$ra,8"); | |
218 | + asm volatile("j lib_interrupt_main"); | |
219 | +} | |
220 | + | |
221 | +char* interrupt_statement(){ | |
222 | + int itype; | |
223 | + int i,opos; | |
224 | + char* err; | |
225 | + int stop=0; | |
226 | + // Check if STOP | |
227 | + stop=nextCodeIs("STOP "); | |
228 | + // Seek the interrupt | |
229 | + for (i=0;i<NUM_INTERRUPT_TYPES;i++){ | |
230 | + if (nextCodeIs((char*)interrupt_list[i*2])) break; | |
231 | + } | |
232 | + if (i<NUM_INTERRUPT_TYPES) { | |
233 | + // Interrupt found | |
234 | + itype=(int)interrupt_list[i*2+1]; | |
235 | + } else { | |
236 | + // Interrupt not found | |
237 | + return ERR_SYNTAX; | |
238 | + } | |
239 | + // Compile INTERRUPT STOP | |
240 | + if (stop) { | |
241 | + // g_int_vector[itype]=0; | |
242 | + i=(int)(&g_int_vector[itype]); | |
243 | + i-=g_gp; | |
244 | + check_obj_space(1); | |
245 | + g_object[g_objpos++]=0xAF800000|(i&0x0000FFFF); // sw zero,xxxx(gp) | |
246 | + return 0; | |
247 | + } | |
248 | + // Detect ',' | |
249 | + next_position(); | |
250 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
251 | + g_srcpos++; | |
252 | + // Store address to call | |
253 | + call_quicklib_code(lib_interrupt,ASM_ORI_A0_ZERO_|itype); | |
254 | + check_obj_space(4); | |
255 | + // Skip the region used for interrupt-calling | |
256 | + opos=g_objpos; | |
257 | + g_object[g_objpos++]=0x10000000; // b xxxxx | |
258 | + g_object[g_objpos++]=0x00000000; // nop | |
259 | + // Begin interrupt-calling region | |
260 | + // Store $ra | |
261 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
262 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
263 | + // Compile as GOSUB statement | |
264 | + err=gosub_statement(); | |
265 | + if (err) return err; | |
266 | + // Retore $ra and return | |
267 | + check_obj_space(3); | |
268 | + g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
269 | + g_object[g_objpos++]=0x03E00008; // jr ra | |
270 | + g_object[g_objpos++]=0x08320004; // addiu sp,sp,4 | |
271 | + // End interrupt-calling region | |
272 | + // Complete B assembly | |
273 | + g_object[opos]|=g_objpos-opos-1; | |
274 | + return 0; | |
275 | +} | |
276 | + | |
277 | +/* | |
278 | + CS0 interrupt | |
279 | + IPL3SOFT vector 1 | |
280 | + | |
281 | + This interrupt is always active. Therefore, Do things as few as possible. | |
282 | + 1) Call music function if needed. | |
283 | + MUSIC interrupt is taken by music.c | |
284 | + 2) Check buttons for KEYS interrupt | |
285 | + 3) Check PS/2 for INKEY interrupt | |
286 | + 4) DRAWCOUNT interrupt | |
287 | +*/ | |
288 | + | |
289 | +const int* keystatus=(int*)&ps2keystatus[0]; | |
290 | + | |
291 | +#pragma interrupt CS0Handler IPL3SOFT vector 1 | |
292 | +void CS0Handler(void){ | |
293 | + static int s_keys=-1; | |
294 | + static char s_inkey=0; | |
295 | + int i; | |
296 | + IFS0bits.CS0IF=0; | |
297 | + // Call music function | |
298 | + if (g_music_active) musicint(); | |
299 | + // The interrupts are valid only when CS1 is active | |
300 | + if (IEC0bits.CS1IE) { | |
301 | + // Raise DRAWCOUNT interrupt flag | |
302 | + raise_interrupt_flag(INTERRUPT_DRAWCOUNT); | |
303 | + // Check buttons | |
304 | + if (0<=s_keys && s_keys!=(KEYPORT&(KEYUP|KEYDOWN|KEYLEFT|KEYRIGHT|KEYSTART|KEYFIRE))) { | |
305 | + // Raise KEYS interrupt flag | |
306 | + raise_interrupt_flag(INTERRUPT_KEYS); | |
307 | + } | |
308 | + s_keys=KEYPORT&(KEYUP|KEYDOWN|KEYLEFT|KEYRIGHT|KEYSTART|KEYFIRE); | |
309 | + // Check PS/2 keyboard down | |
310 | + if (g_int_vector[INTERRUPT_INKEY]) { | |
311 | + for(i=0;i<64;i++){ | |
312 | + if (keystatus[i]) { | |
313 | + // Raise INKEY interrupt flag | |
314 | + if (!s_inkey) raise_interrupt_flag(INTERRUPT_INKEY); | |
315 | + break; | |
316 | + } | |
317 | + } | |
318 | + s_inkey=(i==64) ? 0:1; | |
319 | + } | |
320 | + } | |
321 | +} | |
322 | +/* | |
323 | + for(i=0;i<256;i++){ | |
324 | + if (ps2keystatus[i]) return i; | |
325 | + } | |
326 | +*/ |
@@ -91,6 +91,7 @@ static const int reserved_var_names[]={ | ||
91 | 91 | 0x000b4321, /*NEXT*/ |
92 | 92 | 0x000148f8, /*NEW*/ |
93 | 93 | 0x00014a5d, /*NOT*/ |
94 | + 0x38a658d7, /*OPTION*/ | |
94 | 95 | 0x000152c0, /*PCG*/ |
95 | 96 | 0x000cacec, /*PEEK*/ |
96 | 97 | 0x3b1c6aea, /*PEEK16*/ |
@@ -119,6 +120,7 @@ static const int reserved_var_names[]={ | ||
119 | 120 | 0x47f711de, /*SYSTEM*/ |
120 | 121 | 0x000166bf, /*TAN*/ |
121 | 122 | 0x000f72ed, /*TANH*/ |
123 | + 0x020ed5f3, /*TIMER*/ | |
122 | 124 | 0x02182fee, /*TVRAM*/ |
123 | 125 | 0x022c2a2d, /*UNTIL*/ |
124 | 126 | 0x4e8887d0, /*USEPCG*/ |
@@ -28,6 +28,7 @@ var filearray=[ | ||
28 | 28 | 'run.c', |
29 | 29 | 'string.c', |
30 | 30 | 'statement.c', |
31 | + 'timer.c', | |
31 | 32 | 'value.c', |
32 | 33 | 'varname.c', |
33 | 34 | 'compiler.h', |