Shift simple part/memory components from grammar to config.c table
This commit is contained in:
parent
0ae6c6543b
commit
09c4b670c7
63
src/config.c
63
src/config.c
|
@ -74,21 +74,77 @@ Component_t avr_comp[] = {
|
|||
|
||||
// AVRPART
|
||||
part_comp_desc(desc, COMP_STRING),
|
||||
part_comp_desc(family_id, COMP_STRING),
|
||||
part_comp_desc(prog_modes, COMP_INT),
|
||||
part_comp_desc(mcuid, COMP_INT),
|
||||
part_comp_desc(n_interrupts, COMP_INT),
|
||||
part_comp_desc(n_page_erase, COMP_INT),
|
||||
part_comp_desc(n_boot_sections, COMP_INT),
|
||||
part_comp_desc(boot_section_size, COMP_INT),
|
||||
part_comp_desc(autobaud_sync, COMP_CHAR),
|
||||
part_comp_desc(hvupdi_variant, COMP_INT),
|
||||
part_comp_desc(stk500_devcode, COMP_INT),
|
||||
part_comp_desc(avr910_devcode, COMP_INT),
|
||||
part_comp_desc(chip_erase_delay, COMP_INT),
|
||||
part_comp_desc(pagel, COMP_CHAR),
|
||||
part_comp_desc(bs2, COMP_CHAR),
|
||||
|
||||
part_comp_desc(timeout, COMP_INT),
|
||||
part_comp_desc(stabdelay, COMP_INT),
|
||||
part_comp_desc(cmdexedelay, COMP_INT),
|
||||
part_comp_desc(synchloops, COMP_INT),
|
||||
part_comp_desc(bytedelay, COMP_INT),
|
||||
part_comp_desc(pollindex, COMP_INT),
|
||||
part_comp_desc(pollvalue, COMP_CHAR),
|
||||
part_comp_desc(predelay, COMP_INT),
|
||||
part_comp_desc(postdelay, COMP_INT),
|
||||
part_comp_desc(pollmethod, COMP_INT),
|
||||
|
||||
part_comp_desc(hventerstabdelay, COMP_INT), // STK500 v2 hv mode parameters
|
||||
part_comp_desc(progmodedelay, COMP_INT),
|
||||
part_comp_desc(latchcycles, COMP_INT),
|
||||
part_comp_desc(togglevtg, COMP_INT),
|
||||
part_comp_desc(poweroffdelay, COMP_INT),
|
||||
part_comp_desc(resetdelayms, COMP_INT),
|
||||
part_comp_desc(resetdelayus, COMP_INT),
|
||||
part_comp_desc(hvleavestabdelay, COMP_INT),
|
||||
part_comp_desc(resetdelay, COMP_INT),
|
||||
part_comp_desc(chiperasepulsewidth, COMP_INT),
|
||||
part_comp_desc(chiperasepolltimeout, COMP_INT),
|
||||
part_comp_desc(chiperasetime, COMP_INT),
|
||||
part_comp_desc(programfusepulsewidth, COMP_INT),
|
||||
part_comp_desc(programfusepolltimeout, COMP_INT),
|
||||
part_comp_desc(programlockpulsewidth, COMP_INT),
|
||||
part_comp_desc(programlockpolltimeout, COMP_INT),
|
||||
part_comp_desc(synchcycles, COMP_INT),
|
||||
part_comp_desc(hvspcmdexedelay, COMP_INT),
|
||||
|
||||
part_comp_desc(idr, COMP_CHAR),
|
||||
part_comp_desc(rampz, COMP_CHAR),
|
||||
part_comp_desc(spmcr, COMP_CHAR),
|
||||
part_comp_desc(eecr, COMP_CHAR),
|
||||
part_comp_desc(eind, COMP_CHAR),
|
||||
part_comp_desc(mcu_base, COMP_INT),
|
||||
part_comp_desc(nvm_base, COMP_INT),
|
||||
part_comp_desc(ocd_base, COMP_INT),
|
||||
part_comp_desc(ocdrev, COMP_INT),
|
||||
part_comp_desc(autobaud_sync, COMP_CHAR),
|
||||
|
||||
// AVRMEM
|
||||
mem_comp_desc(paged, COMP_BOOL),
|
||||
mem_comp_desc(size, COMP_INT),
|
||||
mem_comp_desc(num_pages, COMP_INT),
|
||||
mem_comp_desc(n_word_writes, COMP_INT),
|
||||
mem_comp_desc(offset, COMP_INT),
|
||||
mem_comp_desc(min_write_delay, COMP_INT),
|
||||
mem_comp_desc(max_write_delay, COMP_INT),
|
||||
mem_comp_desc(pwroff_after_write, COMP_INT),
|
||||
{"readback_p1", COMP_AVRMEM, offsetof(AVRMEM, readback)+0, 1, COMP_CHAR },
|
||||
{"readback_p2", COMP_AVRMEM, offsetof(AVRMEM, readback)+1, 1, COMP_CHAR },
|
||||
mem_comp_desc(mode, COMP_INT),
|
||||
mem_comp_desc(delay, COMP_INT),
|
||||
mem_comp_desc(pollindex, COMP_INT),
|
||||
mem_comp_desc(blocksize, COMP_INT),
|
||||
mem_comp_desc(readsize, COMP_INT),
|
||||
};
|
||||
|
||||
#define DEBUG 0
|
||||
|
@ -290,6 +346,9 @@ TOKEN *new_constant(const char *con) {
|
|||
!strcmp("PM_XMEGAJTAG", con)? PM_XMEGAJTAG:
|
||||
!strcmp("PM_AVR32JTAG", con)? PM_AVR32JTAG:
|
||||
!strcmp("PM_aWire", con)? PM_aWire:
|
||||
!strcmp("pseudo", con)? 2:
|
||||
!strcmp("yes", con) || !strcmp("true", con)? 1:
|
||||
!strcmp("no", con) || !strcmp("false", con)? 0:
|
||||
(assigned = 0);
|
||||
|
||||
if(!assigned) {
|
||||
|
@ -810,6 +869,7 @@ const char *cfg_comp_type(int type) {
|
|||
case COMP_INT: return "number";
|
||||
case COMP_SHORT: return "short";
|
||||
case COMP_CHAR: return "char";
|
||||
case COMP_BOOL: return "bool";
|
||||
case COMP_STRING: return "string";
|
||||
case COMP_CHAR_ARRAY: return "byte array";
|
||||
case COMP_INT_LISTID: return "number list";
|
||||
|
@ -828,6 +888,7 @@ void cfg_assign(char *sp, int strct, Component_t *cp, VALUE *v) {
|
|||
int num;
|
||||
|
||||
switch(cp->type) {
|
||||
case COMP_BOOL:
|
||||
case COMP_CHAR:
|
||||
case COMP_SHORT:
|
||||
case COMP_INT:
|
||||
|
|
|
@ -48,6 +48,7 @@ enum { // Component types in structure
|
|||
COMP_INT,
|
||||
COMP_SHORT,
|
||||
COMP_CHAR,
|
||||
COMP_BOOL,
|
||||
COMP_STRING,
|
||||
COMP_CHAR_ARRAY, // This and below are not yet implemented
|
||||
COMP_INT_LISTID,
|
||||
|
|
|
@ -71,12 +71,9 @@ static int pin_name;
|
|||
%token K_MEMORY
|
||||
|
||||
%token K_PAGE_SIZE
|
||||
%token K_PAGED
|
||||
|
||||
%token K_ALIAS
|
||||
%token K_BS2
|
||||
%token K_BUFF
|
||||
%token K_CHIP_ERASE_DELAY
|
||||
%token K_CONNTYPE
|
||||
%token K_DEDICATED
|
||||
%token K_DEFAULT_BITCLOCK
|
||||
|
@ -84,40 +81,23 @@ static int pin_name;
|
|||
%token K_DEFAULT_PROGRAMMER
|
||||
%token K_DEFAULT_SERIAL
|
||||
%token K_DEFAULT_SPI
|
||||
%token K_FAMILY_ID
|
||||
%token K_HVUPDI_SUPPORT
|
||||
%token K_HVUPDI_VARIANT
|
||||
%token K_DEVICECODE
|
||||
%token K_STK500_DEVCODE
|
||||
%token K_AVR910_DEVCODE
|
||||
%token K_EEPROM
|
||||
%token K_ERRLED
|
||||
%token K_FLASH
|
||||
%token K_ID
|
||||
%token K_IO
|
||||
%token K_LOADPAGE
|
||||
%token K_MAX_WRITE_DELAY
|
||||
%token K_MCU_BASE
|
||||
%token K_MIN_WRITE_DELAY
|
||||
%token K_SDI
|
||||
%token K_SDO
|
||||
%token K_NUM_PAGES
|
||||
%token K_NVM_BASE
|
||||
%token K_OCD_BASE
|
||||
%token K_OCDREV
|
||||
%token K_OFFSET
|
||||
%token K_PAGEL
|
||||
%token K_PARALLEL
|
||||
%token K_PARENT
|
||||
%token K_PART
|
||||
%token K_PGMLED
|
||||
%token K_PROGRAMMER
|
||||
%token K_PSEUDO
|
||||
%token K_PWROFF_AFTER_WRITE
|
||||
%token K_RDYLED
|
||||
%token K_READBACK
|
||||
%token K_READBACK_P1
|
||||
%token K_READBACK_P2
|
||||
%token K_READMEM
|
||||
%token K_RESET
|
||||
%token K_RETRY_PULSE
|
||||
|
@ -132,46 +112,8 @@ static int pin_name;
|
|||
%token K_VCC
|
||||
%token K_VFYLED
|
||||
|
||||
%token K_NO
|
||||
%token K_YES
|
||||
|
||||
/* stk500 v2 xml file parameters */
|
||||
/* ISP */
|
||||
%token K_TIMEOUT
|
||||
%token K_STABDELAY
|
||||
%token K_CMDEXEDELAY
|
||||
%token K_HVSPCMDEXEDELAY
|
||||
%token K_SYNCHLOOPS
|
||||
%token K_BYTEDELAY
|
||||
%token K_POLLVALUE
|
||||
%token K_POLLINDEX
|
||||
%token K_PREDELAY
|
||||
%token K_POSTDELAY
|
||||
%token K_POLLMETHOD
|
||||
%token K_MODE
|
||||
%token K_DELAY
|
||||
%token K_BLOCKSIZE
|
||||
%token K_READSIZE
|
||||
/* HV mode */
|
||||
%token K_HVENTERSTABDELAY
|
||||
%token K_PROGMODEDELAY
|
||||
%token K_LATCHCYCLES
|
||||
%token K_TOGGLEVTG
|
||||
%token K_POWEROFFDELAY
|
||||
%token K_RESETDELAYMS
|
||||
%token K_RESETDELAYUS
|
||||
%token K_HVLEAVESTABDELAY
|
||||
%token K_RESETDELAY
|
||||
%token K_SYNCHCYCLES
|
||||
%token K_HVCMDEXEDELAY
|
||||
|
||||
%token K_CHIPERASEPULSEWIDTH
|
||||
%token K_CHIPERASEPOLLTIMEOUT
|
||||
%token K_CHIPERASETIME
|
||||
%token K_PROGRAMFUSEPULSEWIDTH
|
||||
%token K_PROGRAMFUSEPOLLTIMEOUT
|
||||
%token K_PROGRAMLOCKPULSEWIDTH
|
||||
%token K_PROGRAMLOCKPOLLTIMEOUT
|
||||
|
||||
%token K_PP_CONTROLSTACK
|
||||
%token K_HVSP_CONTROLSTACK
|
||||
|
@ -638,10 +580,6 @@ reset_disposition :
|
|||
K_DEDICATED | K_IO
|
||||
;
|
||||
|
||||
parallel_modes :
|
||||
yesno | K_PSEUDO
|
||||
;
|
||||
|
||||
retry_lines :
|
||||
K_RESET | K_SCK
|
||||
;
|
||||
|
@ -657,40 +595,13 @@ part_parm :
|
|||
free_token($3);
|
||||
} |
|
||||
|
||||
K_FAMILY_ID TKN_EQUAL TKN_STRING
|
||||
{
|
||||
current_part->family_id = cache_string($3->value.string);
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_HVUPDI_VARIANT TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->hvupdi_variant = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_DEVICECODE TKN_EQUAL numexpr {
|
||||
{
|
||||
yyerror("devicecode is deprecated, use "
|
||||
"stk500_devcode instead");
|
||||
yyerror("devicecode is deprecated, use stk500_devcode instead");
|
||||
YYABORT;
|
||||
}
|
||||
} |
|
||||
|
||||
K_STK500_DEVCODE TKN_EQUAL numexpr {
|
||||
{
|
||||
current_part->stk500_devcode = $3->value.number;
|
||||
free_token($3);
|
||||
}
|
||||
} |
|
||||
|
||||
K_AVR910_DEVCODE TKN_EQUAL numexpr {
|
||||
{
|
||||
current_part->avr910_devcode = $3->value.number;
|
||||
free_token($3);
|
||||
}
|
||||
} |
|
||||
|
||||
K_SIGNATURE TKN_EQUAL TKN_NUMBER TKN_NUMBER TKN_NUMBER {
|
||||
{
|
||||
current_part->signature[0] = $3->value.number;
|
||||
|
@ -857,24 +768,6 @@ part_parm :
|
|||
}
|
||||
} |
|
||||
|
||||
K_CHIP_ERASE_DELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->chip_erase_delay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_PAGEL TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->pagel = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_BS2 TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->bs2 = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_RESET TKN_EQUAL reset_disposition
|
||||
{
|
||||
if ($3->primary == K_DEDICATED)
|
||||
|
@ -885,306 +778,139 @@ part_parm :
|
|||
free_tokens(2, $1, $3);
|
||||
} |
|
||||
|
||||
K_TIMEOUT TKN_EQUAL numexpr
|
||||
K_HAS_JTAG TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->timeout = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_STABDELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->stabdelay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_CMDEXEDELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->cmdexedelay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_HVSPCMDEXEDELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->hvspcmdexedelay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_SYNCHLOOPS TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->synchloops = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_BYTEDELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->bytedelay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_POLLVALUE TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->pollvalue = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_POLLINDEX TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->pollindex = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_PREDELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->predelay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_POSTDELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->postdelay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_POLLMETHOD TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->pollmethod = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_HVENTERSTABDELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->hventerstabdelay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_PROGMODEDELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->progmodedelay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_LATCHCYCLES TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->latchcycles = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_TOGGLEVTG TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->togglevtg = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_POWEROFFDELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->poweroffdelay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_RESETDELAYMS TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->resetdelayms = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_RESETDELAYUS TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->resetdelayus = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_HVLEAVESTABDELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->hvleavestabdelay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_RESETDELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->resetdelay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_CHIPERASEPULSEWIDTH TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->chiperasepulsewidth = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_CHIPERASEPOLLTIMEOUT TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->chiperasepolltimeout = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_CHIPERASETIME TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->chiperasetime = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_PROGRAMFUSEPULSEWIDTH TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->programfusepulsewidth = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_PROGRAMFUSEPOLLTIMEOUT TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->programfusepolltimeout = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_PROGRAMLOCKPULSEWIDTH TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->programlockpulsewidth = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_PROGRAMLOCKPOLLTIMEOUT TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->programlockpolltimeout = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_SYNCHCYCLES TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->synchcycles = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_HAS_JTAG TKN_EQUAL yesno
|
||||
{
|
||||
if ($3->primary == K_YES)
|
||||
if ($3->value.number == 1)
|
||||
current_part->prog_modes |= PM_JTAG;
|
||||
else if ($3->primary == K_NO)
|
||||
else if ($3->value.number == 0)
|
||||
current_part->prog_modes &= ~(PM_JTAG | PM_JTAGmkI | PM_XMEGAJTAG | PM_AVR32JTAG);
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_HAS_DW TKN_EQUAL yesno
|
||||
K_HAS_DW TKN_EQUAL numexpr
|
||||
{
|
||||
if ($3->primary == K_YES)
|
||||
if ($3->value.number == 1)
|
||||
current_part->prog_modes |= PM_debugWIRE;
|
||||
else if ($3->primary == K_NO)
|
||||
else if ($3->value.number == 0)
|
||||
current_part->prog_modes &= ~PM_debugWIRE;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_HAS_PDI TKN_EQUAL yesno
|
||||
K_HAS_PDI TKN_EQUAL numexpr
|
||||
{
|
||||
if ($3->primary == K_YES)
|
||||
if ($3->value.number == 1)
|
||||
current_part->prog_modes |= PM_PDI;
|
||||
else if ($3->primary == K_NO)
|
||||
else if ($3->value.number == 0)
|
||||
current_part->prog_modes &= ~PM_PDI;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_HAS_UPDI TKN_EQUAL yesno
|
||||
K_HAS_UPDI TKN_EQUAL numexpr
|
||||
{
|
||||
if ($3->primary == K_YES)
|
||||
if ($3->value.number == 1)
|
||||
current_part->prog_modes |= PM_UPDI;
|
||||
else if ($3->primary == K_NO)
|
||||
else if ($3->value.number == 0)
|
||||
current_part->prog_modes &= ~PM_UPDI;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_HAS_TPI TKN_EQUAL yesno
|
||||
K_HAS_TPI TKN_EQUAL numexpr
|
||||
{
|
||||
if ($3->primary == K_YES)
|
||||
if ($3->value.number == 1)
|
||||
current_part->prog_modes |= PM_TPI;
|
||||
else if ($3->primary == K_NO)
|
||||
else if ($3->value.number == 0)
|
||||
current_part->prog_modes &= ~PM_TPI;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_IS_AT90S1200 TKN_EQUAL yesno
|
||||
K_IS_AT90S1200 TKN_EQUAL numexpr
|
||||
{
|
||||
if ($3->primary == K_YES)
|
||||
if ($3->value.number == 1)
|
||||
current_part->flags |= AVRPART_IS_AT90S1200;
|
||||
else if ($3->primary == K_NO)
|
||||
else if ($3->value.number == 0)
|
||||
current_part->flags &= ~AVRPART_IS_AT90S1200;
|
||||
else {
|
||||
yyerror("not a Boolean value");
|
||||
free_token($3);
|
||||
YYABORT;
|
||||
}
|
||||
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_IS_AVR32 TKN_EQUAL yesno
|
||||
K_IS_AVR32 TKN_EQUAL numexpr
|
||||
{
|
||||
if ($3->primary == K_YES)
|
||||
if ($3->value.number == 1)
|
||||
current_part->prog_modes |= PM_aWire;
|
||||
else if ($3->primary == K_NO)
|
||||
else if ($3->value.number == 0)
|
||||
current_part->prog_modes &= ~PM_aWire;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_ALLOWFULLPAGEBITSTREAM TKN_EQUAL yesno
|
||||
K_ALLOWFULLPAGEBITSTREAM TKN_EQUAL numexpr
|
||||
{
|
||||
if ($3->primary == K_YES)
|
||||
if ($3->value.number == 1)
|
||||
current_part->flags |= AVRPART_ALLOWFULLPAGEBITSTREAM;
|
||||
else if ($3->primary == K_NO)
|
||||
else if ($3->value.number == 0)
|
||||
current_part->flags &= ~AVRPART_ALLOWFULLPAGEBITSTREAM;
|
||||
else {
|
||||
yyerror("not a Boolean value");
|
||||
free_token($3);
|
||||
YYABORT;
|
||||
}
|
||||
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_ENABLEPAGEPROGRAMMING TKN_EQUAL yesno
|
||||
K_ENABLEPAGEPROGRAMMING TKN_EQUAL numexpr
|
||||
{
|
||||
if ($3->primary == K_YES)
|
||||
if ($3->value.number == 1)
|
||||
current_part->flags |= AVRPART_ENABLEPAGEPROGRAMMING;
|
||||
else if ($3->primary == K_NO)
|
||||
else if ($3->value.number == 0)
|
||||
current_part->flags &= ~AVRPART_ENABLEPAGEPROGRAMMING;
|
||||
else {
|
||||
yyerror("not a Boolean value");
|
||||
free_token($3);
|
||||
YYABORT;
|
||||
}
|
||||
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_MCU_BASE TKN_EQUAL numexpr
|
||||
K_SERIAL TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->mcu_base = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_NVM_BASE TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->nvm_base = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_OCD_BASE TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->ocd_base = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_OCDREV TKN_EQUAL numexpr
|
||||
{
|
||||
current_part->ocdrev = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_SERIAL TKN_EQUAL yesno
|
||||
{
|
||||
if ($3->primary == K_YES)
|
||||
if ($3->value.number == 1)
|
||||
current_part->flags |= AVRPART_SERIALOK;
|
||||
else if ($3->primary == K_NO)
|
||||
else if ($3->value.number == 0)
|
||||
current_part->flags &= ~AVRPART_SERIALOK;
|
||||
else {
|
||||
yyerror("not a Boolean value");
|
||||
free_token($3);
|
||||
YYABORT;
|
||||
}
|
||||
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_PARALLEL TKN_EQUAL parallel_modes
|
||||
K_PARALLEL TKN_EQUAL numexpr
|
||||
{
|
||||
if ($3->primary == K_YES) {
|
||||
if ($3->value.number == 1) {
|
||||
current_part->flags |= AVRPART_PARALLELOK;
|
||||
current_part->flags &= ~AVRPART_PSEUDOPARALLEL;
|
||||
}
|
||||
else if ($3->primary == K_NO) {
|
||||
else if ($3->value.number == 0) {
|
||||
current_part->flags &= ~AVRPART_PARALLELOK;
|
||||
current_part->flags &= ~AVRPART_PSEUDOPARALLEL;
|
||||
}
|
||||
else if ($3->primary == K_PSEUDO) {
|
||||
else if ($3->value.number == 2) {
|
||||
current_part->flags |= AVRPART_PARALLELOK;
|
||||
current_part->flags |= AVRPART_PSEUDOPARALLEL;
|
||||
}
|
||||
else {
|
||||
yyerror("outside [0, 2] (yes/no/pseudo)");
|
||||
free_token($3);
|
||||
YYABORT;
|
||||
}
|
||||
|
||||
|
||||
free_token($3);
|
||||
|
@ -1286,11 +1012,6 @@ part_parm :
|
|||
;
|
||||
|
||||
|
||||
yesno :
|
||||
K_YES | K_NO
|
||||
;
|
||||
|
||||
|
||||
mem_specs :
|
||||
mem_spec TKN_SEMI |
|
||||
mem_alias TKN_SEMI |
|
||||
|
@ -1304,19 +1025,6 @@ mem_spec :
|
|||
free_token($1);
|
||||
} |
|
||||
|
||||
K_PAGED TKN_EQUAL yesno
|
||||
{
|
||||
current_mem->paged = $3->primary == K_YES ? 1 : 0;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_SIZE TKN_EQUAL numexpr
|
||||
{
|
||||
current_mem->size = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
|
||||
K_PAGE_SIZE TKN_EQUAL numexpr
|
||||
{
|
||||
int ps = $3->value.number;
|
||||
|
@ -1327,36 +1035,6 @@ mem_spec :
|
|||
free_token($3);
|
||||
} |
|
||||
|
||||
K_NUM_PAGES TKN_EQUAL numexpr
|
||||
{
|
||||
current_mem->num_pages = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_OFFSET TKN_EQUAL numexpr
|
||||
{
|
||||
current_mem->offset = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_MIN_WRITE_DELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_mem->min_write_delay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_MAX_WRITE_DELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_mem->max_write_delay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_PWROFF_AFTER_WRITE TKN_EQUAL yesno
|
||||
{
|
||||
current_mem->pwroff_after_write = $3->primary == K_YES ? 1 : 0;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_READBACK TKN_EQUAL TKN_NUMBER TKN_NUMBER
|
||||
{
|
||||
current_mem->readback[0] = $3->value.number;
|
||||
|
@ -1365,50 +1043,6 @@ mem_spec :
|
|||
free_token($4);
|
||||
} |
|
||||
|
||||
K_READBACK_P1 TKN_EQUAL numexpr
|
||||
{
|
||||
current_mem->readback[0] = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_READBACK_P2 TKN_EQUAL numexpr
|
||||
{
|
||||
current_mem->readback[1] = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
|
||||
K_MODE TKN_EQUAL numexpr
|
||||
{
|
||||
current_mem->mode = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_DELAY TKN_EQUAL numexpr
|
||||
{
|
||||
current_mem->delay = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_BLOCKSIZE TKN_EQUAL numexpr
|
||||
{
|
||||
current_mem->blocksize = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_READSIZE TKN_EQUAL numexpr
|
||||
{
|
||||
current_mem->readsize = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
K_POLLINDEX TKN_EQUAL numexpr
|
||||
{
|
||||
current_mem->pollindex = $3->value.number;
|
||||
free_token($3);
|
||||
} |
|
||||
|
||||
|
||||
opcode TKN_EQUAL string_list {
|
||||
{
|
||||
int opnum;
|
||||
|
|
|
@ -62,6 +62,11 @@ static int dev_message(int msglvl, const char *fmt, ...);
|
|||
dev_part_strct_entry(tsv, ".prog", id, NULL, #component, dev_sprintf(fmt, pgm->component), pgm->comments); \
|
||||
} while(0)
|
||||
|
||||
#define _if_pgmout_bool(component) do { \
|
||||
if(!base || !!base->component != !!pgm->component) \
|
||||
dev_part_strct_entry(tsv, ".prog", id, NULL, #component, dev_sprintf("%s", pgm->component? "true": "false"), pgm->comments); \
|
||||
} while(0)
|
||||
|
||||
// Result must be a malloc'd string
|
||||
#define _if_pgmout_str(cmp, result, component) do { \
|
||||
if(!base || cmp(base->component, pgm->component)) \
|
||||
|
@ -77,6 +82,11 @@ static int dev_message(int msglvl, const char *fmt, ...);
|
|||
dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->component), p->comments); \
|
||||
} while(0)
|
||||
|
||||
#define _if_partout_bool(component) do { \
|
||||
if(!base || !!base->component != !!p->component) \
|
||||
dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf("%s", p->component? "true": "false"), p->comments); \
|
||||
} while(0)
|
||||
|
||||
#define _if_n_partout(cmp, n, fmt, component) do { \
|
||||
if(!base || cmp(base->component, p->component, n)) \
|
||||
dev_part_strct_entry(tsv, ".pt", p->desc, NULL, #component, dev_sprintf(fmt, p->component), p->comments); \
|
||||
|
@ -120,6 +130,11 @@ static int dev_message(int msglvl, const char *fmt, ...);
|
|||
#define _memout_yn(component) \
|
||||
dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, cfg_strdup("_memout_yn()", m->component? "yes": "no"), m->comments)
|
||||
|
||||
#define _if_memout_bool(component) do { \
|
||||
if(!bm || !!bm->component != !!m->component) \
|
||||
dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, dev_sprintf("%s", m->component? "true": "false"), m->comments); \
|
||||
} while(0)
|
||||
|
||||
#define _if_memout_yn(component) do { \
|
||||
if(!bm || bm->component != m->component) \
|
||||
dev_part_strct_entry(tsv, ".ptmm", p->desc, m->desc, #component, cfg_strdup("_if_memout_yn()", m->component? "yes": "no"), m->comments); \
|
||||
|
|
75
src/lexer.l
75
src/lexer.l
|
@ -122,9 +122,16 @@ SIGN [+-]
|
|||
|
||||
|
||||
(?x: desc | prog_modes | baudrate | usbvid | usbdev | usbsn | usbvendor | usbproduct |
|
||||
mcuid | n_interrupts | n_page_erase | n_word_writes | n_boot_sections |
|
||||
boot_section_size | autobaud_sync | idr | rampz | spmcr | eecr | eind ) { /* struct components */
|
||||
|
||||
family_id | mcuid | n_interrupts | n_page_erase | n_boot_sections | boot_section_size |
|
||||
hvupdi_variant | stk500_devcode | avr910_devcode | chip_erase_delay | pagel | bs2 |
|
||||
timeout | stabdelay | cmdexedelay | synchloops | bytedelay | pollindex | pollvalue | predelay | postdelay | pollmethod |
|
||||
hventerstabdelay | progmodedelay | latchcycles | togglevtg | poweroffdelay | resetdelayms | resetdelayus | resetdelay | hvleavestabdelay |
|
||||
chiperasetime | (chiperase|program(fuse|lock))(polltimeout|pulsewidth) | synchcycles | hvspcmdexedelay |
|
||||
mcu_base | nvm_base | ocd_base | ocdrev |
|
||||
autobaud_sync | idr | rampz | spmcr | eecr | eind |
|
||||
paged | size | num_pages | n_word_writes | offset | min_write_delay | max_write_delay | pwroff_after_write |
|
||||
readback_p1 | readback_p2 | mode | delay | blocksize | readsize ) {
|
||||
/* struct components for PROGRAMMER, AVRPART and AVRMEM */
|
||||
Component_t *cp = cfg_comp_search(yytext, current_strct);
|
||||
if(!cp) {
|
||||
yyerror("unknown component %s in %s", yytext, cfg_strct_name(current_strct));
|
||||
|
@ -136,26 +143,17 @@ SIGN [+-]
|
|||
return TKN_COMPONENT;
|
||||
}
|
||||
|
||||
PM_(SPM|TPI|ISP|PDI|UPDI|HVSP|HVPP|debugWIRE|JTAG|JTAGmkI|XMEGAJTAG|AVR32JTAG|aWire) { /* Constants */
|
||||
|
||||
(?x: PM_(SPM|TPI|ISP|PDI|UPDI|HVSP|HVPP|debugWIRE|JTAG|JTAGmkI|XMEGAJTAG|AVR32JTAG|aWire) |
|
||||
yes|no|pseudo | true|false ) { /* Constants */
|
||||
yylval = new_constant(yytext);
|
||||
return TKN_NUMBER;
|
||||
}
|
||||
|
||||
alias { yylval=NULL; return K_ALIAS; }
|
||||
allowfullpagebitstream { yylval=NULL; ccap(); return K_ALLOWFULLPAGEBITSTREAM; }
|
||||
avr910_devcode { yylval=NULL; ccap(); return K_AVR910_DEVCODE; }
|
||||
bank_size { yylval=NULL; return K_PAGE_SIZE; }
|
||||
banked { yylval=NULL; return K_PAGED; }
|
||||
blocksize { yylval=NULL; ccap(); return K_BLOCKSIZE; }
|
||||
bs2 { yylval=NULL; ccap(); return K_BS2; }
|
||||
buff { yylval=NULL; ccap(); return K_BUFF; }
|
||||
bytedelay { yylval=NULL; ccap(); return K_BYTEDELAY; }
|
||||
chip_erase { yylval=new_token(K_CHIP_ERASE); ccap(); return K_CHIP_ERASE; }
|
||||
chip_erase_delay { yylval=NULL; ccap(); return K_CHIP_ERASE_DELAY; }
|
||||
chiperasepolltimeout { yylval=NULL; ccap(); return K_CHIPERASEPOLLTIMEOUT; }
|
||||
chiperasepulsewidth { yylval=NULL; ccap(); return K_CHIPERASEPULSEWIDTH; }
|
||||
chiperasetime { yylval=NULL; ccap(); return K_CHIPERASETIME; }
|
||||
cmdexedelay { yylval=NULL; ccap(); return K_CMDEXEDELAY; }
|
||||
connection_type { yylval=NULL; ccap(); return K_CONNTYPE; }
|
||||
dedicated { yylval=new_token(K_DEDICATED); return K_DEDICATED; }
|
||||
default_bitclock { yylval=NULL; return K_DEFAULT_BITCLOCK; }
|
||||
|
@ -163,13 +161,11 @@ default_parallel { yylval=NULL; return K_DEFAULT_PARALLEL; }
|
|||
default_programmer { yylval=NULL; return K_DEFAULT_PROGRAMMER; }
|
||||
default_serial { yylval=NULL; return K_DEFAULT_SERIAL; }
|
||||
default_spi { yylval=NULL; return K_DEFAULT_SPI; }
|
||||
delay { yylval=NULL; ccap(); return K_DELAY; }
|
||||
devicecode { yylval=NULL; ccap(); return K_DEVICECODE; }
|
||||
eeprom { yylval=NULL; return K_EEPROM; }
|
||||
eeprom_instr { yylval=NULL; ccap(); return K_EEPROM_INSTR; }
|
||||
enablepageprogramming { yylval=NULL; ccap(); return K_ENABLEPAGEPROGRAMMING; }
|
||||
errled { yylval=NULL; ccap(); return K_ERRLED; }
|
||||
family_id { yylval=NULL; ccap(); return K_FAMILY_ID; }
|
||||
flash { yylval=NULL; return K_FLASH; }
|
||||
flash_instr { yylval=NULL; ccap(); return K_FLASH_INSTR; }
|
||||
has_debugwire { yylval=NULL; ccap(); return K_HAS_DW; }
|
||||
|
@ -177,84 +173,40 @@ has_jtag { yylval=NULL; ccap(); return K_HAS_JTAG; }
|
|||
has_pdi { yylval=NULL; ccap(); return K_HAS_PDI; }
|
||||
has_tpi { yylval=NULL; ccap(); return K_HAS_TPI; }
|
||||
has_updi { yylval=NULL; ccap(); return K_HAS_UPDI; }
|
||||
hventerstabdelay { yylval=NULL; ccap(); return K_HVENTERSTABDELAY; }
|
||||
hvleavestabdelay { yylval=NULL; ccap(); return K_HVLEAVESTABDELAY; }
|
||||
hvsp_controlstack { yylval=NULL; ccap(); return K_HVSP_CONTROLSTACK; }
|
||||
hvspcmdexedelay { yylval=NULL; ccap(); return K_HVSPCMDEXEDELAY; }
|
||||
hvupdi_support { yylval=NULL; ccap(); return K_HVUPDI_SUPPORT; }
|
||||
hvupdi_variant { yylval=NULL; ccap(); return K_HVUPDI_VARIANT; }
|
||||
id { yylval=NULL; ccap(); return K_ID; }
|
||||
io { yylval=new_token(K_IO); return K_IO; }
|
||||
is_at90s1200 { yylval=NULL; ccap(); return K_IS_AT90S1200; }
|
||||
is_avr32 { yylval=NULL; ccap(); return K_IS_AVR32; }
|
||||
latchcycles { yylval=NULL; ccap(); return K_LATCHCYCLES; }
|
||||
load_ext_addr { yylval=new_token(K_LOAD_EXT_ADDR); ccap(); return K_LOAD_EXT_ADDR; }
|
||||
loadpage_hi { yylval=new_token(K_LOADPAGE_HI); ccap(); return K_LOADPAGE_HI; }
|
||||
loadpage_lo { yylval=new_token(K_LOADPAGE_LO); ccap(); return K_LOADPAGE_LO; }
|
||||
max_write_delay { yylval=NULL; ccap(); return K_MAX_WRITE_DELAY; }
|
||||
mcu_base { yylval=NULL; ccap(); return K_MCU_BASE; }
|
||||
memory { yylval=NULL; ccap(); current_strct = COMP_AVRMEM; return K_MEMORY; }
|
||||
min_write_delay { yylval=NULL; ccap(); return K_MIN_WRITE_DELAY; }
|
||||
miso { yylval=NULL; ccap(); return K_SDI; } // Deprecated
|
||||
mode { yylval=NULL; ccap(); return K_MODE; }
|
||||
mosi { yylval=NULL; ccap(); return K_SDO; } // Deprecated
|
||||
no { yylval=new_token(K_NO); return K_NO; }
|
||||
NULL { yylval=NULL; return K_NULL; }
|
||||
num_banks { yylval=NULL; return K_NUM_PAGES; }
|
||||
num_pages { yylval=NULL; ccap(); return K_NUM_PAGES; }
|
||||
nvm_base { yylval=NULL; ccap(); return K_NVM_BASE; }
|
||||
ocd_base { yylval=NULL; ccap(); return K_OCD_BASE; }
|
||||
ocdrev { yylval=NULL; ccap(); return K_OCDREV; }
|
||||
offset { yylval=NULL; ccap(); return K_OFFSET; }
|
||||
paged { yylval=NULL; ccap(); return K_PAGED; }
|
||||
pagel { yylval=NULL; ccap(); return K_PAGEL; }
|
||||
page_size { yylval=NULL; ccap(); return K_PAGE_SIZE; }
|
||||
parallel { yylval=NULL; ccap(); return K_PARALLEL; }
|
||||
parent { yylval=NULL; return K_PARENT; }
|
||||
part { yylval=NULL; ccap(); current_strct = COMP_AVRPART; return K_PART; }
|
||||
pgm_enable { yylval=new_token(K_PGM_ENABLE); ccap(); return K_PGM_ENABLE; }
|
||||
pgmled { yylval=NULL; ccap(); return K_PGMLED; }
|
||||
pollindex { yylval=NULL; ccap(); return K_POLLINDEX; }
|
||||
pollmethod { yylval=NULL; ccap(); return K_POLLMETHOD; }
|
||||
pollvalue { yylval=NULL; ccap(); return K_POLLVALUE; }
|
||||
postdelay { yylval=NULL; ccap(); return K_POSTDELAY; }
|
||||
poweroffdelay { yylval=NULL; ccap(); return K_POWEROFFDELAY; }
|
||||
pp_controlstack { yylval=NULL; ccap(); return K_PP_CONTROLSTACK; }
|
||||
predelay { yylval=NULL; ccap(); return K_PREDELAY; }
|
||||
progmodedelay { yylval=NULL; ccap(); return K_PROGMODEDELAY; }
|
||||
programfusepolltimeout { yylval=NULL; ccap(); return K_PROGRAMFUSEPOLLTIMEOUT; }
|
||||
programfusepulsewidth { yylval=NULL; ccap(); return K_PROGRAMFUSEPULSEWIDTH; }
|
||||
programlockpolltimeout { yylval=NULL; ccap(); return K_PROGRAMLOCKPOLLTIMEOUT; }
|
||||
programlockpulsewidth { yylval=NULL; ccap(); return K_PROGRAMLOCKPULSEWIDTH; }
|
||||
programmer { yylval=NULL; ccap(); current_strct = COMP_PROGRAMMER; return K_PROGRAMMER; }
|
||||
pseudo { yylval=new_token(K_PSEUDO); return K_PSEUDO; }
|
||||
pwroff_after_write { yylval=NULL; ccap(); return K_PWROFF_AFTER_WRITE; }
|
||||
rdyled { yylval=NULL; ccap(); return K_RDYLED; }
|
||||
read { yylval=new_token(K_READ); ccap(); return K_READ; }
|
||||
read_hi { yylval=new_token(K_READ_HI); ccap(); return K_READ_HI; }
|
||||
read_lo { yylval=new_token(K_READ_LO); ccap(); return K_READ_LO; }
|
||||
readback { yylval=NULL; ccap(); return K_READBACK; }
|
||||
readback_p1 { yylval=NULL; ccap(); return K_READBACK_P1; }
|
||||
readback_p2 { yylval=NULL; ccap(); return K_READBACK_P2; }
|
||||
readsize { yylval=NULL; ccap(); return K_READSIZE; }
|
||||
reset { yylval=new_token(K_RESET); ccap(); return K_RESET; }
|
||||
resetdelay { yylval=NULL; ccap(); return K_RESETDELAY; }
|
||||
resetdelayms { yylval=NULL; ccap(); return K_RESETDELAYMS; }
|
||||
resetdelayus { yylval=NULL; ccap(); return K_RESETDELAYUS; }
|
||||
retry_pulse { yylval=NULL; ccap(); return K_RETRY_PULSE; }
|
||||
sck { yylval=new_token(K_SCK); ccap(); return K_SCK; }
|
||||
sdi { yylval=NULL; ccap(); return K_SDI; }
|
||||
sdo { yylval=NULL; ccap(); return K_SDO; }
|
||||
serial { yylval=NULL; ccap(); return K_SERIAL; }
|
||||
signature { yylval=NULL; ccap(); return K_SIGNATURE; }
|
||||
size { yylval=NULL; ccap(); return K_SIZE; }
|
||||
spi { yylval=NULL; return K_SPI; }
|
||||
stabdelay { yylval=NULL; ccap(); return K_STABDELAY; }
|
||||
stk500_devcode { yylval=NULL; ccap(); return K_STK500_DEVCODE; }
|
||||
synchcycles { yylval=NULL; ccap(); return K_SYNCHCYCLES; }
|
||||
synchloops { yylval=NULL; ccap(); return K_SYNCHLOOPS; }
|
||||
timeout { yylval=NULL; ccap(); return K_TIMEOUT; }
|
||||
togglevtg { yylval=NULL; ccap(); return K_TOGGLEVTG; }
|
||||
type { yylval=NULL; ccap(); return K_TYPE; }
|
||||
usb { yylval=NULL; return K_USB; }
|
||||
usbpid { yylval=NULL; ccap(); return K_USBPID; }
|
||||
|
@ -264,7 +216,6 @@ write { yylval=new_token(K_WRITE); ccap(); return K_WRITE; }
|
|||
write_hi { yylval=new_token(K_WRITE_HI); ccap(); return K_WRITE_HI; }
|
||||
write_lo { yylval=new_token(K_WRITE_LO); ccap(); return K_WRITE_LO; }
|
||||
writepage { yylval=new_token(K_WRITEPAGE); ccap(); return K_WRITEPAGE; }
|
||||
yes { yylval=new_token(K_YES); return K_YES; }
|
||||
|
||||
"," { yylval = NULL; pyytext(); return TKN_COMMA; }
|
||||
"=" { yylval = NULL; pyytext(); return TKN_EQUAL; }
|
||||
|
|
Loading…
Reference in New Issue