X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Fpipeline%2Frte_swx_pipeline.c;h=2145ca0a427e1606bdf878e716398b0e0e834db5;hb=2490bb897182f57de80fd924dd3ae48dda819b8c;hp=0d025481378ca12959a093ee40b1bf4987ba86db;hpb=5dc6a5f2e7eb20bdab82068f0e2d01331ca703a2;p=dpdk.git diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c index 0d02548137..2145ca0a42 100644 --- a/lib/pipeline/rte_swx_pipeline.c +++ b/lib/pipeline/rte_swx_pipeline.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "rte_swx_pipeline_internal.h" @@ -1376,6 +1377,26 @@ instruction_is_tx(enum instruction_type type) } } +static int +instruction_does_tx(struct instruction *instr) +{ + switch (instr->type) { + case INSTR_TX: + case INSTR_TX_I: + case INSTR_HDR_EMIT_TX: + case INSTR_HDR_EMIT2_TX: + case INSTR_HDR_EMIT3_TX: + case INSTR_HDR_EMIT4_TX: + case INSTR_HDR_EMIT5_TX: + case INSTR_HDR_EMIT6_TX: + case INSTR_HDR_EMIT7_TX: + case INSTR_HDR_EMIT8_TX: + return 1; + default: + return 0; + } +} + static int instruction_is_jmp(struct instruction *instr) { @@ -1416,6 +1437,24 @@ instruction_is_jmp(struct instruction *instr) } } +static int +instruction_does_thread_yield(struct instruction *instr) +{ + switch (instr->type) { + case INSTR_RX: + case INSTR_TABLE: + case INSTR_TABLE_AF: + case INSTR_SELECTOR: + case INSTR_LEARNER: + case INSTR_LEARNER_AF: + case INSTR_EXTERN_OBJ: + case INSTR_EXTERN_FUNC: + return 1; + default: + return 0; + } +} + static struct field * action_field_parse(struct action *action, const char *name); @@ -2320,6 +2359,9 @@ action_find(struct rte_swx_pipeline *p, const char *name); static int action_has_nbo_args(struct action *a); +static int +learner_action_args_check(struct rte_swx_pipeline *p, struct action *a, const char *mf_name); + static int instr_learn_translate(struct rte_swx_pipeline *p, struct action *action, @@ -2329,16 +2371,31 @@ instr_learn_translate(struct rte_swx_pipeline *p, struct instruction_data *data __rte_unused) { struct action *a; + const char *mf_name; + uint32_t mf_offset = 0; CHECK(action, EINVAL); - CHECK(n_tokens == 2, EINVAL); + CHECK((n_tokens == 2) || (n_tokens == 3), EINVAL); a = action_find(p, tokens[1]); CHECK(a, EINVAL); CHECK(!action_has_nbo_args(a), EINVAL); + mf_name = (n_tokens > 2) ? tokens[2] : NULL; + CHECK(!learner_action_args_check(p, a, mf_name), EINVAL); + + if (mf_name) { + struct field *mf; + + mf = metadata_field_parse(p, mf_name); + CHECK(mf, EINVAL); + + mf_offset = mf->offset / 8; + } + instr->type = INSTR_LEARNER_LEARN; instr->learn.action_id = a->id; + instr->learn.mf_offset = mf_offset; return 0; } @@ -4482,8 +4539,6 @@ instr_meter_translate(struct rte_swx_pipeline *p, instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id; instr->meter.color_out.n_bits = fcout->n_bits; instr->meter.color_out.offset = fcout->offset / 8; - - return 0; } /* index = HMEFT, length = HMEFT, color_in = I, color_out = MEF. */ @@ -4518,8 +4573,6 @@ instr_meter_translate(struct rte_swx_pipeline *p, instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id; instr->meter.color_out.n_bits = fcout->n_bits; instr->meter.color_out.offset = fcout->offset / 8; - - return 0; } /* index = I, length = HMEFT, color_in = MEFT, color_out = MEF. */ @@ -4550,8 +4603,6 @@ instr_meter_translate(struct rte_swx_pipeline *p, instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id; instr->meter.color_out.n_bits = fcout->n_bits; instr->meter.color_out.offset = fcout->offset / 8; - - return 0; } /* index = I, length = HMEFT, color_in = I, color_out = MEF. */ @@ -4581,11 +4632,9 @@ instr_meter_translate(struct rte_swx_pipeline *p, instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id; instr->meter.color_out.n_bits = fcout->n_bits; instr->meter.color_out.offset = fcout->offset / 8; - - return 0; } - CHECK(0, EINVAL); + return 0; } static inline void @@ -5880,7 +5929,7 @@ instr_translate(struct rte_swx_pipeline *p, instr, data); - CHECK(0, EINVAL); + return -EINVAL; } static struct instruction_data * @@ -5926,7 +5975,7 @@ instr_label_check(struct instruction_data *instruction_data, continue; for (j = i + 1; j < n_instructions; j++) - CHECK(strcmp(label, data[j].label), EINVAL); + CHECK(strcmp(label, instruction_data[j].label), EINVAL); } /* Get users for each instruction label. */ @@ -6590,8 +6639,6 @@ error: return err; } -typedef void (*instr_exec_t)(struct rte_swx_pipeline *); - static instr_exec_t instruction_table[] = { [INSTR_RX] = instr_rx_exec, [INSTR_TX] = instr_tx_exec, @@ -6782,12 +6829,41 @@ static instr_exec_t instruction_table[] = { [INSTR_RETURN] = instr_return_exec, }; +static int +instruction_table_build(struct rte_swx_pipeline *p) +{ + p->instruction_table = calloc(RTE_SWX_PIPELINE_INSTRUCTION_TABLE_SIZE_MAX, + sizeof(struct instr_exec_t *)); + if (!p->instruction_table) + return -EINVAL; + + memcpy(p->instruction_table, instruction_table, sizeof(instruction_table)); + + return 0; +} + +static void +instruction_table_build_free(struct rte_swx_pipeline *p) +{ + if (!p->instruction_table) + return; + + free(p->instruction_table); + p->instruction_table = NULL; +} + +static void +instruction_table_free(struct rte_swx_pipeline *p) +{ + instruction_table_build_free(p); +} + static inline void instr_exec(struct rte_swx_pipeline *p) { struct thread *t = &p->threads[p->thread_id]; struct instruction *ip = t->ip; - instr_exec_t instr = instruction_table[ip->type]; + instr_exec_t instr = p->instruction_table[ip->type]; instr(p); } @@ -7225,7 +7301,7 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, uint32_t size) { struct table_type *type; - struct table *t; + struct table *t = NULL; struct action *default_action; struct header *header = NULL; uint32_t action_data_size_max = 0, i; @@ -7252,6 +7328,7 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, const char *action_name = params->action_names[i]; struct action *a; uint32_t action_data_size; + int action_is_for_table_entries = 1, action_is_for_default_entry = 1; CHECK_NAME(action_name, EINVAL); @@ -7262,6 +7339,12 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, action_data_size = a->st ? a->st->n_bits / 8 : 0; if (action_data_size > action_data_size_max) action_data_size_max = action_data_size; + + if (params->action_is_for_table_entries) + action_is_for_table_entries = params->action_is_for_table_entries[i]; + if (params->action_is_for_default_entry) + action_is_for_default_entry = params->action_is_for_default_entry[i]; + CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL); } CHECK_NAME(params->default_action_name, EINVAL); @@ -7270,6 +7353,9 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, params->default_action_name)) break; CHECK(i < params->n_actions, EINVAL); + CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i], + EINVAL); + default_action = action_find(p, params->default_action_name); CHECK((default_action->st && params->default_action_data) || !params->default_action_data, EINVAL); @@ -7293,31 +7379,31 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, /* Memory allocation. */ t = calloc(1, sizeof(struct table)); - CHECK(t, ENOMEM); + if (!t) + goto nomem; t->fields = calloc(params->n_fields, sizeof(struct match_field)); - if (!t->fields) { - free(t); - CHECK(0, ENOMEM); - } + if (!t->fields) + goto nomem; t->actions = calloc(params->n_actions, sizeof(struct action *)); - if (!t->actions) { - free(t->fields); - free(t); - CHECK(0, ENOMEM); - } + if (!t->actions) + goto nomem; if (action_data_size_max) { t->default_action_data = calloc(1, action_data_size_max); - if (!t->default_action_data) { - free(t->actions); - free(t->fields); - free(t); - CHECK(0, ENOMEM); - } + if (!t->default_action_data) + goto nomem; } + t->action_is_for_table_entries = calloc(params->n_actions, sizeof(int)); + if (!t->action_is_for_table_entries) + goto nomem; + + t->action_is_for_default_entry = calloc(params->n_actions, sizeof(int)); + if (!t->action_is_for_default_entry) + goto nomem; + /* Node initialization. */ strcpy(t->name, name); if (args && args[0]) @@ -7336,8 +7422,18 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, t->n_fields = params->n_fields; t->header = header; - for (i = 0; i < params->n_actions; i++) + for (i = 0; i < params->n_actions; i++) { + int action_is_for_table_entries = 1, action_is_for_default_entry = 1; + + if (params->action_is_for_table_entries) + action_is_for_table_entries = params->action_is_for_table_entries[i]; + if (params->action_is_for_default_entry) + action_is_for_default_entry = params->action_is_for_default_entry[i]; + t->actions[i] = action_find(p, params->action_names[i]); + t->action_is_for_table_entries[i] = action_is_for_table_entries; + t->action_is_for_default_entry[i] = action_is_for_default_entry; + } t->default_action = default_action; if (default_action->st) memcpy(t->default_action_data, @@ -7355,6 +7451,19 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p, p->n_tables++; return 0; + +nomem: + if (!t) + return -ENOMEM; + + free(t->action_is_for_default_entry); + free(t->action_is_for_table_entries); + free(t->default_action_data); + free(t->actions); + free(t->fields); + free(t); + + return -ENOMEM; } static struct rte_swx_table_params * @@ -8095,23 +8204,18 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, /* Action checks. */ CHECK(params->n_actions, EINVAL); - CHECK(params->action_names, EINVAL); for (i = 0; i < params->n_actions; i++) { const char *action_name = params->action_names[i]; - const char *action_field_name = params->action_field_names[i]; struct action *a; uint32_t action_data_size; + int action_is_for_table_entries = 1, action_is_for_default_entry = 1; CHECK_NAME(action_name, EINVAL); a = action_find(p, action_name); CHECK(a, EINVAL); - status = learner_action_args_check(p, a, action_field_name); - if (status) - return status; - status = learner_action_learning_check(p, a, params->action_names, @@ -8122,6 +8226,12 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, action_data_size = a->st ? a->st->n_bits / 8 : 0; if (action_data_size > action_data_size_max) action_data_size_max = action_data_size; + + if (params->action_is_for_table_entries) + action_is_for_table_entries = params->action_is_for_table_entries[i]; + if (params->action_is_for_default_entry) + action_is_for_default_entry = params->action_is_for_default_entry[i]; + CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL); } CHECK_NAME(params->default_action_name, EINVAL); @@ -8130,6 +8240,8 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, params->default_action_name)) break; CHECK(i < params->n_actions, EINVAL); + CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i], + EINVAL); default_action = action_find(p, params->default_action_name); CHECK((default_action->st && params->default_action_data) || @@ -8152,16 +8264,20 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, if (!l->actions) goto nomem; - l->action_arg = calloc(params->n_actions, sizeof(struct field *)); - if (!l->action_arg) - goto nomem; - if (action_data_size_max) { l->default_action_data = calloc(1, action_data_size_max); if (!l->default_action_data) goto nomem; } + l->action_is_for_table_entries = calloc(params->n_actions, sizeof(int)); + if (!l->action_is_for_table_entries) + goto nomem; + + l->action_is_for_default_entry = calloc(params->n_actions, sizeof(int)); + if (!l->action_is_for_default_entry) + goto nomem; + /* Node initialization. */ strcpy(l->name, name); @@ -8178,11 +8294,16 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, l->header = header; for (i = 0; i < params->n_actions; i++) { - const char *mf_name = params->action_field_names[i]; + int action_is_for_table_entries = 1, action_is_for_default_entry = 1; - l->actions[i] = action_find(p, params->action_names[i]); + if (params->action_is_for_table_entries) + action_is_for_table_entries = params->action_is_for_table_entries[i]; + if (params->action_is_for_default_entry) + action_is_for_default_entry = params->action_is_for_default_entry[i]; - l->action_arg[i] = mf_name ? metadata_field_parse(p, mf_name) : NULL; + l->actions[i] = action_find(p, params->action_names[i]); + l->action_is_for_table_entries[i] = action_is_for_table_entries; + l->action_is_for_default_entry[i] = action_is_for_default_entry; } l->default_action = default_action; @@ -8214,7 +8335,9 @@ nomem: if (!l) return -ENOMEM; - free(l->action_arg); + free(l->action_is_for_default_entry); + free(l->action_is_for_table_entries); + free(l->default_action_data); free(l->actions); free(l->fields); free(l); @@ -8309,7 +8432,6 @@ learner_build_free(struct rte_swx_pipeline *p) struct learner_runtime *r = &t->learners[j]; free(r->mailbox); - free(r->action_data); } free(t->learners); @@ -8353,7 +8475,6 @@ learner_build(struct rte_swx_pipeline *p) TAILQ_FOREACH(l, &p->learners, node) { struct learner_runtime *r = &t->learners[l->id]; uint64_t size; - uint32_t j; /* r->mailbox. */ size = rte_swx_table_learner_mailbox_size_get(); @@ -8369,21 +8490,6 @@ learner_build(struct rte_swx_pipeline *p) r->key = l->header ? &t->structs[l->header->struct_id] : &t->structs[p->metadata_struct_id]; - - /* r->action_data. */ - r->action_data = calloc(p->n_actions, sizeof(uint8_t *)); - if (!r->action_data) { - status = -ENOMEM; - goto error; - } - - for (j = 0; j < l->n_actions; j++) { - struct action *a = l->actions[j]; - struct field *mf = l->action_arg[j]; - uint8_t *m = t->structs[p->metadata_struct_id]; - - r->action_data[a->id] = mf ? &m[mf->offset / 8] : NULL; - } } } @@ -8410,7 +8516,6 @@ learner_free(struct rte_swx_pipeline *p) TAILQ_REMOVE(&p->learners, l, node); free(l->fields); free(l->actions); - free(l->action_arg); free(l->default_action_data); free(l); } @@ -8903,9 +9008,13 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node) void rte_swx_pipeline_free(struct rte_swx_pipeline *p) { + void *lib; + if (!p) return; + lib = p->lib; + free(p->instruction_data); free(p->instructions); @@ -8916,6 +9025,7 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p) selector_free(p); table_free(p); action_free(p); + instruction_table_free(p); metadata_free(p); header_free(p); extern_func_free(p); @@ -8925,6 +9035,9 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p) struct_free(p); free(p); + + if (lib) + dlclose(lib); } int @@ -8949,6 +9062,9 @@ rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p, return 0; } +static int +pipeline_compile(struct rte_swx_pipeline *p); + int rte_swx_pipeline_build(struct rte_swx_pipeline *p) { @@ -8985,6 +9101,10 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p) if (status) goto error; + status = instruction_table_build(p); + if (status) + goto error; + status = action_build(p); if (status) goto error; @@ -9014,6 +9134,9 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p) goto error; p->build_done = 1; + + pipeline_compile(p); + return 0; error: @@ -9024,6 +9147,7 @@ error: selector_build_free(p); table_build_free(p); action_build_free(p); + instruction_table_build_free(p); metadata_build_free(p); header_build_free(p); extern_func_build_free(p); @@ -9207,6 +9331,9 @@ rte_swx_ctl_table_action_info_get(struct rte_swx_pipeline *p, table_action->action_id = t->actions[table_action_id]->id; + table_action->action_is_for_table_entries = t->action_is_for_table_entries[table_action_id]; + table_action->action_is_for_default_entry = t->action_is_for_default_entry[table_action_id]; + return 0; } @@ -9394,6 +9521,12 @@ rte_swx_ctl_learner_action_info_get(struct rte_swx_pipeline *p, learner_action->action_id = l->actions[learner_action_id]->id; + learner_action->action_is_for_table_entries = + l->action_is_for_table_entries[learner_action_id]; + + learner_action->action_is_for_default_entry = + l->action_is_for_default_entry[learner_action_id]; + return 0; } @@ -9756,3 +9889,2614 @@ rte_swx_ctl_meter_stats_read(struct rte_swx_pipeline *p, return 0; } + +/* + * Pipeline compilation. + */ +static const char * +instr_type_to_name(struct instruction *instr) +{ + switch (instr->type) { + case INSTR_RX: return "INSTR_RX"; + + case INSTR_TX: return "INSTR_TX"; + case INSTR_TX_I: return "INSTR_TX_I"; + + case INSTR_HDR_EXTRACT: return "INSTR_HDR_EXTRACT"; + case INSTR_HDR_EXTRACT2: return "INSTR_HDR_EXTRACT2"; + case INSTR_HDR_EXTRACT3: return "INSTR_HDR_EXTRACT3"; + case INSTR_HDR_EXTRACT4: return "INSTR_HDR_EXTRACT4"; + case INSTR_HDR_EXTRACT5: return "INSTR_HDR_EXTRACT5"; + case INSTR_HDR_EXTRACT6: return "INSTR_HDR_EXTRACT6"; + case INSTR_HDR_EXTRACT7: return "INSTR_HDR_EXTRACT7"; + case INSTR_HDR_EXTRACT8: return "INSTR_HDR_EXTRACT8"; + + case INSTR_HDR_EXTRACT_M: return "INSTR_HDR_EXTRACT_M"; + + case INSTR_HDR_LOOKAHEAD: return "INSTR_HDR_LOOKAHEAD"; + + case INSTR_HDR_EMIT: return "INSTR_HDR_EMIT"; + case INSTR_HDR_EMIT_TX: return "INSTR_HDR_EMIT_TX"; + case INSTR_HDR_EMIT2_TX: return "INSTR_HDR_EMIT2_TX"; + case INSTR_HDR_EMIT3_TX: return "INSTR_HDR_EMIT3_TX"; + case INSTR_HDR_EMIT4_TX: return "INSTR_HDR_EMIT4_TX"; + case INSTR_HDR_EMIT5_TX: return "INSTR_HDR_EMIT5_TX"; + case INSTR_HDR_EMIT6_TX: return "INSTR_HDR_EMIT6_TX"; + case INSTR_HDR_EMIT7_TX: return "INSTR_HDR_EMIT7_TX"; + case INSTR_HDR_EMIT8_TX: return "INSTR_HDR_EMIT8_TX"; + + case INSTR_HDR_VALIDATE: return "INSTR_HDR_VALIDATE"; + case INSTR_HDR_INVALIDATE: return "INSTR_HDR_INVALIDATE"; + + case INSTR_MOV: return "INSTR_MOV"; + case INSTR_MOV_MH: return "INSTR_MOV_MH"; + case INSTR_MOV_HM: return "INSTR_MOV_HM"; + case INSTR_MOV_HH: return "INSTR_MOV_HH"; + case INSTR_MOV_I: return "INSTR_MOV_I"; + + case INSTR_DMA_HT: return "INSTR_DMA_HT"; + case INSTR_DMA_HT2: return "INSTR_DMA_HT2"; + case INSTR_DMA_HT3: return "INSTR_DMA_HT3"; + case INSTR_DMA_HT4: return "INSTR_DMA_HT4"; + case INSTR_DMA_HT5: return "INSTR_DMA_HT5"; + case INSTR_DMA_HT6: return "INSTR_DMA_HT6"; + case INSTR_DMA_HT7: return "INSTR_DMA_HT7"; + case INSTR_DMA_HT8: return "INSTR_DMA_HT8"; + + case INSTR_ALU_ADD: return "INSTR_ALU_ADD"; + case INSTR_ALU_ADD_MH: return "INSTR_ALU_ADD_MH"; + case INSTR_ALU_ADD_HM: return "INSTR_ALU_ADD_HM"; + case INSTR_ALU_ADD_HH: return "INSTR_ALU_ADD_HH"; + case INSTR_ALU_ADD_MI: return "INSTR_ALU_ADD_MI"; + case INSTR_ALU_ADD_HI: return "INSTR_ALU_ADD_HI"; + + case INSTR_ALU_SUB: return "INSTR_ALU_SUB"; + case INSTR_ALU_SUB_MH: return "INSTR_ALU_SUB_MH"; + case INSTR_ALU_SUB_HM: return "INSTR_ALU_SUB_HM"; + case INSTR_ALU_SUB_HH: return "INSTR_ALU_SUB_HH"; + case INSTR_ALU_SUB_MI: return "INSTR_ALU_SUB_MI"; + case INSTR_ALU_SUB_HI: return "INSTR_ALU_SUB_HI"; + + case INSTR_ALU_CKADD_FIELD: return "INSTR_ALU_CKADD_FIELD"; + case INSTR_ALU_CKADD_STRUCT20: return "INSTR_ALU_CKADD_STRUCT20"; + case INSTR_ALU_CKADD_STRUCT: return "INSTR_ALU_CKADD_STRUCT"; + case INSTR_ALU_CKSUB_FIELD: return "INSTR_ALU_CKSUB_FIELD"; + + case INSTR_ALU_AND: return "INSTR_ALU_AND"; + case INSTR_ALU_AND_MH: return "INSTR_ALU_AND_MH"; + case INSTR_ALU_AND_HM: return "INSTR_ALU_AND_HM"; + case INSTR_ALU_AND_HH: return "INSTR_ALU_AND_HH"; + case INSTR_ALU_AND_I: return "INSTR_ALU_AND_I"; + + case INSTR_ALU_OR: return "INSTR_ALU_OR"; + case INSTR_ALU_OR_MH: return "INSTR_ALU_OR_MH"; + case INSTR_ALU_OR_HM: return "INSTR_ALU_OR_HM"; + case INSTR_ALU_OR_HH: return "INSTR_ALU_OR_HH"; + case INSTR_ALU_OR_I: return "INSTR_ALU_OR_I"; + + case INSTR_ALU_XOR: return "INSTR_ALU_XOR"; + case INSTR_ALU_XOR_MH: return "INSTR_ALU_XOR_MH"; + case INSTR_ALU_XOR_HM: return "INSTR_ALU_XOR_HM"; + case INSTR_ALU_XOR_HH: return "INSTR_ALU_XOR_HH"; + case INSTR_ALU_XOR_I: return "INSTR_ALU_XOR_I"; + + case INSTR_ALU_SHL: return "INSTR_ALU_SHL"; + case INSTR_ALU_SHL_MH: return "INSTR_ALU_SHL_MH"; + case INSTR_ALU_SHL_HM: return "INSTR_ALU_SHL_HM"; + case INSTR_ALU_SHL_HH: return "INSTR_ALU_SHL_HH"; + case INSTR_ALU_SHL_MI: return "INSTR_ALU_SHL_MI"; + case INSTR_ALU_SHL_HI: return "INSTR_ALU_SHL_HI"; + + case INSTR_ALU_SHR: return "INSTR_ALU_SHR"; + case INSTR_ALU_SHR_MH: return "INSTR_ALU_SHR_MH"; + case INSTR_ALU_SHR_HM: return "INSTR_ALU_SHR_HM"; + case INSTR_ALU_SHR_HH: return "INSTR_ALU_SHR_HH"; + case INSTR_ALU_SHR_MI: return "INSTR_ALU_SHR_MI"; + case INSTR_ALU_SHR_HI: return "INSTR_ALU_SHR_HI"; + + case INSTR_REGPREFETCH_RH: return "INSTR_REGPREFETCH_RH"; + case INSTR_REGPREFETCH_RM: return "INSTR_REGPREFETCH_RM"; + case INSTR_REGPREFETCH_RI: return "INSTR_REGPREFETCH_RI"; + + case INSTR_REGRD_HRH: return "INSTR_REGRD_HRH"; + case INSTR_REGRD_HRM: return "INSTR_REGRD_HRM"; + case INSTR_REGRD_HRI: return "INSTR_REGRD_HRI"; + case INSTR_REGRD_MRH: return "INSTR_REGRD_MRH"; + case INSTR_REGRD_MRM: return "INSTR_REGRD_MRM"; + case INSTR_REGRD_MRI: return "INSTR_REGRD_MRI"; + + case INSTR_REGWR_RHH: return "INSTR_REGWR_RHH"; + case INSTR_REGWR_RHM: return "INSTR_REGWR_RHM"; + case INSTR_REGWR_RHI: return "INSTR_REGWR_RHI"; + case INSTR_REGWR_RMH: return "INSTR_REGWR_RMH"; + case INSTR_REGWR_RMM: return "INSTR_REGWR_RMM"; + case INSTR_REGWR_RMI: return "INSTR_REGWR_RMI"; + case INSTR_REGWR_RIH: return "INSTR_REGWR_RIH"; + case INSTR_REGWR_RIM: return "INSTR_REGWR_RIM"; + case INSTR_REGWR_RII: return "INSTR_REGWR_RII"; + + case INSTR_REGADD_RHH: return "INSTR_REGADD_RHH"; + case INSTR_REGADD_RHM: return "INSTR_REGADD_RHM"; + case INSTR_REGADD_RHI: return "INSTR_REGADD_RHI"; + case INSTR_REGADD_RMH: return "INSTR_REGADD_RMH"; + case INSTR_REGADD_RMM: return "INSTR_REGADD_RMM"; + case INSTR_REGADD_RMI: return "INSTR_REGADD_RMI"; + case INSTR_REGADD_RIH: return "INSTR_REGADD_RIH"; + case INSTR_REGADD_RIM: return "INSTR_REGADD_RIM"; + case INSTR_REGADD_RII: return "INSTR_REGADD_RII"; + + case INSTR_METPREFETCH_H: return "INSTR_METPREFETCH_H"; + case INSTR_METPREFETCH_M: return "INSTR_METPREFETCH_M"; + case INSTR_METPREFETCH_I: return "INSTR_METPREFETCH_I"; + + case INSTR_METER_HHM: return "INSTR_METER_HHM"; + case INSTR_METER_HHI: return "INSTR_METER_HHI"; + case INSTR_METER_HMM: return "INSTR_METER_HMM"; + case INSTR_METER_HMI: return "INSTR_METER_HMI"; + case INSTR_METER_MHM: return "INSTR_METER_MHM"; + case INSTR_METER_MHI: return "INSTR_METER_MHI"; + case INSTR_METER_MMM: return "INSTR_METER_MMM"; + case INSTR_METER_MMI: return "INSTR_METER_MMI"; + case INSTR_METER_IHM: return "INSTR_METER_IHM"; + case INSTR_METER_IHI: return "INSTR_METER_IHI"; + case INSTR_METER_IMM: return "INSTR_METER_IMM"; + case INSTR_METER_IMI: return "INSTR_METER_IMI"; + + case INSTR_TABLE: return "INSTR_TABLE"; + case INSTR_TABLE_AF: return "INSTR_TABLE_AF"; + case INSTR_SELECTOR: return "INSTR_SELECTOR"; + case INSTR_LEARNER: return "INSTR_LEARNER"; + case INSTR_LEARNER_AF: return "INSTR_LEARNER_AF"; + + case INSTR_LEARNER_LEARN: return "INSTR_LEARNER_LEARN"; + case INSTR_LEARNER_FORGET: return "INSTR_LEARNER_FORGET"; + + case INSTR_EXTERN_OBJ: return "INSTR_EXTERN_OBJ"; + case INSTR_EXTERN_FUNC: return "INSTR_EXTERN_FUNC"; + + case INSTR_JMP: return "INSTR_JMP"; + case INSTR_JMP_VALID: return "INSTR_JMP_VALID"; + case INSTR_JMP_INVALID: return "INSTR_JMP_INVALID"; + case INSTR_JMP_HIT: return "INSTR_JMP_HIT"; + case INSTR_JMP_MISS: return "INSTR_JMP_MISS"; + case INSTR_JMP_ACTION_HIT: return "INSTR_JMP_ACTION_HIT"; + case INSTR_JMP_ACTION_MISS: return "INSTR_JMP_ACTION_MISS"; + case INSTR_JMP_EQ: return "INSTR_JMP_EQ"; + case INSTR_JMP_EQ_MH: return "INSTR_JMP_EQ_MH"; + case INSTR_JMP_EQ_HM: return "INSTR_JMP_EQ_HM"; + case INSTR_JMP_EQ_HH: return "INSTR_JMP_EQ_HH"; + case INSTR_JMP_EQ_I: return "INSTR_JMP_EQ_I"; + case INSTR_JMP_NEQ: return "INSTR_JMP_NEQ"; + case INSTR_JMP_NEQ_MH: return "INSTR_JMP_NEQ_MH"; + case INSTR_JMP_NEQ_HM: return "INSTR_JMP_NEQ_HM"; + case INSTR_JMP_NEQ_HH: return "INSTR_JMP_NEQ_HH"; + case INSTR_JMP_NEQ_I: return "INSTR_JMP_NEQ_I"; + case INSTR_JMP_LT: return "INSTR_JMP_LT"; + case INSTR_JMP_LT_MH: return "INSTR_JMP_LT_MH"; + case INSTR_JMP_LT_HM: return "INSTR_JMP_LT_HM"; + case INSTR_JMP_LT_HH: return "INSTR_JMP_LT_HH"; + case INSTR_JMP_LT_MI: return "INSTR_JMP_LT_MI"; + case INSTR_JMP_LT_HI: return "INSTR_JMP_LT_HI"; + case INSTR_JMP_GT: return "INSTR_JMP_GT"; + case INSTR_JMP_GT_MH: return "INSTR_JMP_GT_MH"; + case INSTR_JMP_GT_HM: return "INSTR_JMP_GT_HM"; + case INSTR_JMP_GT_HH: return "INSTR_JMP_GT_HH"; + case INSTR_JMP_GT_MI: return "INSTR_JMP_GT_MI"; + case INSTR_JMP_GT_HI: return "INSTR_JMP_GT_HI"; + + case INSTR_RETURN: return "INSTR_RETURN"; + + default: return "INSTR_UNKNOWN"; + } +} + +typedef void +(*instruction_export_t)(struct instruction *, FILE *); + +static void +instr_io_export(struct instruction *instr, FILE *f) +{ + uint32_t n_io = 0, n_io_imm = 0, n_hdrs = 0, i; + + /* n_io, n_io_imm, n_hdrs. */ + if (instr->type == INSTR_RX || + instr->type == INSTR_TX || + instr->type == INSTR_HDR_EXTRACT_M || + (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX)) + n_io = 1; + + if (instr->type == INSTR_TX_I) + n_io_imm = 1; + + if (instr->type >= INSTR_HDR_EXTRACT && instr->type <= INSTR_HDR_EXTRACT8) + n_hdrs = 1 + (instr->type - INSTR_HDR_EXTRACT); + + if (instr->type == INSTR_HDR_EXTRACT_M || + instr->type == INSTR_HDR_LOOKAHEAD || + instr->type == INSTR_HDR_EMIT) + n_hdrs = 1; + + if (instr->type >= INSTR_HDR_EMIT_TX && instr->type <= INSTR_HDR_EMIT8_TX) + n_hdrs = 1 + (instr->type - INSTR_HDR_EMIT_TX); + + /* instr. */ + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n", + instr_type_to_name(instr)); + + /* instr.io. */ + fprintf(f, + "\t\t.io = {\n"); + + /* instr.io.io. */ + if (n_io) + fprintf(f, + "\t\t\t.io = {\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t},\n", + instr->io.io.offset, + instr->io.io.n_bits); + + if (n_io_imm) + fprintf(f, + "\t\t\t.io = {\n" + "\t\t\t\t.val = %u,\n" + "\t\t\t},\n", + instr->io.io.val); + + /* instr.io.hdr. */ + if (n_hdrs) { + fprintf(f, + "\t\t.hdr = {\n"); + + /* instr.io.hdr.header_id. */ + fprintf(f, + "\t\t\t.header_id = {"); + + for (i = 0; i < n_hdrs; i++) + fprintf(f, + "%u, ", + instr->io.hdr.header_id[i]); + + fprintf(f, + "},\n"); + + /* instr.io.hdr.struct_id. */ + fprintf(f, + "\t\t\t.struct_id = {"); + + for (i = 0; i < n_hdrs; i++) + fprintf(f, + "%u, ", + instr->io.hdr.struct_id[i]); + + fprintf(f, + "},\n"); + + /* instr.io.hdr.n_bytes. */ + fprintf(f, + "\t\t\t.n_bytes = {"); + + for (i = 0; i < n_hdrs; i++) + fprintf(f, + "%u, ", + instr->io.hdr.n_bytes[i]); + + fprintf(f, + "},\n"); + + /* instr.io.hdr - closing curly brace. */ + fprintf(f, + "\t\t\t}\n,"); + } + + /* instr.io - closing curly brace. */ + fprintf(f, + "\t\t},\n"); + + /* instr - closing curly brace. */ + fprintf(f, + "\t},\n"); +} + +static void +instr_hdr_validate_export(struct instruction *instr, FILE *f) +{ + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.valid = {\n" + "\t\t\t.header_id = %u,\n" + "\t\t},\n" + "\t},\n", + instr_type_to_name(instr), + instr->valid.header_id); +} + +static void +instr_mov_export(struct instruction *instr, FILE *f) +{ + if (instr->type != INSTR_MOV_I) + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.mov = {\n" + "\t\t\t.dst = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t},\n" + "\t\t\t.src = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t},\n" + "\t\t},\n" + "\t},\n", + instr_type_to_name(instr), + instr->mov.dst.struct_id, + instr->mov.dst.n_bits, + instr->mov.dst.offset, + instr->mov.src.struct_id, + instr->mov.src.n_bits, + instr->mov.src.offset); + else + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.mov = {\n" + "\t\t\t.dst = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t}\n," + "\t\t\t.src_val = %" PRIu64 ",\n" + "\t\t},\n" + "\t},\n", + instr_type_to_name(instr), + instr->mov.dst.struct_id, + instr->mov.dst.n_bits, + instr->mov.dst.offset, + instr->mov.src_val); +} + +static void +instr_dma_ht_export(struct instruction *instr, FILE *f) +{ + uint32_t n_dma = 0, i; + + /* n_dma. */ + n_dma = 1 + (instr->type - INSTR_DMA_HT); + + /* instr. */ + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n", + instr_type_to_name(instr)); + + /* instr.dma. */ + fprintf(f, + "\t\t.dma = {\n"); + + /* instr.dma.dst. */ + fprintf(f, + "\t\t\t.dst = {\n"); + + /* instr.dma.dst.header_id. */ + fprintf(f, + "\t\t\t\t.header_id = {"); + + for (i = 0; i < n_dma; i++) + fprintf(f, + "%u, ", + instr->dma.dst.header_id[i]); + + fprintf(f, + "},\n"); + + /* instr.dma.dst.struct_id. */ + fprintf(f, + "\t\t\t\t.struct_id = {"); + + for (i = 0; i < n_dma; i++) + fprintf(f, + "%u, ", + instr->dma.dst.struct_id[i]); + + fprintf(f, + "},\n"); + + /* instr.dma.dst - closing curly brace. */ + fprintf(f, + "\t\t\t},\n"); + + /* instr.dma.src. */ + fprintf(f, + "\t\t\t.src = {\n"); + + /* instr.dma.src.offset. */ + fprintf(f, + "\t\t\t\t.offset = {"); + + for (i = 0; i < n_dma; i++) + fprintf(f, + "%u, ", + instr->dma.src.offset[i]); + + fprintf(f, + "},\n"); + + /* instr.dma.src - closing curly brace. */ + fprintf(f, + "\t\t\t},\n"); + + /* instr.dma.n_bytes. */ + fprintf(f, + "\t\t\t.n_bytes = {"); + + for (i = 0; i < n_dma; i++) + fprintf(f, + "%u, ", + instr->dma.n_bytes[i]); + + fprintf(f, + "},\n"); + + /* instr.dma - closing curly brace. */ + fprintf(f, + "\t\t},\n"); + + /* instr - closing curly brace. */ + fprintf(f, + "\t},\n"); +} + +static void +instr_alu_export(struct instruction *instr, FILE *f) +{ + int imm = 0; + + if (instr->type == INSTR_ALU_ADD_MI || + instr->type == INSTR_ALU_ADD_HI || + instr->type == INSTR_ALU_SUB_MI || + instr->type == INSTR_ALU_SUB_HI || + instr->type == INSTR_ALU_SHL_MI || + instr->type == INSTR_ALU_SHL_HI || + instr->type == INSTR_ALU_SHR_MI || + instr->type == INSTR_ALU_SHR_HI || + instr->type == INSTR_ALU_AND_I || + instr->type == INSTR_ALU_OR_I || + instr->type == INSTR_ALU_XOR_I) + imm = 1; + + if (!imm) + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.alu = {\n" + "\t\t\t.dst = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t},\n" + "\t\t\t.src = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t},\n" + "\t\t},\n" + "\t},\n", + instr_type_to_name(instr), + instr->alu.dst.struct_id, + instr->alu.dst.n_bits, + instr->alu.dst.offset, + instr->alu.src.struct_id, + instr->alu.src.n_bits, + instr->alu.src.offset); + else + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.alu = {\n" + "\t\t\t.dst = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t}\n," + "\t\t\t.src_val = %" PRIu64 ",\n" + "\t\t},\n" + "\t},\n", + instr_type_to_name(instr), + instr->alu.dst.struct_id, + instr->alu.dst.n_bits, + instr->alu.dst.offset, + instr->alu.src_val); +} + +static void +instr_reg_export(struct instruction *instr __rte_unused, FILE *f __rte_unused) +{ + int prefetch = 0, idx_imm = 0, src_imm = 0; + + if (instr->type == INSTR_REGPREFETCH_RH || + instr->type == INSTR_REGPREFETCH_RM || + instr->type == INSTR_REGPREFETCH_RI) + prefetch = 1; + + /* index is the 3rd operand for the regrd instruction and the 2nd + * operand for the regwr and regadd instructions. + */ + if (instr->type == INSTR_REGPREFETCH_RI || + instr->type == INSTR_REGRD_HRI || + instr->type == INSTR_REGRD_MRI || + instr->type == INSTR_REGWR_RIH || + instr->type == INSTR_REGWR_RIM || + instr->type == INSTR_REGWR_RII || + instr->type == INSTR_REGADD_RIH || + instr->type == INSTR_REGADD_RIM || + instr->type == INSTR_REGADD_RII) + idx_imm = 1; + + /* src is the 3rd operand for the regwr and regadd instructions. */ + if (instr->type == INSTR_REGWR_RHI || + instr->type == INSTR_REGWR_RMI || + instr->type == INSTR_REGWR_RII || + instr->type == INSTR_REGADD_RHI || + instr->type == INSTR_REGADD_RMI || + instr->type == INSTR_REGADD_RII) + src_imm = 1; + + /* instr.regarray.regarray_id. */ + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.regarray = {\n" + "\t\t\t.regarray_id = %u,\n", + instr_type_to_name(instr), + instr->regarray.regarray_id); + + /* instr.regarray.idx / instr.regarray.idx_val. */ + if (!idx_imm) + fprintf(f, + "\t\t\t\t.idx = {\n" + "\t\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t\t.offset = %u,\n" + "\t\t\t\t},\n", + instr->regarray.idx.struct_id, + instr->regarray.idx.n_bits, + instr->regarray.idx.offset); + else + fprintf(f, + "\t\t\t\t.idx_val = %u,\n", + instr->regarray.idx_val); + + /* instr.regarray.dstsrc / instr.regarray.dstsrc_val. */ + if (!prefetch) { + if (!src_imm) + fprintf(f, + "\t\t\t\t.dstsrc = {\n" + "\t\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t\t.offset = %u,\n" + "\t\t\t\t},\n", + instr->regarray.dstsrc.struct_id, + instr->regarray.dstsrc.n_bits, + instr->regarray.dstsrc.offset); + else + fprintf(f, + "\t\t\t\t.dstsrc_val = %" PRIu64 ",\n", + instr->regarray.dstsrc_val); + } + + /* instr.regarray and instr - closing curly braces. */ + fprintf(f, + "\t\t},\n" + "\t},\n"); +} + +static void +instr_meter_export(struct instruction *instr __rte_unused, FILE *f __rte_unused) +{ + int prefetch = 0, idx_imm = 0, color_in_imm = 0; + + if (instr->type == INSTR_METPREFETCH_H || + instr->type == INSTR_METPREFETCH_M || + instr->type == INSTR_METPREFETCH_I) + prefetch = 1; + + /* idx_imm. */ + if (instr->type == INSTR_METPREFETCH_I || + instr->type == INSTR_METER_IHM || + instr->type == INSTR_METER_IHI || + instr->type == INSTR_METER_IMM || + instr->type == INSTR_METER_IMI) + idx_imm = 1; + + /* color_in_imm. */ + if (instr->type == INSTR_METER_HHI || + instr->type == INSTR_METER_HMI || + instr->type == INSTR_METER_MHI || + instr->type == INSTR_METER_MMI || + instr->type == INSTR_METER_IHI || + instr->type == INSTR_METER_IMI) + color_in_imm = 1; + + /* instr.meter.metarray_id. */ + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.meter = {\n" + "\t\t\t.metarray_id = %u,\n", + instr_type_to_name(instr), + instr->meter.metarray_id); + + /* instr.meter.idx / instr.meter.idx_val. */ + if (!idx_imm) + fprintf(f, + "\t\t\t.idx = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t},\n", + instr->meter.idx.struct_id, + instr->meter.idx.n_bits, + instr->meter.idx.offset); + else + fprintf(f, + "\t\t\t.idx_val = %u,\n", + instr->meter.idx_val); + + if (!prefetch) { + /* instr.meter.length. */ + fprintf(f, + "\t\t\t.length = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t},\n", + instr->meter.length.struct_id, + instr->meter.length.n_bits, + instr->meter.length.offset); + + /* instr.meter.color_in / instr.meter.color_in_val. */ + if (!color_in_imm) + fprintf(f, + "\t\t\t.color_in = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t},\n", + instr->meter.color_in.struct_id, + instr->meter.color_in.n_bits, + instr->meter.color_in.offset); + else + fprintf(f, + "\t\t\t.color_in_val = %u,\n", + (uint32_t)instr->meter.color_in_val); + + /* instr.meter.color_out. */ + fprintf(f, + "\t\t\t.color_out = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t},\n", + instr->meter.color_out.struct_id, + instr->meter.color_out.n_bits, + instr->meter.color_out.offset); + } + + /* instr.meter and instr - closing curly braces. */ + fprintf(f, + "\t\t},\n" + "\t},\n"); +} + +static void +instr_table_export(struct instruction *instr, + FILE *f) +{ + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.table = {\n" + "\t\t\t.table_id = %u,\n" + "\t\t},\n" + "\t},\n", + instr_type_to_name(instr), + instr->table.table_id); +} + +static void +instr_learn_export(struct instruction *instr, FILE *f) +{ + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.learn = {\n" + "\t\t\t\t.action_id = %u,\n" + "\t\t},\n" + "\t},\n", + instr_type_to_name(instr), + instr->learn.action_id); +} + +static void +instr_forget_export(struct instruction *instr, FILE *f) +{ + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t},\n", + instr_type_to_name(instr)); +} + +static void +instr_extern_export(struct instruction *instr, FILE *f) +{ + if (instr->type == INSTR_EXTERN_OBJ) + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.ext_obj = {\n" + "\t\t\t.ext_obj_id = %u,\n" + "\t\t\t.func_id = %u,\n" + "\t\t},\n" + "\t},\n", + instr_type_to_name(instr), + instr->ext_obj.ext_obj_id, + instr->ext_obj.func_id); + else + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.ext_func = {\n" + "\t\t\t.ext_func_id = %u,\n" + "\t\t},\n" + "\t},\n", + instr_type_to_name(instr), + instr->ext_func.ext_func_id); +} + +static void +instr_jmp_export(struct instruction *instr, FILE *f __rte_unused) +{ + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.jmp = {\n" + "\t\t\t.ip = NULL,\n", + instr_type_to_name(instr)); + + switch (instr->type) { + case INSTR_JMP_VALID: + case INSTR_JMP_INVALID: + fprintf(f, + "\t\t\t.header_id = %u,\n", + instr->jmp.header_id); + break; + + case INSTR_JMP_ACTION_HIT: + case INSTR_JMP_ACTION_MISS: + fprintf(f, + "\t\t\t.action_id = %u,\n", + instr->jmp.action_id); + break; + + case INSTR_JMP_EQ: + case INSTR_JMP_EQ_MH: + case INSTR_JMP_EQ_HM: + case INSTR_JMP_EQ_HH: + case INSTR_JMP_NEQ: + case INSTR_JMP_NEQ_MH: + case INSTR_JMP_NEQ_HM: + case INSTR_JMP_NEQ_HH: + case INSTR_JMP_LT: + case INSTR_JMP_LT_MH: + case INSTR_JMP_LT_HM: + case INSTR_JMP_LT_HH: + case INSTR_JMP_GT: + case INSTR_JMP_GT_MH: + case INSTR_JMP_GT_HM: + case INSTR_JMP_GT_HH: + fprintf(f, + "\t\t\t.a = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t},\n" + "\t\t\t.b = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t},\n", + instr->jmp.a.struct_id, + instr->jmp.a.n_bits, + instr->jmp.a.offset, + instr->jmp.b.struct_id, + instr->jmp.b.n_bits, + instr->jmp.b.offset); + break; + + case INSTR_JMP_EQ_I: + case INSTR_JMP_NEQ_I: + case INSTR_JMP_LT_MI: + case INSTR_JMP_LT_HI: + case INSTR_JMP_GT_MI: + case INSTR_JMP_GT_HI: + fprintf(f, + "\t\t\t.a = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t}\n," + "\t\t\t.b_val = %" PRIu64 ",\n", + instr->jmp.a.struct_id, + instr->jmp.a.n_bits, + instr->jmp.a.offset, + instr->jmp.b_val); + break; + + default: + break; + } + + fprintf(f, + "\t\t},\n" + "\t},\n"); +} + +static void +instr_return_export(struct instruction *instr, + FILE *f) +{ + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n", + instr_type_to_name(instr)); + + fprintf(f, + "\t},\n"); +} + +static instruction_export_t export_table[] = { + [INSTR_RX] = instr_io_export, + + [INSTR_TX] = instr_io_export, + [INSTR_TX_I] = instr_io_export, + + [INSTR_HDR_EXTRACT] = instr_io_export, + [INSTR_HDR_EXTRACT2] = instr_io_export, + [INSTR_HDR_EXTRACT3] = instr_io_export, + [INSTR_HDR_EXTRACT4] = instr_io_export, + [INSTR_HDR_EXTRACT5] = instr_io_export, + [INSTR_HDR_EXTRACT6] = instr_io_export, + [INSTR_HDR_EXTRACT7] = instr_io_export, + [INSTR_HDR_EXTRACT8] = instr_io_export, + + [INSTR_HDR_EXTRACT_M] = instr_io_export, + + [INSTR_HDR_LOOKAHEAD] = instr_io_export, + + [INSTR_HDR_EMIT] = instr_io_export, + [INSTR_HDR_EMIT_TX] = instr_io_export, + [INSTR_HDR_EMIT2_TX] = instr_io_export, + [INSTR_HDR_EMIT3_TX] = instr_io_export, + [INSTR_HDR_EMIT4_TX] = instr_io_export, + [INSTR_HDR_EMIT5_TX] = instr_io_export, + [INSTR_HDR_EMIT6_TX] = instr_io_export, + [INSTR_HDR_EMIT7_TX] = instr_io_export, + [INSTR_HDR_EMIT8_TX] = instr_io_export, + + [INSTR_HDR_VALIDATE] = instr_hdr_validate_export, + [INSTR_HDR_INVALIDATE] = instr_hdr_validate_export, + + [INSTR_MOV] = instr_mov_export, + [INSTR_MOV_MH] = instr_mov_export, + [INSTR_MOV_HM] = instr_mov_export, + [INSTR_MOV_HH] = instr_mov_export, + [INSTR_MOV_I] = instr_mov_export, + + [INSTR_DMA_HT] = instr_dma_ht_export, + [INSTR_DMA_HT2] = instr_dma_ht_export, + [INSTR_DMA_HT3] = instr_dma_ht_export, + [INSTR_DMA_HT4] = instr_dma_ht_export, + [INSTR_DMA_HT5] = instr_dma_ht_export, + [INSTR_DMA_HT6] = instr_dma_ht_export, + [INSTR_DMA_HT7] = instr_dma_ht_export, + [INSTR_DMA_HT8] = instr_dma_ht_export, + + [INSTR_ALU_ADD] = instr_alu_export, + [INSTR_ALU_ADD_MH] = instr_alu_export, + [INSTR_ALU_ADD_HM] = instr_alu_export, + [INSTR_ALU_ADD_HH] = instr_alu_export, + [INSTR_ALU_ADD_MI] = instr_alu_export, + [INSTR_ALU_ADD_HI] = instr_alu_export, + + [INSTR_ALU_SUB] = instr_alu_export, + [INSTR_ALU_SUB_MH] = instr_alu_export, + [INSTR_ALU_SUB_HM] = instr_alu_export, + [INSTR_ALU_SUB_HH] = instr_alu_export, + [INSTR_ALU_SUB_MI] = instr_alu_export, + [INSTR_ALU_SUB_HI] = instr_alu_export, + + [INSTR_ALU_CKADD_FIELD] = instr_alu_export, + [INSTR_ALU_CKADD_STRUCT] = instr_alu_export, + [INSTR_ALU_CKADD_STRUCT20] = instr_alu_export, + [INSTR_ALU_CKSUB_FIELD] = instr_alu_export, + + [INSTR_ALU_AND] = instr_alu_export, + [INSTR_ALU_AND_MH] = instr_alu_export, + [INSTR_ALU_AND_HM] = instr_alu_export, + [INSTR_ALU_AND_HH] = instr_alu_export, + [INSTR_ALU_AND_I] = instr_alu_export, + + [INSTR_ALU_OR] = instr_alu_export, + [INSTR_ALU_OR_MH] = instr_alu_export, + [INSTR_ALU_OR_HM] = instr_alu_export, + [INSTR_ALU_OR_HH] = instr_alu_export, + [INSTR_ALU_OR_I] = instr_alu_export, + + [INSTR_ALU_XOR] = instr_alu_export, + [INSTR_ALU_XOR_MH] = instr_alu_export, + [INSTR_ALU_XOR_HM] = instr_alu_export, + [INSTR_ALU_XOR_HH] = instr_alu_export, + [INSTR_ALU_XOR_I] = instr_alu_export, + + [INSTR_ALU_SHL] = instr_alu_export, + [INSTR_ALU_SHL_MH] = instr_alu_export, + [INSTR_ALU_SHL_HM] = instr_alu_export, + [INSTR_ALU_SHL_HH] = instr_alu_export, + [INSTR_ALU_SHL_MI] = instr_alu_export, + [INSTR_ALU_SHL_HI] = instr_alu_export, + + [INSTR_ALU_SHR] = instr_alu_export, + [INSTR_ALU_SHR_MH] = instr_alu_export, + [INSTR_ALU_SHR_HM] = instr_alu_export, + [INSTR_ALU_SHR_HH] = instr_alu_export, + [INSTR_ALU_SHR_MI] = instr_alu_export, + [INSTR_ALU_SHR_HI] = instr_alu_export, + + [INSTR_REGPREFETCH_RH] = instr_reg_export, + [INSTR_REGPREFETCH_RM] = instr_reg_export, + [INSTR_REGPREFETCH_RI] = instr_reg_export, + + [INSTR_REGRD_HRH] = instr_reg_export, + [INSTR_REGRD_HRM] = instr_reg_export, + [INSTR_REGRD_MRH] = instr_reg_export, + [INSTR_REGRD_MRM] = instr_reg_export, + [INSTR_REGRD_HRI] = instr_reg_export, + [INSTR_REGRD_MRI] = instr_reg_export, + + [INSTR_REGWR_RHH] = instr_reg_export, + [INSTR_REGWR_RHM] = instr_reg_export, + [INSTR_REGWR_RMH] = instr_reg_export, + [INSTR_REGWR_RMM] = instr_reg_export, + [INSTR_REGWR_RHI] = instr_reg_export, + [INSTR_REGWR_RMI] = instr_reg_export, + [INSTR_REGWR_RIH] = instr_reg_export, + [INSTR_REGWR_RIM] = instr_reg_export, + [INSTR_REGWR_RII] = instr_reg_export, + + [INSTR_REGADD_RHH] = instr_reg_export, + [INSTR_REGADD_RHM] = instr_reg_export, + [INSTR_REGADD_RMH] = instr_reg_export, + [INSTR_REGADD_RMM] = instr_reg_export, + [INSTR_REGADD_RHI] = instr_reg_export, + [INSTR_REGADD_RMI] = instr_reg_export, + [INSTR_REGADD_RIH] = instr_reg_export, + [INSTR_REGADD_RIM] = instr_reg_export, + [INSTR_REGADD_RII] = instr_reg_export, + + [INSTR_METPREFETCH_H] = instr_meter_export, + [INSTR_METPREFETCH_M] = instr_meter_export, + [INSTR_METPREFETCH_I] = instr_meter_export, + + [INSTR_METER_HHM] = instr_meter_export, + [INSTR_METER_HHI] = instr_meter_export, + [INSTR_METER_HMM] = instr_meter_export, + [INSTR_METER_HMI] = instr_meter_export, + [INSTR_METER_MHM] = instr_meter_export, + [INSTR_METER_MHI] = instr_meter_export, + [INSTR_METER_MMM] = instr_meter_export, + [INSTR_METER_MMI] = instr_meter_export, + [INSTR_METER_IHM] = instr_meter_export, + [INSTR_METER_IHI] = instr_meter_export, + [INSTR_METER_IMM] = instr_meter_export, + [INSTR_METER_IMI] = instr_meter_export, + + [INSTR_TABLE] = instr_table_export, + [INSTR_TABLE_AF] = instr_table_export, + [INSTR_SELECTOR] = instr_table_export, + [INSTR_LEARNER] = instr_table_export, + [INSTR_LEARNER_AF] = instr_table_export, + + [INSTR_LEARNER_LEARN] = instr_learn_export, + [INSTR_LEARNER_FORGET] = instr_forget_export, + + [INSTR_EXTERN_OBJ] = instr_extern_export, + [INSTR_EXTERN_FUNC] = instr_extern_export, + + [INSTR_JMP] = instr_jmp_export, + [INSTR_JMP_VALID] = instr_jmp_export, + [INSTR_JMP_INVALID] = instr_jmp_export, + [INSTR_JMP_HIT] = instr_jmp_export, + [INSTR_JMP_MISS] = instr_jmp_export, + [INSTR_JMP_ACTION_HIT] = instr_jmp_export, + [INSTR_JMP_ACTION_MISS] = instr_jmp_export, + + [INSTR_JMP_EQ] = instr_jmp_export, + [INSTR_JMP_EQ_MH] = instr_jmp_export, + [INSTR_JMP_EQ_HM] = instr_jmp_export, + [INSTR_JMP_EQ_HH] = instr_jmp_export, + [INSTR_JMP_EQ_I] = instr_jmp_export, + + [INSTR_JMP_NEQ] = instr_jmp_export, + [INSTR_JMP_NEQ_MH] = instr_jmp_export, + [INSTR_JMP_NEQ_HM] = instr_jmp_export, + [INSTR_JMP_NEQ_HH] = instr_jmp_export, + [INSTR_JMP_NEQ_I] = instr_jmp_export, + + [INSTR_JMP_LT] = instr_jmp_export, + [INSTR_JMP_LT_MH] = instr_jmp_export, + [INSTR_JMP_LT_HM] = instr_jmp_export, + [INSTR_JMP_LT_HH] = instr_jmp_export, + [INSTR_JMP_LT_MI] = instr_jmp_export, + [INSTR_JMP_LT_HI] = instr_jmp_export, + + [INSTR_JMP_GT] = instr_jmp_export, + [INSTR_JMP_GT_MH] = instr_jmp_export, + [INSTR_JMP_GT_HM] = instr_jmp_export, + [INSTR_JMP_GT_HH] = instr_jmp_export, + [INSTR_JMP_GT_MI] = instr_jmp_export, + [INSTR_JMP_GT_HI] = instr_jmp_export, + + [INSTR_RETURN] = instr_return_export, +}; + +static void +action_data_codegen(struct action *a, FILE *f) +{ + uint32_t i; + + fprintf(f, + "static const struct instruction action_%s_instructions[] = {\n", + a->name); + + for (i = 0; i < a->n_instructions; i++) { + struct instruction *instr = &a->instructions[i]; + instruction_export_t func = export_table[instr->type]; + + func(instr, f); + } + + fprintf(f, "};\n"); +} + +static const char * +instr_type_to_func(struct instruction *instr) +{ + switch (instr->type) { + case INSTR_RX: return NULL; + + case INSTR_TX: return "__instr_tx_exec"; + case INSTR_TX_I: return "__instr_tx_i_exec"; + + case INSTR_HDR_EXTRACT: return "__instr_hdr_extract_exec"; + case INSTR_HDR_EXTRACT2: return "__instr_hdr_extract2_exec"; + case INSTR_HDR_EXTRACT3: return "__instr_hdr_extract3_exec"; + case INSTR_HDR_EXTRACT4: return "__instr_hdr_extract4_exec"; + case INSTR_HDR_EXTRACT5: return "__instr_hdr_extract5_exec"; + case INSTR_HDR_EXTRACT6: return "__instr_hdr_extract6_exec"; + case INSTR_HDR_EXTRACT7: return "__instr_hdr_extract7_exec"; + case INSTR_HDR_EXTRACT8: return "__instr_hdr_extract8_exec"; + + case INSTR_HDR_EXTRACT_M: return "__instr_hdr_extract_m_exec"; + + case INSTR_HDR_LOOKAHEAD: return "__instr_hdr_lookahead_exec"; + + case INSTR_HDR_EMIT: return "__instr_hdr_emit_exec"; + case INSTR_HDR_EMIT_TX: return "__instr_hdr_emit_tx_exec"; + case INSTR_HDR_EMIT2_TX: return "__instr_hdr_emit2_tx_exec"; + case INSTR_HDR_EMIT3_TX: return "__instr_hdr_emit3_tx_exec"; + case INSTR_HDR_EMIT4_TX: return "__instr_hdr_emit4_tx_exec"; + case INSTR_HDR_EMIT5_TX: return "__instr_hdr_emit5_tx_exec"; + case INSTR_HDR_EMIT6_TX: return "__instr_hdr_emit6_tx_exec"; + case INSTR_HDR_EMIT7_TX: return "__instr_hdr_emit7_tx_exec"; + case INSTR_HDR_EMIT8_TX: return "__instr_hdr_emit8_tx_exec"; + + case INSTR_HDR_VALIDATE: return "__instr_hdr_validate_exec"; + case INSTR_HDR_INVALIDATE: return "__instr_hdr_invalidate_exec"; + + case INSTR_MOV: return "__instr_mov_exec"; + case INSTR_MOV_MH: return "__instr_mov_mh_exec"; + case INSTR_MOV_HM: return "__instr_mov_hm_exec"; + case INSTR_MOV_HH: return "__instr_mov_hh_exec"; + case INSTR_MOV_I: return "__instr_mov_i_exec"; + + case INSTR_DMA_HT: return "__instr_dma_ht_exec"; + case INSTR_DMA_HT2: return "__instr_dma_ht2_exec"; + case INSTR_DMA_HT3: return "__instr_dma_ht3_exec"; + case INSTR_DMA_HT4: return "__instr_dma_ht4_exec"; + case INSTR_DMA_HT5: return "__instr_dma_ht5_exec"; + case INSTR_DMA_HT6: return "__instr_dma_ht6_exec"; + case INSTR_DMA_HT7: return "__instr_dma_ht7_exec"; + case INSTR_DMA_HT8: return "__instr_dma_ht8_exec"; + + case INSTR_ALU_ADD: return "__instr_alu_add_exec"; + case INSTR_ALU_ADD_MH: return "__instr_alu_add_mh_exec"; + case INSTR_ALU_ADD_HM: return "__instr_alu_add_hm_exec"; + case INSTR_ALU_ADD_HH: return "__instr_alu_add_hh_exec"; + case INSTR_ALU_ADD_MI: return "__instr_alu_add_mi_exec"; + case INSTR_ALU_ADD_HI: return "__instr_alu_add_hi_exec"; + + case INSTR_ALU_SUB: return "__instr_alu_sub_exec"; + case INSTR_ALU_SUB_MH: return "__instr_alu_sub_mh_exec"; + case INSTR_ALU_SUB_HM: return "__instr_alu_sub_hm_exec"; + case INSTR_ALU_SUB_HH: return "__instr_alu_sub_hh_exec"; + case INSTR_ALU_SUB_MI: return "__instr_alu_sub_mi_exec"; + case INSTR_ALU_SUB_HI: return "__instr_alu_sub_hi_exec"; + + case INSTR_ALU_CKADD_FIELD: return "__instr_alu_ckadd_field_exec"; + case INSTR_ALU_CKADD_STRUCT20: return "__instr_alu_ckadd_struct20_exec"; + case INSTR_ALU_CKADD_STRUCT: return "__instr_alu_ckadd_struct_exec"; + case INSTR_ALU_CKSUB_FIELD: return "__instr_alu_cksub_field_exec"; + + case INSTR_ALU_AND: return "__instr_alu_and_exec"; + case INSTR_ALU_AND_MH: return "__instr_alu_and_mh_exec"; + case INSTR_ALU_AND_HM: return "__instr_alu_and_hm_exec"; + case INSTR_ALU_AND_HH: return "__instr_alu_and_hh_exec"; + case INSTR_ALU_AND_I: return "__instr_alu_and_i_exec"; + + case INSTR_ALU_OR: return "__instr_alu_or_exec"; + case INSTR_ALU_OR_MH: return "__instr_alu_or_mh_exec"; + case INSTR_ALU_OR_HM: return "__instr_alu_or_hm_exec"; + case INSTR_ALU_OR_HH: return "__instr_alu_or_hh_exec"; + case INSTR_ALU_OR_I: return "__instr_alu_or_i_exec"; + + case INSTR_ALU_XOR: return "__instr_alu_xor_exec"; + case INSTR_ALU_XOR_MH: return "__instr_alu_xor_mh_exec"; + case INSTR_ALU_XOR_HM: return "__instr_alu_xor_hm_exec"; + case INSTR_ALU_XOR_HH: return "__instr_alu_xor_hh_exec"; + case INSTR_ALU_XOR_I: return "__instr_alu_xor_i_exec"; + + case INSTR_ALU_SHL: return "__instr_alu_shl_exec"; + case INSTR_ALU_SHL_MH: return "__instr_alu_shl_mh_exec"; + case INSTR_ALU_SHL_HM: return "__instr_alu_shl_hm_exec"; + case INSTR_ALU_SHL_HH: return "__instr_alu_shl_hh_exec"; + case INSTR_ALU_SHL_MI: return "__instr_alu_shl_mi_exec"; + case INSTR_ALU_SHL_HI: return "__instr_alu_shl_hi_exec"; + + case INSTR_ALU_SHR: return "__instr_alu_shr_exec"; + case INSTR_ALU_SHR_MH: return "__instr_alu_shr_mh_exec"; + case INSTR_ALU_SHR_HM: return "__instr_alu_shr_hm_exec"; + case INSTR_ALU_SHR_HH: return "__instr_alu_shr_hh_exec"; + case INSTR_ALU_SHR_MI: return "__instr_alu_shr_mi_exec"; + case INSTR_ALU_SHR_HI: return "__instr_alu_shr_hi_exec"; + + case INSTR_REGPREFETCH_RH: return "__instr_regprefetch_rh_exec"; + case INSTR_REGPREFETCH_RM: return "__instr_regprefetch_rm_exec"; + case INSTR_REGPREFETCH_RI: return "__instr_regprefetch_ri_exec"; + + case INSTR_REGRD_HRH: return "__instr_regrd_hrh_exec"; + case INSTR_REGRD_HRM: return "__instr_regrd_hrm_exec"; + case INSTR_REGRD_HRI: return "__instr_regrd_hri_exec"; + case INSTR_REGRD_MRH: return "__instr_regrd_mrh_exec"; + case INSTR_REGRD_MRM: return "__instr_regrd_mrm_exec"; + case INSTR_REGRD_MRI: return "__instr_regrd_mri_exec"; + + case INSTR_REGWR_RHH: return "__instr_regwr_rhh_exec"; + case INSTR_REGWR_RHM: return "__instr_regwr_rhm_exec"; + case INSTR_REGWR_RHI: return "__instr_regwr_rhi_exec"; + case INSTR_REGWR_RMH: return "__instr_regwr_rmh_exec"; + case INSTR_REGWR_RMM: return "__instr_regwr_rmm_exec"; + case INSTR_REGWR_RMI: return "__instr_regwr_rmi_exec"; + case INSTR_REGWR_RIH: return "__instr_regwr_rih_exec"; + case INSTR_REGWR_RIM: return "__instr_regwr_rim_exec"; + case INSTR_REGWR_RII: return "__instr_regwr_rii_exec"; + + case INSTR_REGADD_RHH: return "__instr_regadd_rhh_exec"; + case INSTR_REGADD_RHM: return "__instr_regadd_rhm_exec"; + case INSTR_REGADD_RHI: return "__instr_regadd_rhi_exec"; + case INSTR_REGADD_RMH: return "__instr_regadd_rmh_exec"; + case INSTR_REGADD_RMM: return "__instr_regadd_rmm_exec"; + case INSTR_REGADD_RMI: return "__instr_regadd_rmi_exec"; + case INSTR_REGADD_RIH: return "__instr_regadd_rih_exec"; + case INSTR_REGADD_RIM: return "__instr_regadd_rim_exec"; + case INSTR_REGADD_RII: return "__instr_regadd_rii_exec"; + + case INSTR_METPREFETCH_H: return "__instr_metprefetch_h_exec"; + case INSTR_METPREFETCH_M: return "__instr_metprefetch_m_exec"; + case INSTR_METPREFETCH_I: return "__instr_metprefetch_i_exec"; + + case INSTR_METER_HHM: return "__instr_meter_hhm_exec"; + case INSTR_METER_HHI: return "__instr_meter_hhi_exec"; + case INSTR_METER_HMM: return "__instr_meter_hmm_exec"; + case INSTR_METER_HMI: return "__instr_meter_hmi_exec"; + case INSTR_METER_MHM: return "__instr_meter_mhm_exec"; + case INSTR_METER_MHI: return "__instr_meter_mhi_exec"; + case INSTR_METER_MMM: return "__instr_meter_mmm_exec"; + case INSTR_METER_MMI: return "__instr_meter_mmi_exec"; + case INSTR_METER_IHM: return "__instr_meter_ihm_exec"; + case INSTR_METER_IHI: return "__instr_meter_ihi_exec"; + case INSTR_METER_IMM: return "__instr_meter_imm_exec"; + case INSTR_METER_IMI: return "__instr_meter_imi_exec"; + + case INSTR_TABLE: return NULL; + case INSTR_TABLE_AF: return NULL; + case INSTR_SELECTOR: return NULL; + case INSTR_LEARNER: return NULL; + case INSTR_LEARNER_AF: return NULL; + + case INSTR_LEARNER_LEARN: return "__instr_learn_exec"; + case INSTR_LEARNER_FORGET: return "__instr_forget_exec"; + + case INSTR_EXTERN_OBJ: return NULL; + case INSTR_EXTERN_FUNC: return NULL; + + case INSTR_JMP: return NULL; + case INSTR_JMP_VALID: return NULL; + case INSTR_JMP_INVALID: return NULL; + case INSTR_JMP_HIT: return NULL; + case INSTR_JMP_MISS: return NULL; + case INSTR_JMP_ACTION_HIT: return NULL; + case INSTR_JMP_ACTION_MISS: return NULL; + case INSTR_JMP_EQ: return NULL; + case INSTR_JMP_EQ_MH: return NULL; + case INSTR_JMP_EQ_HM: return NULL; + case INSTR_JMP_EQ_HH: return NULL; + case INSTR_JMP_EQ_I: return NULL; + case INSTR_JMP_NEQ: return NULL; + case INSTR_JMP_NEQ_MH: return NULL; + case INSTR_JMP_NEQ_HM: return NULL; + case INSTR_JMP_NEQ_HH: return NULL; + case INSTR_JMP_NEQ_I: return NULL; + case INSTR_JMP_LT: return NULL; + case INSTR_JMP_LT_MH: return NULL; + case INSTR_JMP_LT_HM: return NULL; + case INSTR_JMP_LT_HH: return NULL; + case INSTR_JMP_LT_MI: return NULL; + case INSTR_JMP_LT_HI: return NULL; + case INSTR_JMP_GT: return NULL; + case INSTR_JMP_GT_MH: return NULL; + case INSTR_JMP_GT_HM: return NULL; + case INSTR_JMP_GT_HH: return NULL; + case INSTR_JMP_GT_MI: return NULL; + case INSTR_JMP_GT_HI: return NULL; + + case INSTR_RETURN: return NULL; + + default: return NULL; + } +} + +static void +action_instr_does_tx_codegen(struct action *a, + uint32_t instr_pos, + struct instruction *instr, + FILE *f) +{ + fprintf(f, + "%s(p, t, &action_%s_instructions[%u]);\n" + "\tthread_ip_reset(p, t);\n" + "\tinstr_rx_exec(p);\n" + "\treturn;\n", + instr_type_to_func(instr), + a->name, + instr_pos); +} + +static void +action_instr_extern_obj_codegen(struct action *a, + uint32_t instr_pos, + FILE *f) +{ + fprintf(f, + "while (!__instr_extern_obj_exec(p, t, &action_%s_instructions[%u]));\n", + a->name, + instr_pos); +} + +static void +action_instr_extern_func_codegen(struct action *a, + uint32_t instr_pos, + FILE *f) +{ + fprintf(f, + "while (!__instr_extern_func_exec(p, t, &action_%s_instructions[%u]));\n", + a->name, + instr_pos); +} + +static void +action_instr_jmp_codegen(struct action *a, + uint32_t instr_pos, + struct instruction *instr, + struct instruction_data *data, + FILE *f) +{ + switch (instr->type) { + case INSTR_JMP: + fprintf(f, + "goto %s;\n", + data->jmp_label); + return; + + case INSTR_JMP_VALID: + fprintf(f, + "if (HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_INVALID: + fprintf(f, + "if (!HEADER_VALID(t, action_%s_instructions[%u].jmp.header_id))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_HIT: + fprintf(f, + "if (t->hit)\n" + "\t\tgoto %s;\n", + data->jmp_label); + return; + + case INSTR_JMP_MISS: + fprintf(f, + "if (!t->hit)\n" + "\t\tgoto %s;\n", + data->jmp_label); + return; + + case INSTR_JMP_ACTION_HIT: + fprintf(f, + "if (t->action_id == action_%s_instructions[%u].jmp.action_id)\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_ACTION_MISS: + fprintf(f, + "if (t->action_id != action_%s_instructions[%u].jmp.action_id)\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_EQ: + fprintf(f, + "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " + "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_EQ_MH: + fprintf(f, + "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " + "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_EQ_HM: + fprintf(f, + "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == " + "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_EQ_HH: + fprintf(f, + "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) == " + "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_EQ_I: + fprintf(f, + "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) == " + "action_%s_instructions[%u].jmp.b_val)\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_NEQ: + fprintf(f, + "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " + "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_NEQ_MH: + fprintf(f, + "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " + "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_NEQ_HM: + fprintf(f, + "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != " + "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_NEQ_HH: + fprintf(f, + "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) != " + "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_NEQ_I: + fprintf(f, + "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) != " + "action_%s_instructions[%u].jmp.b_val)\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_LT: + fprintf(f, + "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " + "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_LT_MH: + fprintf(f, + "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " + "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_LT_HM: + fprintf(f, + "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " + "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_LT_HH: + fprintf(f, + "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " + "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_LT_MI: + fprintf(f, + "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) < " + "action_%s_instructions[%u].jmp.b_val)\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_LT_HI: + fprintf(f, + "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) < " + "action_%s_instructions[%u].jmp.b_val)\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_GT: + fprintf(f, + "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " + "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_GT_MH: + fprintf(f, + "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " + "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_GT_HM: + fprintf(f, + "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " + "instr_operand_hbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_GT_HH: + fprintf(f, + "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " + "instr_operand_nbo(t, &action_%s_instructions[%u].jmp.b))\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_GT_MI: + fprintf(f, + "if (instr_operand_hbo(t, &action_%s_instructions[%u].jmp.a) > " + "action_%s_instructions[%u].jmp.b_val)\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + case INSTR_JMP_GT_HI: + fprintf(f, + "if (instr_operand_nbo(t, &action_%s_instructions[%u].jmp.a) > " + "action_%s_instructions[%u].jmp.b_val)\n" + "\t\tgoto %s;\n", + a->name, + instr_pos, + a->name, + instr_pos, + data->jmp_label); + return; + + default: + return; + } +} + +static void +action_instr_return_codegen(FILE *f) +{ + fprintf(f, + "return;\n"); +} + +static void +action_instr_codegen(struct action *a, FILE *f) +{ + uint32_t i; + + fprintf(f, + "void\n" + "action_%s_run(struct rte_swx_pipeline *p)\n" + "{\n" + "\tstruct thread *t = &p->threads[p->thread_id];\n" + "\n", + a->name); + + for (i = 0; i < a->n_instructions; i++) { + struct instruction *instr = &a->instructions[i]; + struct instruction_data *data = &a->instruction_data[i]; + + /* Label, if present. */ + if (data->label[0]) + fprintf(f, "\n%s : ", data->label); + else + fprintf(f, "\n\t"); + + /* TX instruction type. */ + if (instruction_does_tx(instr)) { + action_instr_does_tx_codegen(a, i, instr, f); + continue; + } + + /* Extern object/function instruction type. */ + if (instr->type == INSTR_EXTERN_OBJ) { + action_instr_extern_obj_codegen(a, i, f); + continue; + } + + if (instr->type == INSTR_EXTERN_FUNC) { + action_instr_extern_func_codegen(a, i, f); + continue; + } + + /* Jump instruction type. */ + if (instruction_is_jmp(instr)) { + action_instr_jmp_codegen(a, i, instr, data, f); + continue; + } + + /* Return instruction type. */ + if (instr->type == INSTR_RETURN) { + action_instr_return_codegen(f); + continue; + } + + /* Any other instruction type. */ + fprintf(f, + "%s(p, t, &action_%s_instructions[%u]);\n", + instr_type_to_func(instr), + a->name, + i); + } + + fprintf(f, "}\n\n"); +} + +struct instruction_group { + TAILQ_ENTRY(instruction_group) node; + + uint32_t group_id; + + uint32_t first_instr_id; + + uint32_t last_instr_id; + + instr_exec_t func; +}; + +TAILQ_HEAD(instruction_group_list, instruction_group); + +static struct instruction_group * +instruction_group_list_group_find(struct instruction_group_list *igl, uint32_t instruction_id) +{ + struct instruction_group *g; + + TAILQ_FOREACH(g, igl, node) + if ((g->first_instr_id <= instruction_id) && (instruction_id <= g->last_instr_id)) + return g; + + return NULL; +} + +static void +instruction_group_list_free(struct instruction_group_list *igl) +{ + if (!igl) + return; + + for ( ; ; ) { + struct instruction_group *g; + + g = TAILQ_FIRST(igl); + if (!g) + break; + + TAILQ_REMOVE(igl, g, node); + free(g); + } + + free(igl); +} + +static struct instruction_group_list * +instruction_group_list_create(struct rte_swx_pipeline *p) +{ + struct instruction_group_list *igl = NULL; + struct instruction_group *g = NULL; + uint32_t n_groups = 0, i; + + if (!p || !p->instructions || !p->instruction_data || !p->n_instructions) + goto error; + + /* List init. */ + igl = calloc(1, sizeof(struct instruction_group_list)); + if (!igl) + goto error; + + TAILQ_INIT(igl); + + /* Allocate the first group. */ + g = calloc(1, sizeof(struct instruction_group)); + if (!g) + goto error; + + /* Iteration 1: Separate the instructions into groups based on the thread yield + * instructions. Do not worry about the jump instructions at this point. + */ + for (i = 0; i < p->n_instructions; i++) { + struct instruction *instr = &p->instructions[i]; + + /* Check for thread yield instructions. */ + if (!instruction_does_thread_yield(instr)) + continue; + + /* If the current group contains at least one instruction, then finalize it (with + * the previous instruction), add it to the list and allocate a new group (that + * starts with the current instruction). + */ + if (i - g->first_instr_id) { + /* Finalize the group. */ + g->last_instr_id = i - 1; + + /* Add the group to the list. Advance the number of groups. */ + TAILQ_INSERT_TAIL(igl, g, node); + n_groups++; + + /* Allocate a new group. */ + g = calloc(1, sizeof(struct instruction_group)); + if (!g) + goto error; + + /* Initialize the new group. */ + g->group_id = n_groups; + g->first_instr_id = i; + } + + /* Finalize the current group (with the current instruction, therefore this group + * contains just the current thread yield instruction), add it to the list and + * allocate a new group (that starts with the next instruction). + */ + + /* Finalize the group. */ + g->last_instr_id = i; + + /* Add the group to the list. Advance the number of groups. */ + TAILQ_INSERT_TAIL(igl, g, node); + n_groups++; + + /* Allocate a new group. */ + g = calloc(1, sizeof(struct instruction_group)); + if (!g) + goto error; + + /* Initialize the new group. */ + g->group_id = n_groups; + g->first_instr_id = i + 1; + } + + /* Handle the last group. */ + if (i - g->first_instr_id) { + /* Finalize the group. */ + g->last_instr_id = i - 1; + + /* Add the group to the list. Advance the number of groups. */ + TAILQ_INSERT_TAIL(igl, g, node); + n_groups++; + } else + free(g); + + g = NULL; + + /* Iteration 2: Handle jumps. If the current group contains an instruction which represents + * the destination of a jump instruction located in a different group ("far jump"), then the + * current group has to be split, so that the instruction representing the far jump + * destination is at the start of its group. + */ + for ( ; ; ) { + int is_modified = 0; + + for (i = 0; i < p->n_instructions; i++) { + struct instruction_data *data = &p->instruction_data[i]; + struct instruction_group *g; + uint32_t j; + + /* Continue when the current instruction is not a jump destination. */ + if (!data->n_users) + continue; + + g = instruction_group_list_group_find(igl, i); + if (!g) + goto error; + + /* Find out all the jump instructions with this destination. */ + for (j = 0; j < p->n_instructions; j++) { + struct instruction *jmp_instr = &p->instructions[j]; + struct instruction_data *jmp_data = &p->instruction_data[j]; + struct instruction_group *jmp_g, *new_g; + + /* Continue when not a jump instruction. Even when jump instruction, + * continue when the jump destination is not this instruction. + */ + if (!instruction_is_jmp(jmp_instr) || + strcmp(jmp_data->jmp_label, data->label)) + continue; + + jmp_g = instruction_group_list_group_find(igl, j); + if (!jmp_g) + goto error; + + /* Continue when both the jump instruction and the jump destination + * instruction are in the same group. Even when in different groups, + * still continue if the jump destination instruction is already the + * first instruction of its group. + */ + if ((jmp_g->group_id == g->group_id) || (g->first_instr_id == i)) + continue; + + /* Split the group of the current jump destination instruction to + * make this instruction the first instruction of a new group. + */ + new_g = calloc(1, sizeof(struct instruction_group)); + if (!new_g) + goto error; + + new_g->group_id = n_groups; + new_g->first_instr_id = i; + new_g->last_instr_id = g->last_instr_id; + + g->last_instr_id = i - 1; + + TAILQ_INSERT_AFTER(igl, g, new_g, node); + n_groups++; + is_modified = 1; + + /* The decision to split this group (to make the current instruction + * the first instruction of a new group) is already taken and fully + * implemented, so no need to search for more reasons to do it. + */ + break; + } + } + + /* Re-evaluate everything, as at least one group got split, so some jumps that were + * previously considered local (i.e. the jump destination is in the same group as + * the jump instruction) can now be "far jumps" (i.e. the jump destination is in a + * different group than the jump instruction). Wost case scenario: each instruction + * that is a jump destination ends up as the first instruction of its group. + */ + if (!is_modified) + break; + } + + /* Re-assign the group IDs to be in incremental order. */ + i = 0; + TAILQ_FOREACH(g, igl, node) { + g->group_id = i; + + i++; + } + + return igl; + +error: + instruction_group_list_free(igl); + + free(g); + + return NULL; +} + +static void +pipeline_instr_does_tx_codegen(struct rte_swx_pipeline *p __rte_unused, + uint32_t instr_pos, + struct instruction *instr, + FILE *f) +{ + fprintf(f, + "%s(p, t, &pipeline_instructions[%u]);\n" + "\tthread_ip_reset(p, t);\n" + "\tinstr_rx_exec(p);\n" + "\treturn;\n", + instr_type_to_func(instr), + instr_pos); +} + +static int +pipeline_instr_jmp_codegen(struct rte_swx_pipeline *p, + struct instruction_group_list *igl, + uint32_t jmp_instr_id, + struct instruction *jmp_instr, + struct instruction_data *jmp_data, + FILE *f) +{ + struct instruction_group *jmp_g, *g; + struct instruction_data *data; + uint32_t instr_id; + + switch (jmp_instr->type) { + case INSTR_JMP: + break; + + case INSTR_JMP_VALID: + fprintf(f, + "if (HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))", + jmp_instr_id); + break; + + case INSTR_JMP_INVALID: + fprintf(f, + "if (!HEADER_VALID(t, pipeline_instructions[%u].jmp.header_id))", + jmp_instr_id); + break; + + case INSTR_JMP_HIT: + fprintf(f, + "if (t->hit)\n"); + break; + + case INSTR_JMP_MISS: + fprintf(f, + "if (!t->hit)\n"); + break; + + case INSTR_JMP_ACTION_HIT: + fprintf(f, + "if (t->action_id == pipeline_instructions[%u].jmp.action_id)", + jmp_instr_id); + break; + + case INSTR_JMP_ACTION_MISS: + fprintf(f, + "if (t->action_id != pipeline_instructions[%u].jmp.action_id)", + jmp_instr_id); + break; + + case INSTR_JMP_EQ: + fprintf(f, + "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " + "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_EQ_MH: + fprintf(f, + "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " + "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_EQ_HM: + fprintf(f, + "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == " + "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_EQ_HH: + fprintf(f, + "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) == " + "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_EQ_I: + fprintf(f, + "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) == " + "pipeline_instructions[%u].jmp.b_val)", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_NEQ: + fprintf(f, + "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " + "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_NEQ_MH: + fprintf(f, + "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " + "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_NEQ_HM: + fprintf(f, + "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != " + "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_NEQ_HH: + fprintf(f, + "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) != " + "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_NEQ_I: + fprintf(f, + "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) != " + "pipeline_instructions[%u].jmp.b_val)", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_LT: + fprintf(f, + "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " + "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_LT_MH: + fprintf(f, + "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " + "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_LT_HM: + fprintf(f, + "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " + "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_LT_HH: + fprintf(f, + "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " + "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_LT_MI: + fprintf(f, + "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) < " + "pipeline_instructions[%u].jmp.b_val)", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_LT_HI: + fprintf(f, + "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) < " + "pipeline_instructions[%u].jmp.b_val)", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_GT: + fprintf(f, + "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " + "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_GT_MH: + fprintf(f, + "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " + "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_GT_HM: + fprintf(f, + "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " + "instr_operand_hbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_GT_HH: + fprintf(f, + "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " + "instr_operand_nbo(t, &pipeline_instructions[%u].jmp.b))", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_GT_MI: + fprintf(f, + "if (instr_operand_hbo(t, &pipeline_instructions[%u].jmp.a) > " + "pipeline_instructions[%u].jmp.b_val)", + jmp_instr_id, + jmp_instr_id); + break; + + case INSTR_JMP_GT_HI: + fprintf(f, + "if (instr_operand_nbo(t, &pipeline_instructions[%u].jmp.a) > " + "pipeline_instructions[%u].jmp.b_val)", + jmp_instr_id, + jmp_instr_id); + break; + + default: + break; + } + + /* Find the instruction group of the jump instruction. */ + jmp_g = instruction_group_list_group_find(igl, jmp_instr_id); + if (!jmp_g) + return -EINVAL; + + /* Find the instruction group of the jump destination instruction. */ + data = label_find(p->instruction_data, p->n_instructions, jmp_data->jmp_label); + if (!data) + return -EINVAL; + + instr_id = data - p->instruction_data; + + g = instruction_group_list_group_find(igl, instr_id); + if (!g) + return -EINVAL; + + /* Code generation for "near" jump (same instruction group) or "far" jump (different + * instruction group). + */ + if (g->group_id == jmp_g->group_id) + fprintf(f, + "\n\t\tgoto %s;\n", + jmp_data->jmp_label); + else + fprintf(f, + " {\n" + "\t\tthread_ip_set(t, &p->instructions[%u]);\n" + "\t\treturn;\n" + "\t}\n\n", + g->group_id); + + return 0; +} + +static void +instruction_group_list_codegen(struct instruction_group_list *igl, + struct rte_swx_pipeline *p, + FILE *f) +{ + struct instruction_group *g; + uint32_t i; + int is_required = 0; + + /* Check if code generation is required. */ + TAILQ_FOREACH(g, igl, node) + if (g->first_instr_id < g->last_instr_id) + is_required = 1; + + if (!is_required) + return; + + /* Generate the code for the pipeline instruction array. */ + fprintf(f, + "static const struct instruction pipeline_instructions[] = {\n"); + + for (i = 0; i < p->n_instructions; i++) { + struct instruction *instr = &p->instructions[i]; + instruction_export_t func = export_table[instr->type]; + + func(instr, f); + } + + fprintf(f, "};\n\n"); + + /* Generate the code for the pipeline functions: one function for each instruction group + * that contains more than one instruction. + */ + TAILQ_FOREACH(g, igl, node) { + struct instruction *last_instr; + uint32_t j; + + /* Skip if group contains a single instruction. */ + if (g->last_instr_id == g->first_instr_id) + continue; + + /* Generate new pipeline function. */ + fprintf(f, + "void\n" + "pipeline_func_%u(struct rte_swx_pipeline *p)\n" + "{\n" + "\tstruct thread *t = &p->threads[p->thread_id];\n" + "\n", + g->group_id); + + /* Generate the code for each pipeline instruction. */ + for (j = g->first_instr_id; j <= g->last_instr_id; j++) { + struct instruction *instr = &p->instructions[j]; + struct instruction_data *data = &p->instruction_data[j]; + + /* Label, if present. */ + if (data->label[0]) + fprintf(f, "\n%s : ", data->label); + else + fprintf(f, "\n\t"); + + /* TX instruction type. */ + if (instruction_does_tx(instr)) { + pipeline_instr_does_tx_codegen(p, j, instr, f); + continue; + } + + /* Jump instruction type. */ + if (instruction_is_jmp(instr)) { + pipeline_instr_jmp_codegen(p, igl, j, instr, data, f); + continue; + } + + /* Any other instruction type. */ + fprintf(f, + "%s(p, t, &pipeline_instructions[%u]);\n", + instr_type_to_func(instr), + j); + } + + /* Finalize the generated pipeline function. For some instructions such as TX, + * emit-many-and-TX and unconditional jump, the next instruction has been already + * decided unconditionally and the instruction pointer of the current thread set + * accordingly; for all the other instructions, the instruction pointer must be + * incremented now. + */ + last_instr = &p->instructions[g->last_instr_id]; + + if (!instruction_does_tx(last_instr) && (last_instr->type != INSTR_JMP)) + fprintf(f, + "thread_ip_inc(p);\n"); + + fprintf(f, + "}\n" + "\n"); + } +} + +static uint32_t +instruction_group_list_custom_instructions_count(struct instruction_group_list *igl) +{ + struct instruction_group *g; + uint32_t n_custom_instr = 0; + + /* Groups with a single instruction: no function is generated for this group, the group + * keeps its current instruction. Groups with more than two instructions: one function and + * the associated custom instruction get generated for each such group. + */ + TAILQ_FOREACH(g, igl, node) { + if (g->first_instr_id == g->last_instr_id) + continue; + + n_custom_instr++; + } + + return n_custom_instr; +} + +static int +pipeline_codegen(struct rte_swx_pipeline *p, struct instruction_group_list *igl) +{ + struct action *a; + FILE *f = NULL; + + /* Create the .c file. */ + f = fopen("/tmp/pipeline.c", "w"); + if (!f) + return -EIO; + + /* Include the .h file. */ + fprintf(f, "#include \"rte_swx_pipeline_internal.h\"\n"); + + /* Add the code for each action. */ + TAILQ_FOREACH(a, &p->actions, node) { + fprintf(f, "/**\n * Action %s\n */\n\n", a->name); + + action_data_codegen(a, f); + + fprintf(f, "\n"); + + action_instr_codegen(a, f); + + fprintf(f, "\n"); + } + + /* Add the pipeline code. */ + instruction_group_list_codegen(igl, p, f); + + /* Close the .c file. */ + fclose(f); + + return 0; +} + +#ifndef RTE_SWX_PIPELINE_CMD_MAX_SIZE +#define RTE_SWX_PIPELINE_CMD_MAX_SIZE 4096 +#endif + +static int +pipeline_libload(struct rte_swx_pipeline *p, struct instruction_group_list *igl) +{ + struct action *a; + struct instruction_group *g; + char *dir_in, *buffer = NULL; + const char *dir_out; + int status = 0; + + /* Get the environment variables. */ + dir_in = getenv("RTE_INSTALL_DIR"); + if (!dir_in) { + status = -EINVAL; + goto free; + } + + dir_out = "/tmp"; + + /* Memory allocation for the command buffer. */ + buffer = malloc(RTE_SWX_PIPELINE_CMD_MAX_SIZE); + if (!buffer) { + status = -ENOMEM; + goto free; + } + + snprintf(buffer, + RTE_SWX_PIPELINE_CMD_MAX_SIZE, + "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s/pipeline.o %s/pipeline.c " + "-I %s/lib/pipeline " + "-I %s/lib/eal/include " + "-I %s/lib/eal/x86/include " + "-I %s/lib/eal/include/generic " + "-I %s/lib/meter " + "-I %s/lib/port " + "-I %s/lib/table " + "-I %s/lib/pipeline " + "-I %s/config " + "-I %s/build " + "-I %s/lib/eal/linux/include " + ">%s/pipeline.log 2>&1 " + "&& " + "gcc -shared %s/pipeline.o -o %s/libpipeline.so " + ">>%s/pipeline.log 2>&1", + dir_out, + dir_out, + dir_in, + dir_in, + dir_in, + dir_in, + dir_in, + dir_in, + dir_in, + dir_in, + dir_in, + dir_in, + dir_in, + dir_out, + dir_out, + dir_out, + dir_out); + + /* Build the shared object library. */ + status = system(buffer); + if (status) + goto free; + + /* Open library. */ + snprintf(buffer, + RTE_SWX_PIPELINE_CMD_MAX_SIZE, + "%s/libpipeline.so", + dir_out); + + p->lib = dlopen(buffer, RTLD_LAZY); + if (!p->lib) { + status = -EIO; + goto free; + } + + /* Get the action function symbols. */ + TAILQ_FOREACH(a, &p->actions, node) { + snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "action_%s_run", a->name); + + p->action_funcs[a->id] = dlsym(p->lib, buffer); + if (!p->action_funcs[a->id]) { + status = -EINVAL; + goto free; + } + } + + /* Get the pipeline function symbols. */ + TAILQ_FOREACH(g, igl, node) { + if (g->first_instr_id == g->last_instr_id) + continue; + + snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "pipeline_func_%u", g->group_id); + + g->func = dlsym(p->lib, buffer); + if (!g->func) { + status = -EINVAL; + goto free; + } + } + +free: + if (status && p->lib) { + dlclose(p->lib); + p->lib = NULL; + } + + free(buffer); + + return status; +} + +static int +pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused, + struct instruction_group_list *igl) +{ + uint32_t n_custom_instr = instruction_group_list_custom_instructions_count(igl); + + /* Check that enough space is available within the pipeline instruction table to store all + * the custom instructions. + */ + if (INSTR_CUSTOM_0 + n_custom_instr > RTE_SWX_PIPELINE_INSTRUCTION_TABLE_SIZE_MAX) + return -ENOSPC; + + return 0; +} + +static void +pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl) +{ + struct instruction_group *g; + uint32_t i; + + /* Pipeline table instructions. */ + for (i = 0; i < p->n_instructions; i++) { + struct instruction *instr = &p->instructions[i]; + + if (instr->type == INSTR_TABLE) + instr->type = INSTR_TABLE_AF; + + if (instr->type == INSTR_LEARNER) + instr->type = INSTR_LEARNER_AF; + } + + /* Pipeline custom instructions. */ + i = 0; + TAILQ_FOREACH(g, igl, node) { + struct instruction *instr = &p->instructions[g->first_instr_id]; + uint32_t j; + + if (g->first_instr_id == g->last_instr_id) + continue; + + /* Install a new custom instruction. */ + p->instruction_table[INSTR_CUSTOM_0 + i] = g->func; + + /* First instruction of the group: change its type to the new custom instruction. */ + instr->type = INSTR_CUSTOM_0 + i; + + /* All the subsequent instructions of the group: invalidate. */ + for (j = g->first_instr_id + 1; j <= g->last_instr_id; j++) { + struct instruction_data *data = &p->instruction_data[j]; + + data->invalid = 1; + } + + i++; + } + + /* Remove the invalidated instructions. */ + p->n_instructions = instr_compact(p->instructions, p->instruction_data, p->n_instructions); + + /* Resolve the jump destination for any "standalone" jump instructions (i.e. those jump + * instructions that are the only instruction within their group, so they were left + * unmodified). + */ + instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions); +} + +static int +pipeline_compile(struct rte_swx_pipeline *p) +{ + struct instruction_group_list *igl = NULL; + int status = 0; + + igl = instruction_group_list_create(p); + if (!igl) { + status = -ENOMEM; + goto free; + } + + /* Code generation. */ + status = pipeline_codegen(p, igl); + if (status) + goto free; + + /* Build and load the shared object library. */ + status = pipeline_libload(p, igl); + if (status) + goto free; + + /* Adjust instructions. */ + status = pipeline_adjust_check(p, igl); + if (status) + goto free; + + pipeline_adjust(p, igl); + +free: + instruction_group_list_free(igl); + + return status; +}