revision 948:545c85cc56f1
summary |
tree |
shortlog |
changelog |
graph |
changeset |
raw | bz2 | zip | gz changeset | 948:545c85cc56f1 |
parent | 947:aa80962d6439 |
child | 949:d7833018931f |
author | nkeynes |
date | Wed Jan 07 04:39:04 2009 +0000 (15 years ago) |
branch | lxdream-mem |
Introduce sh4_finalize_instruction to clean-up on instruction exits
Remove the sh4_flush_icache special cases, now works through the
general case.
Remove the sh4_flush_icache special cases, now works through the
general case.
1.1 --- a/src/sh4/mmu.c Tue Jan 06 02:03:36 2009 +00001.2 +++ b/src/sh4/mmu.c Wed Jan 07 04:39:04 2009 +00001.3 @@ -277,7 +277,8 @@1.4 // current block1.5 mmu_set_tlb_enabled( val & MMUCR_AT );1.6 MMIO_WRITE( MMU, MMUCR, val );1.7 - sh4_flush_icache();1.8 + sh4_core_exit( CORE_EXIT_FLUSH_ICACHE );1.9 + xlat_flush_cache(); // If we're not running, flush the cache anyway1.10 }1.11 break;1.12 case CCR:
2.1 --- a/src/sh4/sh4.c Tue Jan 06 02:03:36 2009 +00002.2 +++ b/src/sh4/sh4.c Wed Jan 07 04:39:04 2009 +00002.3 @@ -209,24 +209,15 @@2.4 }2.5 }2.6 #endif2.7 + if( exit_code != CORE_EXIT_EXCEPTION ) {2.8 + sh4_finalize_instruction();2.9 + }2.10 // longjmp back into sh4_run_slice2.11 sh4_running = FALSE;2.12 longjmp(sh4_exit_jmp_buf, exit_code);2.13 }2.14 }2.16 -void sh4_flush_icache()2.17 -{2.18 -#ifdef SH4_TRANSLATOR2.19 - // FIXME: Special case needs to be generalized2.20 - if( sh4_use_translator ) {2.21 - if( sh4_translate_flush_cache() ) {2.22 - longjmp(sh4_exit_jmp_buf, CORE_EXIT_CONTINUE);2.23 - }2.24 - }2.25 -#endif2.26 -}2.27 -2.28 void sh4_save_state( FILE *f )2.29 {2.30 if( sh4_use_translator ) {2.31 @@ -377,10 +368,7 @@2.32 sh4r.pc = sh4r.vbr + v; \2.33 sh4r.new_pc = sh4r.pc + 2; \2.34 sh4_write_sr( sh4r.ssr |SR_MD|SR_BL|SR_RB ); \2.35 - if( sh4r.in_delay_slot ) { \2.36 - sh4r.in_delay_slot = 0; \2.37 - sh4r.spc -= 2; \2.38 - } \2.39 + sh4r.in_delay_slot = 0; \2.40 } \2.41 return TRUE; } while(0)
3.1 --- a/src/sh4/sh4core.h Tue Jan 06 02:03:36 2009 +00003.2 +++ b/src/sh4/sh4core.h Wed Jan 07 04:39:04 2009 +00003.3 @@ -72,7 +72,7 @@3.6 /**3.7 - * SH4 vm-exit flag - exit the current block but continue (eg exception handling)3.8 + * SH4 vm-exit flag - exit the current block but continue normally3.9 */3.10 #define CORE_EXIT_CONTINUE 13.12 @@ -239,6 +239,13 @@3.13 gboolean FASTCALL sh4_raise_tlb_exception( int );3.14 void FASTCALL sh4_accept_interrupt( void );3.16 +/**3.17 + * Complete the current instruction as part of a core exit. Prevents the3.18 + * system from being left in an inconsistent state when an exit is3.19 + * triggered during a memory write.3.20 + */3.21 +void sh4_finalize_instruction( void );3.22 +3.23 /* Status Register (SR) bits */3.24 #define SR_MD 0x40000000 /* Processor mode ( User=0, Privileged=1 ) */3.25 #define SR_RB 0x20000000 /* Register bank (priviledged mode only) */
4.1 --- a/src/sh4/sh4core.in Tue Jan 06 02:03:36 2009 +00004.2 +++ b/src/sh4/sh4core.in Wed Jan 07 04:39:04 2009 +00004.3 @@ -102,9 +102,6 @@4.5 /********************** SH4 emulation core ****************************/4.7 -#define UNDEF(ir) return sh4_raise_slot_exception(EXC_ILLEGAL, EXC_SLOT_ILLEGAL)4.8 -#define UNIMP(ir) do{ ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", sh4r.pc, ir ); sh4_core_exit(CORE_EXIT_HALT); return FALSE; }while(0)4.9 -4.10 #if(SH4_CALLTRACE == 1)4.11 #define MAX_CALLSTACK 324.12 static struct call_stack {4.13 @@ -187,10 +184,6 @@4.14 #define MEM_WRITE_LONG( addr, val ) ADDRSPACE[(addr)>>12]->write_long(addr, val)4.15 #define MEM_PREFETCH( addr ) ADDRSPACE[(addr)>>12]->prefetch(addr)4.16 #endif4.17 -4.18 -4.19 -4.20 -4.22 #define FP_WIDTH (IS_FPU_DOUBLESIZE() ? 8 : 4)4.24 @@ -223,6 +216,131 @@4.25 MEM_WRITE_LONG(addr, *((uint32_t *)&FR((reg))) ); \4.26 }4.28 +#define UNDEF(ir)4.29 +#define UNIMP(ir)4.30 +4.31 +/**4.32 + * Perform instruction-completion following core exit of a partially completed4.33 + * instruction. NOTE: This is only allowed on memory writes, operation is not4.34 + * guaranteed in any other case.4.35 + */4.36 +void sh4_finalize_instruction( void )4.37 +{4.38 + unsigned short ir;4.39 + uint32_t tmp;4.40 +4.41 + assert( IS_IN_ICACHE(sh4r.pc) );4.42 + ir = *(uint16_t *)GET_ICACHE_PTR(sh4r.pc);4.43 +4.44 + /**4.45 + * Note - we can't take an exit on a control transfer instruction itself,4.46 + * which means the exit must have happened in the delay slot. So for these4.47 + * cases, finalize the delay slot instruction, and re-execute the control transfer.4.48 + *4.49 + * For delay slots which modify the argument used in the branch instruction,4.50 + * we pretty much just assume that that can't have already happened in an exit case.4.51 + */4.52 +4.53 +%%4.54 +BRA disp {:4.55 + sh4r.pc += 2;4.56 + sh4_finalize_instruction();4.57 + sh4r.pc += disp;4.58 + sh4r.slice_cycle += sh4_cpu_period;4.59 +:}4.60 +BRAF Rn {:4.61 + sh4r.pc += 2;4.62 + tmp = sh4r.r[Rn];4.63 + sh4_finalize_instruction();4.64 + sh4r.pc += tmp;4.65 + sh4r.slice_cycle += sh4_cpu_period;4.66 +:}4.67 +BSR disp {:4.68 + /* Note: PR is already set */4.69 + sh4r.pc += 2;4.70 + sh4_finalize_instruction();4.71 + sh4r.pc += disp;4.72 + sh4r.slice_cycle += sh4_cpu_period;4.73 +:}4.74 +BSRF Rn {:4.75 + /* Note: PR is already set */4.76 + sh4r.pc += 2;4.77 + tmp = sh4r.r[Rn];4.78 + sh4_finalize_instruction();4.79 + sh4r.pc += tmp;4.80 + sh4r.slice_cycle += sh4_cpu_period;4.81 +:}4.82 +BF/S disp {:4.83 + sh4r.pc += 2;4.84 + sh4_finalize_instruction();4.85 + if( !sh4r.t ) {4.86 + sh4r.pc += disp;4.87 + }4.88 + sh4r.slice_cycle += sh4_cpu_period;4.89 +:}4.90 +BT/S disp {:4.91 + sh4r.pc += 2;4.92 + sh4_finalize_instruction();4.93 + if( sh4r.t ) {4.94 + sh4r.pc += disp;4.95 + }4.96 + sh4r.slice_cycle += sh4_cpu_period;4.97 +:}4.98 +JMP @Rn {:4.99 + sh4r.pc += 2;4.100 + tmp = sh4r.r[Rn];4.101 + sh4_finalize_instruction();4.102 + sh4r.pc = tmp;4.103 + sh4r.new_pc = tmp + 2;4.104 + sh4r.slice_cycle += 2*sh4_cpu_period;4.105 + return;4.106 +:}4.107 +JSR @Rn {:4.108 + /* Note: PR is already set */4.109 + sh4r.pc += 2;4.110 + tmp = sh4r.r[Rn];4.111 + sh4_finalize_instruction();4.112 + sh4r.pc = tmp;4.113 + sh4r.new_pc = tmp + 2;4.114 + sh4r.slice_cycle += 2*sh4_cpu_period;4.115 + return;4.116 +:}4.117 +RTS {:4.118 + sh4r.pc += 2;4.119 + sh4_finalize_instruction();4.120 + sh4r.pc = sh4r.pr;4.121 + sh4r.new_pc = sh4r.pr + 2;4.122 + sh4r.slice_cycle += 2*sh4_cpu_period;4.123 + return;4.124 +:}4.125 +RTE {:4.126 + /* SR is already set */4.127 + sh4r.pc += 2;4.128 + sh4_finalize_instruction();4.129 + sh4r.pc = sh4r.spc;4.130 + sh4r.new_pc = sh4r.pr + 2;4.131 + sh4r.slice_cycle += 2*sh4_cpu_period;4.132 + return;4.133 +:}4.134 +MOV.B Rm, @-Rn {: sh4r.r[Rn]--; :}4.135 +MOV.W Rm, @-Rn {: sh4r.r[Rn] -= 2; :}4.136 +MOV.L Rm, @-Rn {: sh4r.r[Rn] -= 4; :}4.137 +MOV.B @Rm+, Rn {: sh4r.r[Rm] ++; :}4.138 +MOV.W @Rm+, Rn {: sh4r.r[Rm] += 2; :}4.139 +MOV.L @Rm+, Rn {: sh4r.r[Rm] += 4; :}4.140 +%%4.141 + sh4r.pc += 2;4.142 + sh4r.new_pc = sh4r.pc+2;4.143 + sh4r.slice_cycle += sh4_cpu_period;4.144 +}4.145 +4.146 +#undef UNDEF(ir)4.147 +#undef UNIMP(ir)4.148 +4.149 +#define UNDEF(ir) return sh4_raise_slot_exception(EXC_ILLEGAL, EXC_SLOT_ILLEGAL)4.150 +#define UNIMP(ir) do{ ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", sh4r.pc, ir ); sh4_core_exit(CORE_EXIT_HALT); return FALSE; }while(0)4.151 +4.152 +4.153 gboolean sh4_execute_instruction( void )4.154 {4.155 uint32_t pc;4.156 @@ -265,6 +383,14 @@4.157 }4.158 assert( IS_IN_ICACHE(pc) );4.159 ir = *(uint16_t *)GET_ICACHE_PTR(sh4r.pc);4.160 +4.161 + /* FIXME: This is a bit of a hack, but the PC of the delay slot should not4.162 + * be visible until after the instruction has executed (for exception4.163 + * correctness)4.164 + */4.165 + if( sh4r.in_delay_slot ) {4.166 + sh4r.pc -= 2;4.167 + }4.168 %%4.169 AND Rm, Rn {: sh4r.r[Rn] &= sh4r.r[Rm]; :}4.170 AND #imm, R0 {: R0 &= imm; :}
5.1 --- a/src/test/testsh4x86.c Tue Jan 06 02:03:36 2009 +00005.2 +++ b/src/test/testsh4x86.c Wed Jan 07 04:39:04 2009 +00005.3 @@ -78,8 +78,8 @@5.4 gboolean sh4_clear_breakpoint( uint32_t pc, breakpoint_type_t type ) { return TRUE; }5.5 gboolean dreamcast_is_running() { return FALSE; }5.6 int sh4_get_breakpoint( uint32_t pc ) { return 0; }5.7 +void sh4_finalize_instruction() { }5.8 void sh4_core_exit( int exit_code ){}5.9 -void sh4_flush_icache(){}5.10 void event_execute() {}5.11 void TMU_run_slice( uint32_t nanos ) {}5.12 void CCN_set_cache_control( uint32_t val ) { }
6.1 --- a/src/tools/actparse.c Tue Jan 06 02:03:36 2009 +00006.2 +++ b/src/tools/actparse.c Wed Jan 07 04:39:04 2009 +00006.3 @@ -32,7 +32,7 @@6.4 return action;6.5 }6.7 -int add_action( struct actionset *actions, struct ruleset *rules, char *operation, char *action )6.8 +int add_action( char **actions, struct ruleset *rules, char *operation, char *action )6.9 {6.10 char *act = g_strchomp(action);6.12 @@ -65,11 +65,11 @@6.14 for( i=0; i<rules->rule_count; i++ ) {6.15 if( strcasecmp(rules->rules[i]->format, operation) == 0 ) {6.16 - if( actions->actions[i] != NULL ) {6.17 + if( actions[i] != NULL ) {6.18 fprintf( stderr, "Duplicate actions for operation '%s'\n", operation );6.19 return -1;6.20 }6.21 - actions->actions[i] = act;6.22 + actions[i] = act;6.23 return 0;6.24 }6.25 }6.26 @@ -77,65 +77,105 @@6.27 return -1;6.28 }6.30 +struct actionfile {6.31 + FILE *f;6.32 + char *text;6.33 + int length;6.34 + int yyposn;6.35 + int yyline;6.36 + struct ruleset *rules;6.37 + struct actiontoken token;6.38 +};6.40 -struct actionset *parse_action_file( struct ruleset *rules, FILE *f )6.41 +actionfile_t action_file_open( const char *filename, struct ruleset *rules )6.42 {6.43 - struct actionset *actions = malloc( sizeof(struct actionset ) );6.44 struct stat st;6.45 - char *text;6.46 - int i, length;6.47 + FILE *f = fopen( filename, "ro" );6.48 + if( f == NULL )6.49 + return NULL;6.50 + fstat( fileno(f), &st );6.51 +6.52 + actionfile_t af = malloc( sizeof(struct actionfile) );6.53 + af->f = f;6.54 + af->length = st.st_size+1;6.55 + af->text = malloc( st.st_size+1 );6.56 + fread( af->text, st.st_size, 1, f );6.57 + af->text[st.st_size] = '\0';6.58 + af->yyline = 0;6.59 + af->yyposn = 0;6.60 + af->rules = rules;6.61 + af->token.symbol = NONE;6.62 +6.63 + return af;6.64 +}6.66 - memset( actions, 0, sizeof( struct actionset ) );6.67 - /* Read whole file in (for convenience) */6.68 - fstat( fileno(f), &st );6.69 - length = st.st_size;6.70 - text = malloc( length+1 );6.71 - fread( text, length, 1, f );6.72 - text[length] = '\0';6.73 - yyline = 0;6.74 - actions->pretext = text;6.75 - for( i=0; i<length; i++ ) {6.76 - if( text[i] == '\n' ) {6.77 - yyline++;6.78 - if( i+3 < length && text[i+1] == '%' && text[i+2] == '%' ) {6.79 - text[i+1] = '\0';6.80 - i+=3;6.81 - break;6.82 +actiontoken_t action_file_next( actionfile_t af )6.83 +{6.84 + if( af->token.symbol == ACTIONS ) {6.85 + /* Destroy previous actions */6.86 + memset( af->token.actions, 0, sizeof(af->token.actions) );6.87 + }6.88 +6.89 + if( af->yyposn == af->length ) {6.90 + af->token.symbol = END;6.91 + } else if( af->token.symbol == TEXT || /* ACTIONS must follow TEXT */6.92 + (af->token.symbol == NONE && af->text[af->yyposn] == '\%' && af->text[af->yyposn+1] == '%') ) {6.93 + /* Begin action block */6.94 + af->token.symbol = ACTIONS;6.95 +6.96 + char *operation = &af->text[af->yyposn];6.97 + while( af->yyposn < af->length ) {6.98 + if( af->text[af->yyposn] == '\n' ) {6.99 + yyline++;6.100 + if( af->text[af->yyposn+1] == '%' && af->text[af->yyposn+2] == '%' ) {6.101 + af->yyposn += 3;6.102 + break;6.103 + }6.104 }6.105 +6.106 + if( af->text[af->yyposn] == '{' && af->text[af->yyposn+1] == ':' ) {6.107 + af->text[af->yyposn] = '\0';6.108 + af->yyposn+=2;6.109 + char *action = &af->text[af->yyposn];6.110 + while( af->yyposn < af->length ) {6.111 + if( af->text[af->yyposn] == ':' && af->text[af->yyposn+1] == '}' ) {6.112 + af->text[af->yyposn] = '\0';6.113 + af->yyposn++;6.114 + if( add_action( af->token.actions, af->rules, operation, action ) != 0 ) {6.115 + af->token.symbol = ERROR;6.116 + return &af->token;6.117 + }6.118 + operation = &af->text[af->yyposn+1];6.119 + break;6.120 + }6.121 + af->yyposn++;6.122 + }6.123 + }6.124 + af->yyposn++;6.125 }6.126 - }6.127 -6.128 - char *operation = &text[i];6.129 - for( ; i<length; i++ ) {6.130 - if( text[i] == '\n' ) {6.131 - yyline++;6.132 - if( i+3 < length && text[i+1] == '%' && text[i+2] == '%' ) {6.133 - i+=3;6.134 - break;6.135 - }6.136 - }6.137 -6.138 - if( text[i] == '{' && text[i+1] == ':' ) {6.139 - text[i] = '\0';6.140 - i+=2;6.141 - char *action = &text[i];6.142 - for( ;i<length; i++ ) {6.143 - if( text[i] == ':' && text[i+1] == '}' ) {6.144 - text[i] = '\0';6.145 - i++;6.146 - if( add_action( actions, rules, operation, action ) != 0 ) {6.147 - free(actions);6.148 - free(text);6.149 - return NULL;6.150 - }6.151 - operation = &text[i+1];6.152 + } else {6.153 + /* Text block */6.154 + af->token.symbol = TEXT;6.155 + af->token.text = &af->text[af->yyposn];6.156 + while( af->yyposn < af->length ) {6.157 + af->yyposn++;6.158 + if( af->text[af->yyposn-1] == '\n' ) {6.159 + af->yyline++;6.160 + if( af->text[af->yyposn] == '%' && af->text[af->yyposn+1] == '%' ) {6.161 + af->text[af->yyposn] = '\0';6.162 + af->yyposn += 2;6.163 break;6.164 }6.165 }6.166 }6.167 }6.168 + return &af->token;6.169 +}6.171 - actions->posttext = &text[i];6.172 +void action_file_close( actionfile_t af )6.173 +{6.174 + free( af->text );6.175 + fclose( af->f );6.176 + free( af );6.177 +}6.179 - return actions;6.180 -}
7.1 --- a/src/tools/gendec.c Tue Jan 06 02:03:36 2009 +00007.2 +++ b/src/tools/gendec.c Wed Jan 07 04:39:04 2009 +00007.3 @@ -161,7 +161,7 @@7.4 }7.5 }7.7 -void split_and_generate( struct ruleset *rules, struct actionset *actions,7.8 +void split_and_generate( struct ruleset *rules, char **actions,7.9 int ruleidx[], int rule_count, int input_mask,7.10 int depth, FILE *f ) {7.11 uint32_t mask;7.12 @@ -170,7 +170,7 @@7.13 if( rule_count == 0 ) {7.14 fprintf( f, "%*cUNDEF(ir);\n", depth*8, ' ' );7.15 } else if( rule_count == 1 ) {7.16 - fprint_action( rules->rules[ruleidx[0]], actions->actions[ruleidx[0]], depth, f );7.17 + fprint_action( rules->rules[ruleidx[0]], actions[ruleidx[0]], depth, f );7.18 } else {7.20 mask = find_mask(rules, ruleidx, rule_count, input_mask);7.21 @@ -223,7 +223,7 @@7.22 }7.23 }7.25 -int generate_decoder( struct ruleset *rules, struct actionset *actions, FILE *f )7.26 +int generate_decoder( struct ruleset *rules, actionfile_t af, FILE *out )7.27 {7.28 int ruleidx[rules->rule_count];7.29 int i;7.30 @@ -232,27 +232,42 @@7.31 ruleidx[i] = i;7.32 }7.34 - fputs( actions->pretext, f );7.35 -7.36 - split_and_generate( rules, actions, ruleidx, rules->rule_count, 0, 1, f );7.37 -7.38 - fputs( actions->posttext, f );7.39 -7.40 + actiontoken_t token = action_file_next(af);7.41 + while( token->symbol != END ) {7.42 + if( token->symbol == TEXT ) {7.43 + fputs( token->text, out );7.44 + } else if( token->symbol == ERROR ) {7.45 + fprintf( stderr, "Error parsing action file" );7.46 + return -1;7.47 + } else {7.48 + split_and_generate( rules, token->actions, ruleidx, rules->rule_count, 0, 1, out );7.49 + }7.50 + token = action_file_next(af);7.51 + }7.52 return 0;7.53 }7.55 -int generate_template( struct ruleset *rules, struct actionset *actions, FILE *f )7.56 +int generate_template( struct ruleset *rules, actionfile_t af, FILE *out )7.57 {7.58 int i;7.59 - fputs( actions->pretext, f );7.60 - fputs( "%%\n", f );7.61 -7.62 - for( i=0; i<rules->rule_count; i++ ) {7.63 - fprintf( f, "%s {: %s :}\n", rules->rules[i]->format,7.64 - actions->actions[i] == NULL ? "" : actions->actions[i] );7.65 +7.66 + actiontoken_t token = action_file_next(af);7.67 + while( token->symbol != END ) {7.68 + if( token->symbol == TEXT ) {7.69 + fputs( token->text, out );7.70 + } else if( token->symbol == ERROR ) {7.71 + fprintf( stderr, "Error parsing action file" );7.72 + return -1;7.73 + } else {7.74 + fputs( "%%\n", out );7.75 + for( i=0; i<rules->rule_count; i++ ) {7.76 + fprintf( out, "%s {: %s :}\n", rules->rules[i]->format,7.77 + token->actions[i] == NULL ? "" : token->actions[i] );7.78 + }7.79 + fputs( "%%\n", out );7.80 + }7.81 + token = action_file_next(af);7.82 }7.83 - fputs( "%%\n", f );7.84 - fputs( actions->posttext, f );7.86 return 0;7.87 }7.88 @@ -309,26 +324,21 @@7.89 exit(2);7.90 }7.92 - act_file = fopen( act_filename, "ro" );7.93 - if( act_file == NULL ) {7.94 - fprintf( stderr, "Unable to open '%s' for reading (%s)\n", act_filename, strerror(errno) );7.95 - exit(3);7.96 - }7.97 -7.98 /* Parse the input */7.99 struct ruleset *rules = parse_ruleset_file( ins_file );7.100 fclose( ins_file );7.101 if( rules == NULL ) {7.102 exit(5);7.103 }7.104 -7.105 - struct actionset *actions = parse_action_file( rules, act_file );7.106 - fclose( act_file );7.107 - if( actions == NULL ) {7.108 - exit(6);7.109 +7.110 + actionfile_t af = action_file_open( act_filename, rules );7.111 + if( af == NULL ) {7.112 + fprintf( stderr, "Unable to open '%s' for reading (%s)\n", act_filename, strerror(errno) );7.113 + exit(3);7.114 }7.116 - /* Finally write out the results */7.117 +7.118 + /* Open the output file */7.119 out_file = fopen( out_filename, "wo" );7.120 if( out_file == NULL ) {7.121 fprintf( stderr, "Unable to open '%s' for writing (%s)\n", out_filename, strerror(errno) );7.122 @@ -337,16 +347,18 @@7.124 switch( gen_mode ) {7.125 case GEN_SOURCE:7.126 - if( generate_decoder( rules, actions, out_file ) != 0 ) {7.127 + if( generate_decoder( rules, af, out_file ) != 0 ) {7.128 exit(7);7.129 }7.130 break;7.131 case GEN_TEMPLATE:7.132 - if( generate_template( rules, actions, out_file ) != 0 ) {7.133 + if( generate_template( rules, af, out_file ) != 0 ) {7.134 exit(7);7.135 }7.136 break;7.137 }7.138 +7.139 + action_file_close(af);7.140 fclose( out_file );7.141 return 0;7.142 }
8.1 --- a/src/tools/gendec.h Tue Jan 06 02:03:36 2009 +00008.2 +++ b/src/tools/gendec.h Wed Jan 07 04:39:04 2009 +00008.3 @@ -70,14 +70,24 @@8.4 };8.6 struct actionset {8.7 - char *pretext;8.8 - char *posttext;8.9 char *actions[MAX_RULES];8.10 };8.12 -struct actionset *parse_action_file( struct ruleset *rules, FILE *f );8.13 +typedef struct actionfile *actionfile_t;8.15 -int generate_decoder( struct ruleset *rules, struct actionset *actions, FILE *f );8.16 +typedef struct actiontoken {8.17 + enum { NONE, TEXT, ACTIONS, END, ERROR } symbol;8.18 + char *text;8.19 + char *actions[MAX_RULES];8.20 +} *actiontoken_t;8.21 +8.22 +actionfile_t action_file_open( const char *filename, struct ruleset *rules );8.23 +8.24 +actiontoken_t action_file_next( actionfile_t af );8.25 +8.26 +void action_file_close( actionfile_t af );8.27 +8.28 +int generate_decoder( struct ruleset *rules, actionfile_t af, FILE *f );8.30 #ifdef __cplusplus8.31 }
.