/* Subroutines for insn-output.c for ATMEL AVR micro controllers
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
Contributed by Denis Chertykov (denisc@overta.ru)
static int avr_naked_function_p (tree);
static int interrupt_function_p (tree);
static int signal_function_p (tree);
+static int avr_OS_task_function_p (tree);
static int avr_regs_to_save (HARD_REG_SET *);
static int sequent_regs_live (void);
static const char *ptrreg_to_str (int);
const char *avr_base_arch_macro;
const char *avr_extra_arch_macro;
-section *progmem_section;
+/* Current architecture. */
+const struct base_arch_s *avr_current_arch;
-/* More than 8K of program memory: use "call" and "jmp". */
-int avr_mega_p = 0;
+section *progmem_section;
/* Core have 'MUL*' instructions. */
int avr_have_mul_p = 0;
/* Core have 'MOVW' and 'LPM Rx,Z' instructions. */
int avr_have_movw_lpmx_p = 0;
-struct base_arch_s {
- int asm_only;
- int have_mul;
- int mega;
- int have_movw_lpmx;
- const char *const macro;
-};
-
static const struct base_arch_s avr_arch_types[] = {
- { 1, 0, 0, 0, NULL }, /* unknown device specified */
- { 1, 0, 0, 0, "__AVR_ARCH__=1" },
- { 0, 0, 0, 0, "__AVR_ARCH__=2" },
- { 0, 0, 0, 1, "__AVR_ARCH__=25"},
- { 0, 0, 1, 0, "__AVR_ARCH__=3" },
- { 0, 1, 0, 1, "__AVR_ARCH__=4" },
- { 0, 1, 1, 1, "__AVR_ARCH__=5" }
+ { 1, 0, 0, 0, 0, 0, 0, 0, NULL }, /* unknown device specified */
+ { 1, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=1" },
+ { 0, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=2" },
+ { 0, 0, 0, 1, 0, 0, 0, 0, "__AVR_ARCH__=25" },
+ { 0, 0, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=3" },
+ { 0, 0, 1, 0, 1, 0, 0, 0, "__AVR_ARCH__=31" },
+ { 0, 0, 1, 1, 0, 0, 0, 0, "__AVR_ARCH__=35" },
+ { 0, 1, 0, 1, 0, 0, 0, 0, "__AVR_ARCH__=4" },
+ { 0, 1, 1, 1, 0, 0, 0, 0, "__AVR_ARCH__=5" },
+ { 0, 1, 1, 1, 1, 1, 0, 0, "__AVR_ARCH__=51" },
+ { 0, 1, 1, 1, 1, 1, 1, 0, "__AVR_ARCH__=6" }
};
/* These names are used as the index into the avr_arch_types[] table
ARCH_AVR2,
ARCH_AVR25,
ARCH_AVR3,
+ ARCH_AVR31,
+ ARCH_AVR35,
ARCH_AVR4,
- ARCH_AVR5
+ ARCH_AVR5,
+ ARCH_AVR51,
+ ARCH_AVR6
};
struct mcu_type_s {
{ "attiny861", ARCH_AVR25, "__AVR_ATtiny861__" },
{ "attiny43u", ARCH_AVR25, "__AVR_ATtiny43U__" },
{ "attiny48", ARCH_AVR25, "__AVR_ATtiny48__" },
+ { "attiny88", ARCH_AVR25, "__AVR_ATtiny88__" },
{ "at86rf401", ARCH_AVR25, "__AVR_AT86RF401__" },
- /* Classic, > 8K. */
+ /* Classic, > 8K, <= 64K. */
{ "avr3", ARCH_AVR3, NULL },
- { "atmega103", ARCH_AVR3, "__AVR_ATmega103__" },
- { "atmega603", ARCH_AVR3, "__AVR_ATmega603__" },
{ "at43usb320", ARCH_AVR3, "__AVR_AT43USB320__" },
{ "at43usb355", ARCH_AVR3, "__AVR_AT43USB355__" },
{ "at76c711", ARCH_AVR3, "__AVR_AT76C711__" },
+ /* Classic, == 128K. */
+ { "avr31", ARCH_AVR31, NULL },
+ { "atmega103", ARCH_AVR31, "__AVR_ATmega103__" },
+ /* Classic + MOVW + JMP/CALL. */
+ { "avr35", ARCH_AVR35, NULL },
+ { "at90usb82", ARCH_AVR35, "__AVR_AT90USB82__" },
+ { "at90usb162", ARCH_AVR35, "__AVR_AT90USB162__" },
/* Enhanced, <= 8K. */
{ "avr4", ARCH_AVR4, NULL },
{ "atmega8", ARCH_AVR4, "__AVR_ATmega8__" },
{ "at90pwm2b", ARCH_AVR4, "__AVR_AT90PWM2B__" },
{ "at90pwm3", ARCH_AVR4, "__AVR_AT90PWM3__" },
{ "at90pwm3b", ARCH_AVR4, "__AVR_AT90PWM3B__" },
- /* Enhanced, > 8K. */
+ /* Enhanced, > 8K, <= 64K. */
{ "avr5", ARCH_AVR5, NULL },
{ "atmega16", ARCH_AVR5, "__AVR_ATmega16__" },
{ "atmega161", ARCH_AVR5, "__AVR_ATmega161__" },
{ "atmega329p", ARCH_AVR5, "__AVR_ATmega329P__" },
{ "atmega3290", ARCH_AVR5, "__AVR_ATmega3290__" },
{ "atmega3290p", ARCH_AVR5, "__AVR_ATmega3290P__" },
+ { "atmega32hvb", ARCH_AVR5, "__AVR_ATmega32HVB__" },
{ "atmega406", ARCH_AVR5, "__AVR_ATmega406__" },
{ "atmega64", ARCH_AVR5, "__AVR_ATmega64__" },
{ "atmega640", ARCH_AVR5, "__AVR_ATmega640__" },
{ "atmega6450", ARCH_AVR5, "__AVR_ATmega6450__" },
{ "atmega649", ARCH_AVR5, "__AVR_ATmega649__" },
{ "atmega6490", ARCH_AVR5, "__AVR_ATmega6490__" },
- { "atmega128", ARCH_AVR5, "__AVR_ATmega128__" },
- { "atmega1280", ARCH_AVR5, "__AVR_ATmega1280__" },
- { "atmega1281", ARCH_AVR5, "__AVR_ATmega1281__" },
{ "atmega16hva", ARCH_AVR5, "__AVR_ATmega16HVA__" },
{ "at90can32", ARCH_AVR5, "__AVR_AT90CAN32__" },
{ "at90can64", ARCH_AVR5, "__AVR_AT90CAN64__" },
- { "at90can128", ARCH_AVR5, "__AVR_AT90CAN128__" },
{ "at90pwm216", ARCH_AVR5, "__AVR_AT90PWM216__" },
{ "at90pwm316", ARCH_AVR5, "__AVR_AT90PWM316__" },
- { "at90usb82", ARCH_AVR5, "__AVR_AT90USB82__" },
- { "at90usb162", ARCH_AVR5, "__AVR_AT90USB162__" },
{ "at90usb646", ARCH_AVR5, "__AVR_AT90USB646__" },
{ "at90usb647", ARCH_AVR5, "__AVR_AT90USB647__" },
- { "at90usb1286", ARCH_AVR5, "__AVR_AT90USB1286__" },
- { "at90usb1287", ARCH_AVR5, "__AVR_AT90USB1287__" },
{ "at94k", ARCH_AVR5, "__AVR_AT94K__" },
+ /* Enhanced, == 128K. */
+ { "avr51", ARCH_AVR51, NULL },
+ { "atmega128", ARCH_AVR51, "__AVR_ATmega128__" },
+ { "atmega1280", ARCH_AVR51, "__AVR_ATmega1280__" },
+ { "atmega1281", ARCH_AVR51, "__AVR_ATmega1281__" },
+ { "atmega1284p", ARCH_AVR51, "__AVR_ATmega1284P__" },
+ { "at90can128", ARCH_AVR51, "__AVR_AT90CAN128__" },
+ { "at90usb1286", ARCH_AVR51, "__AVR_AT90USB1286__" },
+ { "at90usb1287", ARCH_AVR51, "__AVR_AT90USB1287__" },
+ /* 3-Byte PC. */
+ { "avr6", ARCH_AVR6, NULL },
+ { "atmega2560", ARCH_AVR6, "__AVR_ATmega2560__" },
+ { "atmega2561", ARCH_AVR6, "__AVR_ATmega2561__" },
/* Assembler only. */
{ "avr1", ARCH_AVR1, NULL },
{ "at90s1200", ARCH_AVR1, "__AVR_AT90S1200__" },
fprintf (stderr," %s\n", t->name);
}
+ avr_current_arch = &avr_arch_types[t->arch];
base = &avr_arch_types[t->arch];
avr_asm_only_p = base->asm_only;
avr_have_mul_p = base->have_mul;
- avr_mega_p = base->mega;
avr_have_movw_lpmx_p = base->have_movw_lpmx;
avr_base_arch_macro = base->macro;
avr_extra_arch_macro = t->macro;
if (optimize && !TARGET_NO_TABLEJUMP)
- avr_case_values_threshold = (!AVR_MEGA || TARGET_CALL_PROLOGUES) ? 8 : 17;
+ avr_case_values_threshold =
+ (!AVR_HAVE_JMP_CALL || TARGET_CALL_PROLOGUES) ? 8 : 17;
tmp_reg_rtx = gen_rtx_REG (QImode, TMP_REGNO);
zero_reg_rtx = gen_rtx_REG (QImode, ZERO_REGNO);
return a != NULL_TREE;
}
+/* Return nonzero if FUNC is a OS_task function. */
+
+static int
+avr_OS_task_function_p (tree func)
+{
+ tree a;
+
+ gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
+
+ a = lookup_attribute ("OS_task", TYPE_ATTRIBUTES (TREE_TYPE (func)));
+ return a != NULL_TREE;
+}
+
/* Return the number of hard registers to push/pop in the prologue/epilogue
of the current function, and optionally store these registers in SET. */
int reg, count;
int int_or_sig_p = (interrupt_function_p (current_function_decl)
|| signal_function_p (current_function_decl));
- int leaf_func_p = leaf_function_p ();
+
+ if (!reload_completed)
+ cfun->machine->is_leaf = leaf_function_p ();
if (set)
CLEAR_HARD_REG_SET (*set);
count = 0;
- /* No need to save any registers if the function never returns. */
- if (TREE_THIS_VOLATILE (current_function_decl))
+ /* No need to save any registers if the function never returns or
+ is have "OS_task" attribute. */
+ if (TREE_THIS_VOLATILE (current_function_decl)
+ || cfun->machine->is_OS_task)
return 0;
for (reg = 0; reg < 32; reg++)
if (fixed_regs[reg])
continue;
- if ((int_or_sig_p && !leaf_func_p && call_used_regs[reg])
+ if ((int_or_sig_p && !cfun->machine->is_leaf && call_used_regs[reg])
|| (df_regs_ever_live_p (reg)
&& (int_or_sig_p || !call_used_regs[reg])
&& !(frame_pointer_needed
else
{
int offset = frame_pointer_needed ? 2 : 0;
+ int avr_pc_size = AVR_HAVE_EIJMP_EICALL ? 3 : 2;
offset += avr_regs_to_save (NULL);
- return get_frame_size () + 2 + 1 + offset;
+ return get_frame_size () + (avr_pc_size) + 1 + offset;
}
}
&& ! interrupt_function_p (current_function_decl)
&& ! signal_function_p (current_function_decl)
&& ! avr_naked_function_p (current_function_decl)
- && ! MAIN_NAME_P (DECL_NAME (current_function_decl))
&& ! TREE_THIS_VOLATILE (current_function_decl));
}
expand_prologue (void)
{
int live_seq;
+ HARD_REG_SET set;
int minimize;
HOST_WIDE_INT size = get_frame_size();
/* Define templates for push instructions. */
last_insn_address = 0;
/* Init cfun->machine. */
- cfun->machine->is_main = MAIN_NAME_P (DECL_NAME (current_function_decl));
cfun->machine->is_naked = avr_naked_function_p (current_function_decl);
cfun->machine->is_interrupt = interrupt_function_p (current_function_decl);
cfun->machine->is_signal = signal_function_p (current_function_decl);
+ cfun->machine->is_OS_task = avr_OS_task_function_p (current_function_decl);
/* Prologue: naked. */
if (cfun->machine->is_naked)
return;
}
+ avr_regs_to_save (&set);
live_seq = sequent_regs_live ();
minimize = (TARGET_CALL_PROLOGUES
- && !(cfun->machine->is_interrupt || cfun->machine->is_signal)
+ && !cfun->machine->is_interrupt
+ && !cfun->machine->is_signal
+ && !cfun->machine->is_OS_task
&& live_seq);
if (cfun->machine->is_interrupt || cfun->machine->is_signal)
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_move_insn (pushbyte, tmp_reg_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
-
+
+ /* Push RAMPZ. */
+ if(AVR_HAVE_RAMPZ
+ && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1)))
+ {
+ insn = emit_move_insn (tmp_reg_rtx,
+ gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ insn = emit_move_insn (pushbyte, tmp_reg_rtx);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
/* Clear zero reg. */
insn = emit_move_insn (zero_reg_rtx, const0_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
/* Prevent any attempt to delete the setting of ZERO_REG! */
emit_insn (gen_rtx_USE (VOIDmode, zero_reg_rtx));
}
- if (cfun->machine->is_main)
- {
- char buffer[40];
- sprintf (buffer, "%s - %d", avr_init_stack, (int) size);
- rtx sym = gen_rtx_SYMBOL_REF (HImode, ggc_strdup (buffer));
- /* Initialize stack pointer using frame pointer. */
- insn = emit_move_insn (frame_pointer_rtx, sym);
- RTX_FRAME_RELATED_P (insn) = 1;
- insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
- }
- else if (minimize && (frame_pointer_needed || live_seq > 6))
+ if (minimize && (frame_pointer_needed || live_seq > 6))
{
insn = emit_move_insn (gen_rtx_REG (HImode, REG_X),
gen_int_mode (size, HImode));
}
else
{
- HARD_REG_SET set;
- avr_regs_to_save (&set);
int reg;
for (reg = 0; reg < 32; ++reg)
{
}
if (frame_pointer_needed)
{
- /* Push frame pointer. */
- insn = emit_move_insn (pushword, frame_pointer_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
+ if(!cfun->machine->is_OS_task)
+ {
+ /* Push frame pointer. */
+ insn = emit_move_insn (pushword, frame_pointer_rtx);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
if (!size)
{
insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_move_insn (myfp,
- gen_rtx_PLUS (GET_MODE(myfp), frame_pointer_rtx,
+ gen_rtx_PLUS (GET_MODE(myfp), myfp,
gen_int_mode (-size, GET_MODE(myfp))));
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_move_insn ( stack_pointer_rtx, frame_pointer_rtx);
{
fputs ("/* prologue: Signal */\n", file);
}
- else if (cfun->machine->is_main)
- {
- fputs ("/* prologue: main */\n", file);
- }
else
fputs ("/* prologue: function */\n", file);
}
{
int reg;
int live_seq;
+ HARD_REG_SET set;
int minimize;
HOST_WIDE_INT size = get_frame_size();
return;
}
+ avr_regs_to_save (&set);
live_seq = sequent_regs_live ();
minimize = (TARGET_CALL_PROLOGUES
- && !(cfun->machine->is_interrupt || cfun->machine->is_signal)
+ && !cfun->machine->is_interrupt
+ && !cfun->machine->is_signal
+ && !cfun->machine->is_OS_task
&& live_seq);
- if (cfun->machine->is_main)
- {
- /* Return value from main() is already in the correct registers
- (r25:r24) as the exit() argument. */
- emit_jump_insn (gen_return ());
- }
- else if (minimize && (frame_pointer_needed || live_seq > 4))
+ if (minimize && (frame_pointer_needed || live_seq > 4))
{
if (frame_pointer_needed)
{
emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
}
}
-
- /* Restore previous frame_pointer. */
- emit_insn (gen_pophi (frame_pointer_rtx));
+ if(!cfun->machine->is_OS_task)
+ {
+ /* Restore previous frame_pointer. */
+ emit_insn (gen_pophi (frame_pointer_rtx));
+ }
}
/* Restore used registers. */
- HARD_REG_SET set;
- avr_regs_to_save (&set);
for (reg = 31; reg >= 0; --reg)
{
if (TEST_HARD_REG_BIT (set, reg))
}
if (cfun->machine->is_interrupt || cfun->machine->is_signal)
{
+ /* Restore RAMPZ using tmp reg as scratch. */
+ if(AVR_HAVE_RAMPZ
+ && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1)))
+ {
+ emit_insn (gen_popqi (tmp_reg_rtx));
+ emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(RAMPZ_ADDR)),
+ tmp_reg_rtx);
+ }
/* Restore SREG using tmp reg as scratch. */
emit_insn (gen_popqi (tmp_reg_rtx));
&& ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (addr))
|| GET_CODE (addr) == LABEL_REF))
{
- fprintf (file, "pm(");
+ fprintf (file, "gs(");
output_addr_const (file,addr);
fprintf (file ,")");
}
if (code == '~')
{
- if (!AVR_MEGA)
+ if (!AVR_HAVE_JMP_CALL)
fputc ('r', file);
}
+ else if (code == '!')
+ {
+ if (AVR_HAVE_EIJMP_EICALL)
+ fputc ('e', file);
+ }
else if (REG_P (x))
{
if (x == zero_reg_rtx)
return 1;
else if (-2046 <= jump_distance && jump_distance <= 2045)
return 2;
- else if (AVR_MEGA)
+ else if (AVR_HAVE_JMP_CALL)
return 3;
return 2;
or inside main or signal function prologue where they disabled. */
else if (TARGET_NO_INTERRUPTS
|| (reload_completed
- && cfun->machine->is_main
- && prologue_epilogue_contains (insn))
- || (reload_completed
&& cfun->machine->is_signal
&& prologue_epilogue_contains (insn)))
{
*l = 1;
return AS2 (in,%0,__SREG__);
}
- if (avr_io_address_p (x, 1))
+ if (optimize > 0 && io_address_operand (x, QImode))
{
*l = 1;
return AS2 (in,%0,%1-0x20);
}
else if (CONSTANT_ADDRESS_P (base))
{
- if (avr_io_address_p (base, 2))
+ if (optimize > 0 && io_address_operand (base, HImode))
{
*l = 2;
return (AS2 (in,%A0,%A1-0x20) CR_TAB
*l = 1;
return AS2 (out,__SREG__,%1);
}
- if (avr_io_address_p (x, 1))
+ if (optimize > 0 && io_address_operand (x, QImode))
{
*l = 1;
return AS2 (out,%0-0x20,%1);
l = &tmp;
if (CONSTANT_ADDRESS_P (base))
{
- if (avr_io_address_p (base, 2))
+ if (optimize > 0 && io_address_operand (base, HImode))
{
*l = 2;
return (AS2 (out,%B0-0x20,%B1) CR_TAB
int
frame_pointer_required_p (void)
{
- return (current_function_calls_alloca
- || current_function_args_info.nregs == 0
+ return (cfun->calls_alloca
+ || crtl->args.info.nregs == 0
|| get_frame_size () > 0);
}
&& ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x))
|| GET_CODE (x) == LABEL_REF))
{
- fputs ("\t.word\tpm(", asm_out_file);
+ fputs ("\t.word\tgs(", asm_out_file);
output_addr_const (asm_out_file, x);
fputs (")\n", asm_out_file);
return true;
{ "signal", 0, 0, true, false, false, avr_handle_fndecl_attribute },
{ "interrupt", 0, 0, true, false, false, avr_handle_fndecl_attribute },
{ "naked", 0, 0, false, true, true, avr_handle_fntype_attribute },
+ { "OS_task", 0, 0, false, true, true, avr_handle_fntype_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
{
fprintf (asm_out_file,
"\t.section .progmem.gcc_sw_table, \"%s\", @progbits\n",
- AVR_MEGA ? "a" : "ax");
+ AVR_HAVE_JMP_CALL ? "a" : "ax");
/* Should already be aligned, this is just to be safe if it isn't. */
fprintf (asm_out_file, "\t.p2align 1\n");
}
static void
avr_asm_init_sections (void)
{
- progmem_section = get_unnamed_section (AVR_MEGA ? 0 : SECTION_CODE,
+ progmem_section = get_unnamed_section (AVR_HAVE_JMP_CALL ? 0 : SECTION_CODE,
avr_output_progmem_section_asm_op,
NULL);
readonly_data_section = data_section;
if (AVR_HAVE_MUL)
*total = COSTS_N_INSNS (optimize_size ? 3 : 4);
else if (optimize_size)
- *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
+ *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1);
else
return false;
break;
if (AVR_HAVE_MUL)
*total = COSTS_N_INSNS (optimize_size ? 7 : 10);
else if (optimize_size)
- *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
+ *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1);
else
return false;
break;
case UDIV:
case UMOD:
if (optimize_size)
- *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
+ *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1);
else
return false;
*total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
return 18;
if (CONSTANT_ADDRESS_P (x))
{
- if (avr_io_address_p (x, 1))
+ if (optimize > 0 && io_address_operand (x, QImode))
return 2;
return 4;
}
return !(regno & 1);
}
-/* Returns 1 if X is a valid address for an I/O register of size SIZE
- (1 or 2). Used for lds/sts -> in/out optimization. Add 0x20 to SIZE
- to check for the lower half of I/O space (for cbi/sbi/sbic/sbis). */
-
-int
-avr_io_address_p (rtx x, int size)
-{
- return (optimize > 0 && GET_CODE (x) == CONST_INT
- && INTVAL (x) >= 0x20 && INTVAL (x) <= 0x60 - size);
-}
-
const char *
output_reload_inhi (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
{
avr_output_addr_vec_elt (FILE *stream, int value)
{
switch_to_section (progmem_section);
- if (AVR_MEGA)
- fprintf (stream, "\t.word pm(.L%d)\n", value);
+ if (AVR_HAVE_JMP_CALL)
+ fprintf (stream, "\t.word gs(.L%d)\n", value);
else
fprintf (stream, "\trjmp .L%d\n", value);
}