void debug_print(Printer& p, Expr* e) { if (not e) { print(p, "()"); return; } switch (e->kind) { // Names case basic_id: return debug_terminal(p, as<Basic_id>(e)); case operator_id: return debug_operator(p, as<Operator_id>(e)); case scoped_id: return debug_scoped(p, as<Scoped_id>(e)); case indexed_id: return debug_indexed(p, as<Indexed_id>(e)); case decl_id: return debug_id(p, as<Decl_id>(e)); // Types case typename_type: return print(p, "typename"); case unit_type: return print(p, "unit"); case bool_type: return print(p, "bool"); case nat_type: return print(p, "nat"); case int_type: return print(p, "int"); case char_type: return print(p, "char"); case bitfield_type: return debug_ternary(p, as<Bitfield_type>(e)); case fn_type: return debug_binary(p, as<Fn_type>(e)); case range_type: return debug_unary(p, as<Range_type>(e)); case record_type: return debug_nested_unary(p, as<Record_type>(e)); case variant_type: return debug_nested_unary(p, as<Variant_type>(e)); case dep_variant_type: return debug_nested_binary(p, as<Dep_variant_type>(e)); case enum_type: return debug_nested_binary(p, as<Enum_type>(e)); case array_type: return debug_binary(p, as<Array_type>(e)); case dep_type: return debug_binary(p, as<Dep_type>(e)); case module_type: return debug_module(p, as<Module>(e)); // Networking primitives case net_str_type: return debug_unary(p, as<Net_str_type>(e)); case net_seq_type: return debug_binary(p, as<Net_seq_type>(e)); // Terms case unit_term: return print(p, "<unit>"); case bool_term: return debug_terminal(p, as<Bool>(e)); case int_term: return debug_terminal(p, as<Int>(e)); case default_term: return print(p, "default"); case fn_term: return debug_fn(p, as<Fn>(e)); case builtin_term: return print(p, "<builtin>"); case call_term: return debug_binary(p, as<Call>(e)); case promo_term: return debug_binary(p, as<Promo>(e)); case pred_term: return debug_binary(p, as<Pred>(e)); case range_term: return debug_binary(p, as<Range>(e)); case variant_term: return debug_binary(p, as<Variant>(e)); case unary_term: return debug_binary(p, as<Unary>(e)); case binary_term: return debug_ternary(p, as<Binary>(e)); case if_term: return debug_ternary(p, as<If>(e)); // Statements case block_stmt: return debug_nested_unary(p, as<Block>(e)); case return_stmt: return debug_unary(p, as<Return>(e)); // Declarations case top_decl: return debug_nested_unary(p, as<Top>(e)); case def_decl: return debug_ternary(p, as<Def>(e)); case parm_decl: return debug_ternary(p, as<Parm>(e)); case field_decl: return debug_ternary(p, as<Field>(e)); case alt_decl: return debug_binary(p, as<Alt>(e)); case enum_decl: return debug_constructor(p, as<Enum>(e)); case import_decl: return debug_unary(p, as<Import>(e)); case using_decl: return debug_unary(p, as<Using>(e)); // Unhandled default: // FIXME: Make a print formatter that gives complete information // about a node, including its class and id. steve_unreachable(format("debugging unhandled expression '{}'", node_name(e))); } }
/* How to use: * Do not call this directly, but use "stella_sync = UPDATE_VALUES" instead. * Purpose: * Sort channels' brightness values from high to low (and the * interrupt time points from low to high), to be able to switch on * channels one after the other depending on their brightness level * and point in time. * Implementation details: * Use a "linked list" to avoid expensive memory copies. Main difference * to a real linked list is, that all elements are already preallocated * on the stack and are not allocated on demand. * The function directly writes to a "just calculated"-structure and if we * want new values in the pwm interrupt, we just have to swap pointers from * the "interrupt save"-structure to the "just calculated"-structure. (The * meaning of both structures changes, too, of course.) * Although we provide each channel in the structure with its neccessary * information such as portmask and brightness level, we will actually * ignore brightness levels of 0% and 100% due to not linking them to the linked list. * 100%-level channels are switched on at the beginning of each * pwm cycle and not touched afterwards. Channels with same brightness * levels are merged together (their portmask at least). * */ static void stella_sort() { stella_timetable_entry_s *current, *last; uint8_t i; cal_table->head = 0; cal_table->port[0].mask = 0; cal_table->port[0].port = &STELLA_PORT1; #ifdef STELLA_PINS_PORT2 cal_table->port[1].mask = 0; cal_table->port[1].port = &STELLA_PORT2; #endif for (i = 0; i < STELLA_CHANNELS; ++i) { /* set data of channel i */ cal_table->channel[i].port.mask = _BV(i + STELLA_OFFSET_PORT1); cal_table->channel[i].port.port = &STELLA_PORT1; #ifdef STELLA_PINS_PORT2 if (i >= STELLA_PINS_PORT1) { cal_table->channel[i].port.mask = _BV((i - STELLA_PINS_PORT1) + STELLA_OFFSET_PORT2); cal_table->channel[i].port.port = &STELLA_PORT2; } #endif cal_table->channel[i].value = 255 - stella_brightness[i]; cal_table->channel[i].next = 0; /* Special case: 0% brightness (Don't include this channel!) */ if (stella_brightness[i] == 0) continue; //cal_table->portmask |= _BV(i+STELLA_OFFSET); /* Special case: 100% brightness (Merge pwm cycle start masks! Don't include this channel!) */ if (stella_brightness[i] == 255) { #ifdef STELLA_PINS_PORT2 if (i >= STELLA_PINS_PORT1) cal_table->port[1].mask |= _BV((i - STELLA_PINS_PORT1) + STELLA_OFFSET_PORT2); else cal_table->port[0].mask |= _BV(i + STELLA_OFFSET_PORT1); #else cal_table->port[0].mask |= _BV(i + STELLA_OFFSET_PORT1); #endif continue; } /* first item in linked list */ if (!cal_table->head) { cal_table->head = &(cal_table->channel[i]); continue; } /* add to linked list with >=1 entries */ current = cal_table->head; last = 0; while (current) { // same value as current item: do not add to linked list // but just update the portmask (DO THIS ONLY IF BOTH CHANNELS OPERATE ON THE SAME PORT) if (current->value == cal_table->channel[i].value && current->port.port == cal_table->channel[i].port.port) { #ifdef STELLA_PINS_PORT2 if (i >= STELLA_PINS_PORT1) current->port.mask |= _BV((i - STELLA_PINS_PORT1) + STELLA_OFFSET_PORT2); else current->port.mask |= _BV(i + STELLA_OFFSET_PORT1); #else current->port.mask |= _BV(i + STELLA_OFFSET_PORT1); #endif break; } // insert our new value at the head of the list else if (!last && current->value > cal_table->channel[i].value) { cal_table->channel[i].next = cal_table->head; cal_table->head = &(cal_table->channel[i]); break; } // insert our new value somewhere in betweem else if (current->value > cal_table->channel[i].value) { cal_table->channel[i].next = last->next; last->next = &(cal_table->channel[i]); break; } // reached the end of the linked list: just append our new entry else if (!current->next) { current->next = &(cal_table->channel[i]); break; } // else go to the next item in the linked list else { last = current; current = current->next; } } } #ifdef DEBUG_STELLA current = cal_table->head; while (current) { //debug_printf("%u %s\n", current->value, debug_binary(current->portmask)); current = current->next; } debug_printf("Mask1: %s %u\n" #ifdef STELLA_PINS_PORT2 "Mask2: %s %u\n" #endif , debug_binary(stella_portmask[0]), stella_portmask[0] #ifdef STELLA_PINS_PORT2 , debug_binary(stella_portmask[1]), stella_portmask[1] #endif ); #endif /* Allow the interrupt to actually apply the calculated values */ stella_sync = NEW_VALUES; }
/* How to use: * Do not call this directly, but use "stella_sync = UPDATE_VALUES" instead. * Purpose: * Sort channels' brightness values from high to low (and the * interrupt time points from low to high), to be able to switch on * channels one after the other depending on their brightness level * and point in time. * Implementation details: * Use a "linked list" to avoid expensive memory copies. Main difference * to a real linked list is, that all elements are already preallocated * on the stack and are not allocated on demand. * The function directly writes to a "just calculated"-structure and if we * want new values in the pwm interrupt, we just have to swap pointers from * the "interrupt save"-structure to the "just calculated"-structure. (The * meaning of both structures changes, too, of course.) * Although we provide each channel in the structure with its neccessary * information such as portmask and brightness level, we will actually * ignore brightness levels of 0% and 100% due to not linking them to the linked list. * 100%-level channels are only switched on at the beginning of each * pwm cycle and not touched afterwards. Channels with same brightness * levels are merged together (their portmask at least). * */ inline void stella_sort() { struct stella_timetable_entry* current, *last; uint8_t i; cal_table->portmask = 0; cal_table->head = 0; for (i=0;i<STELLA_PINS;++i) { /* set current item */ cal_table->channel[i].portmask = _BV(i+STELLA_OFFSET); cal_table->channel[i].value = 255 - stella_brightness[i]; cal_table->channel[i].next = 0; #ifdef STELLA_GAMMACORRECTION if (i<100) cal_table->channel[i].gamma_wait_cycles = pgm_read_byte(stella_gamma[i]); else cal_table->channel[i].gamma_wait_cycles = 0; cal_table->channel[i].gamma_wait_counter = cal_table->channel[i].gamma_wait_cycles; #endif /* Sepcial cases: 0% brightness */ if (stella_brightness[i] == 0) continue; //cal_table->portmask |= _BV(i+STELLA_OFFSET); if (stella_brightness[i] == 255) { cal_table->portmask |= _BV(i+STELLA_OFFSET); continue; } /* first item in linked list */ if (!cal_table->head) { cal_table->head = &(cal_table->channel[i]); continue; } /* add to linked list with >=1 entries */ current = cal_table->head; last = 0; while (current) { // same value as current item: do not add to linked list // but just update the portmask if (current->value == cal_table->channel[i].value) { //current->portmask &= (uint8_t)~_BV(i+STELLA_OFFSET); current->portmask |= _BV(i+STELLA_OFFSET); break; } // insert our new value at the head of the list else if (!last && current->value > cal_table->channel[i].value) { cal_table->channel[i].next = cal_table->head; cal_table->head = &(cal_table->channel[i]); break; } // insert our new value somewhere in betweem else if (current->value > cal_table->channel[i].value) { cal_table->channel[i].next = last->next; last->next = &(cal_table->channel[i]); break; } // reached the end of the linked list: just add our new entry else if (!current->next) { current->next = &(cal_table->channel[i]); break; } // else go to the next item in the linked list else { last = current; current = current->next; } } } #ifdef DEBUG_STELLA // debug out current = cal_table->head; i = 0; while (current) { i++; debug_printf("%u %s\n", current->value, debug_binary(current->portmask)); current = current->next; } debug_printf("%s %u\n", debug_binary(stella_portmask_neg), stella_portmask_neg); #endif /* Allow the interrupt to actually apply the calculated values */ stella_sync = NEW_VALUES; }