#include "hail-list.h" static HAIL_LIST_HEAD(g_machine_list); void init_machines(void); /* three interfaces to device driver 1. init_machines: generated by hail compiler, explicitly called by driver 2. run_machines: defined here, instrumented by hail compiler 3. cleanup_machines: defined here, explicitly called by driver */ #define HAIL_READ_REG 1 #define HAIL_WRITE_REG 2 #define HAIL_DMY_FLW 1 #define HAIL_IMM_FLW 2 #define HAIL_OPT_FLW 4 #define HAIL_EVT_FLW 8 #define HAIL_NOT_IN_STATE 0 #define HAIL_IN_1ST_STATE 1 #define HAIL_IN_OTHER_STATE 2 #define WORD_SIZE 4 /* assume size 4 for alignment */ #define MEM_SIZE(type) \ WORD_SIZE * (sizeof(type) / WORD_SIZE + sizeof(type) % WORD_SIZE != 0 ) struct hail_access_t { struct hail_list_head hook; /*to state*/ char op; /* read or write */ char name[64]; /* reg name */ }; static inline struct hail_access_t *new_hail_access(char op, const char *name, const char *pool, int *pool_idx) { /*struct hail_access_t *p = HAIL_MALLOC(struct hail_access_t);*/ struct hail_access_t *p = (struct hail_access_t *)(pool + *pool_idx); *pool_idx += MEM_SIZE(struct hail_access_t); p->op = op; strcpy(p->name, name); return p; } struct hail_state_t { struct hail_list_head hook; /*to machine*/ struct hail_list_head access_list; char connector; /* =i>, =o>, =e> */ }; static inline struct hail_state_t *new_hail_state(char cnn, const char *pool, int *pool_idx) { /*struct hail_state_t *p = HAIL_MALLOC(struct hail_state_t);*/ struct hail_state_t *p = (struct hail_state_t *)(pool + *pool_idx); *pool_idx += MEM_SIZE(struct hail_state_t); INIT_HAIL_LIST_HEAD(&p->access_list); p->connector = cnn; return p; } #if 0 static inline void free_hail_state(struct hail_state_t *state) { struct hail_list_head *pos, *next; hail_list_for_each_safe(pos, next, &state->access_list){ struct hail_access_t *p; p = hail_list_entry(pos, struct hail_access_t, hook); hail_list_del(&p->hook); free(p); } free(state); } #endif static inline int access_in_state(char op, const char *name, struct hail_state_t *state) { struct hail_list_head *pos; hail_list_for_each(pos, &state->access_list){ struct hail_access_t *p; p = hail_list_entry(pos, struct hail_access_t, hook); if((p->op == op) && !strcmp(p->name, name)) return 1; } return 0; } struct hail_machine_t{ struct hail_list_head hook; /* to machine list */ struct hail_list_head state_list; /*pay attention: last state in the tail */ struct hail_list_head *current_pos; /*point to current state */ }; static inline struct hail_machine_t *new_hail_machine(const char *pool, int *pool_idx) { /*struct hail_machine_t *p = HAIL_MALLOC(struct hail_machine_t);*/ struct hail_machine_t *p = (struct hail_machine_t *)(pool + *pool_idx); *pool_idx += MEM_SIZE(struct hail_machine_t); INIT_HAIL_LIST_HEAD(&p->state_list); p->current_pos = &p->state_list; return p; } #if 0 static inline void free_hail_machine(struct hail_machine_t *machine) { struct hail_list_head *pos, *next; hail_list_for_each_safe(pos, next, &machine->state_list){ struct hail_state_t *state; state = hail_list_entry(pos, struct hail_state_t, hook); hail_list_del(&state->hook); free_hail_state(state); } free(machine); } #endif static inline int verify_machines(void) { int retval = 1; struct hail_list_head *pos, *pos2, *next; hail_list_for_each_safe(pos, next, &g_machine_list){ struct hail_machine_t *p; int state_count = 0; p = hail_list_entry(pos, struct hail_machine_t, hook); hail_list_for_each(pos2, &p->state_list){ struct hail_state_t *state; state = hail_list_entry(pos2, struct hail_state_t, hook); /* each state must have at least one access */ if(hail_list_empty(&state->access_list)){ HAIL_FAIL("empty access in a state"); retval = 0; } state_count ++; } /* for each state */ /*each machine must have at least 2 states */ if(state_count < 2){ hail_list_del(&p->hook); /* free_hail_machine(p); */ } }/* for each machine */ return retval; } static inline int skip_next_state(char op, const char *name, struct hail_machine_t *machine) { int retval = 0; struct hail_list_head *pos; for (pos = machine->current_pos->next->next; pos != &machine->state_list; pos = pos->next){ struct hail_state_t *state; state = hail_list_entry(pos, struct hail_state_t, hook); if(access_in_state(op, name, state)){ retval = 1; break; } } return retval; } static inline int backward_machine(char op, const char *name, struct hail_machine_t *machine) { int retval = HAIL_NOT_IN_STATE; struct hail_list_head *pos; for (pos = machine->current_pos->prev; pos != &machine->state_list; pos = pos->prev){ struct hail_state_t *state; state = hail_list_entry(pos, struct hail_state_t, hook); if(access_in_state(op, name, state)){ machine->current_pos = pos; /* change current state */ retval = (pos != (&machine->state_list)->next)? HAIL_IN_OTHER_STATE : HAIL_IN_1ST_STATE; break; } } return retval; } static inline int run_machines(char op, const char *name) { int retval = 1; struct hail_list_head *pos; HAIL_FLAG_TYPE flags; /* disable interrupt */ HAIL_DISABLE_INTERRUPT(flags); hail_list_for_each(pos, &g_machine_list){ struct hail_machine_t *cur_machine; struct hail_state_t *cur_state, *next_state; cur_machine = hail_list_entry(pos, struct hail_machine_t, hook); cur_state = (cur_machine->current_pos != &cur_machine->state_list) ? hail_list_entry(cur_machine->current_pos, struct hail_state_t, hook) : NULL; next_state = hail_list_entry(cur_machine->current_pos->next, struct hail_state_t, hook); if(access_in_state(op, name, next_state)){ /* advance to next state */ cur_machine->current_pos = cur_machine->current_pos->next; if(cur_machine->current_pos->next == &cur_machine->state_list) /* end, so restart */ cur_machine->current_pos = &cur_machine->state_list; } else if(skip_next_state(op, name, cur_machine)){ HAIL_FAIL("follow fail: skip next state"); retval = 0; } else if(cur_state){ switch(cur_state->connector){ case HAIL_IMM_FLW: HAIL_FAIL("immediate follow fail"); retval = 0; break; case HAIL_EVT_FLW: if(HAIL_NOT_IN_STATE != backward_machine(op, name, cur_machine)){ HAIL_FAIL("eventual follow fail"); retval = 0; } break; case HAIL_OPT_FLW: if(HAIL_IN_OTHER_STATE == backward_machine(op, name, cur_machine)){ HAIL_FAIL("optional follow fail: back to non-1st state"); retval = 0; } break; } /* switch */ } /* else if cur_state */ }/*for each machine */ /* enable interrupt */ HAIL_ENABLE_INTERRUPT(flags); return retval; } static inline int cleanup_machines(void) { int retval = 0; struct hail_list_head *pos, *next; hail_list_for_each_safe(pos, next, &g_machine_list){ struct hail_machine_t *cur_machine; cur_machine = hail_list_entry(pos, struct hail_machine_t, hook); if(cur_machine->current_pos != &cur_machine->state_list){ struct hail_state_t *cur_state; cur_state = hail_list_entry(cur_machine->current_pos, struct hail_state_t, hook); if(HAIL_EVT_FLW == cur_state->connector){ HAIL_FAIL("eventual follow pending"); retval = 1; } } #if 0 /* free memory */ hail_list_del(&cur_machine->hook); free_hail_machine(cur_machine); #endif } return retval; }