/*
* picasm -- pic16bit.c
*
* Copyright 1995-2004 Timo Rossi, <trossi@iki.fi>
* See the file LICENSE for license terms.
*
*/
#include <stdio.h>
#include "picasm.h"
#include "token.h"
#include "symtab.h"
/*
* Assemble 16-bit PIC code
*/
int
assemble_16bit_mnemonic(int op)
{
long val;
struct symbol *sym;
char *cp;
int symtype;
long i, t;
switch(op)
{
case KW_SUBLW:
case KW_ANDLW:
case KW_IORLW:
case KW_XORLW:
case KW_MULLW:
case KW_MOVLB:
case KW_MOVLR:
case KW_CPFSEQ:
case KW_CPFSGT:
case KW_CPFSLT:
if(get_expression(&val) != OK)
return FAIL;
if(val < -0x80 || val > 0xff)
error(0, "8-bit literal out of range");
if(val < 0)
val += 0x100;
switch(op)
{
case KW_SUBLW: gen_code(0xb200 | val); break;
case KW_ANDLW: gen_code(0xb500 | val); break;
case KW_IORLW: gen_code(0xb300 | val); break;
case KW_XORLW: gen_code(0xb400 | val); break;
case KW_MULLW:
if(pic_instr_set == PIC16BIT)
{
gen_code(0xbc00 | val);
}
else
{
error(1, "Unimplemented instruction MULLW");
}
break;
case KW_MOVLB: gen_code(0xb800 | (val & 0x0f)); break;
case KW_MOVLR:
if(pic_instr_set == PIC16BIT)
{
gen_code(0xba00 | (val & 0xf0));
}
else
{
error(1, "Unimplemented instruction MOVLR");
}
break;
case KW_CPFSEQ: gen_code(0x3100 | val); break;
case KW_CPFSGT: gen_code(0x3200 | val); break;
case KW_CPFSLT: gen_code(0x3000 | val); break;
}
break;
case KW_ADDLW:
if(gen_byte_c(0xb100) != OK)
return FAIL;
break;
case KW_MOVLW:
if(gen_byte_c(0xb000) != OK)
return FAIL;
break;
case KW_ADDWF:
case KW_ADDWFC:
case KW_SUBWF:
case KW_SUBWFB:
case KW_ANDWF:
case KW_IORWF:
case KW_XORWF:
case KW_COMF:
case KW_DECF:
case KW_INCF:
case KW_MOVF:
case KW_DECFSZ:
case KW_DCFSNZ:
case KW_INCFSZ:
case KW_INFSNZ:
case KW_RLCF:
case KW_RRCF:
case KW_RLNCF:
case KW_RRNCF:
case KW_SWAPF:
if(get_expression(&val) != OK)
return FAIL;
if(val < 0 || val > 0xff)
error(0, "Register file address out of range");
t = 1;
if(token_type == TOK_COMMA)
{
get_token();
if(get_expression(&t) != OK)
return FAIL;
}
else
{
if(warnlevel > 0)
warning("Destination speficier omitted");
}
val = (val & 0xff) | (t != 0 ? 0x100 : 0);
switch(op)
{
case KW_ADDWF: gen_code(0x0700 | val); break;
case KW_ADDWFC: gen_code(0x1000 | val); break;
case KW_SUBWF: gen_code(0x0400 | val); break;
case KW_SUBWFB: gen_code(0x0200 | val); break;
case KW_ANDWF: gen_code(0x0a00 | val); break;
case KW_IORWF: gen_code(0x0800 | val); break;
case KW_XORWF: gen_code(0x0c00 | val); break;
case KW_COMF: gen_code(0x1200 | val); break;
case KW_DECF: gen_code(0x0600 | val); break;
case KW_INCF: gen_code(0x1400 | val); break;
case KW_MOVFP:
/* XXX add check for PIC type - why? */
gen_code(0x6000 | val);
break;
case KW_MOVPF:
/* XXX add check for PIC type - why? */
gen_code(0x4000 | val);
break;
case KW_DECFSZ: gen_code(0x1600 | val); break;
case KW_DCFSNZ: gen_code(0x2600 | val); break;
case KW_INCFSZ: gen_code(0x1e00 | val); break;
case KW_INFSNZ: gen_code(0x2400 | val); break;
case KW_RLCF: gen_code(0x1a00 | val); break;
case KW_RRCF: gen_code(0x1800 | val); break;
case KW_RLNCF: gen_code(0x2200 | val); break;
case KW_RRNCF: gen_code(0x2000 | val); break;
case KW_SWAPF: gen_code(0x1c00 | val); break;
}
break;
/********** XXX */
case KW_MOVWF:
case KW_MULWF:
case KW_TSTFSZ:
if(get_expression(&val) != OK)
return FAIL;
if(val < 0 || val > 0xff)
error(0, "Register file address out of range");
switch(op)
{
case KW_MOVWF: gen_code(0x0100 | val); break;
case KW_MULWF:
if(pic_instr_set == PIC16BIT)
{
gen_code(0x3400 | val);
}
else
{
error(1, "Unimplemented instruction MULWF");
}
break;
case KW_TSTFSZ: gen_code(0x3300 | val); break;
}
break;
/************ XXX */
case KW_BCF:
case KW_BSF:
case KW_BTFSC:
case KW_BTFSS:
case KW_BTG:
if(get_expression(&val) != OK)
return FAIL;
if(val < 0 || val > 0xff)
error(0, "Register file address out of range");
if(token_type != TOK_COMMA)
{
error(1, "',' expected");
return FAIL;
}
get_token();
if(get_expression(&t) != OK)
return FAIL;
if(t < 0 || t > 7)
{
error(0, "Bit number out of range");
}
val |= (t << 8);
switch(op)
{
case KW_BCF: gen_code(0x8800 | val); break;
case KW_BSF: gen_code(0x8000 | val); break;
case KW_BTFSC: gen_code(0x9800 | val); break;
case KW_BTFSS: gen_code(0x9000 | val); break;
case KW_BTG: gen_code(0x3800 | val); break;
}
break;
case KW_MOVFP:
if(get_expression(&val) != OK)
return FAIL;
if(val < 0 || val > 0xff)
error(0, "Source register file address out of range");
if(token_type != TOK_COMMA)
{
error(1, "',' expected");
return FAIL;
}
get_token();
if(get_expression(&t) != OK)
return FAIL;
if(t < 0 || t > 0x1f)
{
error(0, "Destination register file address out of range");
}
val |= (t << 8);
gen_code(0x6000 | val);
break;
case KW_MOVPF:
if(get_expression(&val) != OK)
return FAIL;
if(val < 0 || val > 0x1f)
error(0, "Source register file address out of range");
if(token_type != TOK_COMMA)
{
error(1, "',' expected");
return FAIL;
}
get_token();
if(get_expression(&t) != OK)
return FAIL;
if(t < 0 || t > 0xff)
{
error(0, "Destination register file address out of range");
}
t |= (val << 8);
gen_code(0x4000 | val);
break;
case KW_CLRF: /* XXXX f,s */
case KW_DAW:
case KW_NEGW:
case KW_SETF:
if(get_expression(&val) != OK)
return FAIL;
if(val < 0 || val > 0xff)
error(0, "Register file address out of range");
t = 1;
if(token_type == TOK_COMMA)
{
get_token();
if(get_expression(&t) != OK)
return FAIL;
}
else
{
if(warnlevel > 0)
warning("Destination speficier omitted");
}
val = (val & 0xff) | (t != 0 ? 0x100 : 0);
switch(op)
{
case KW_CLRF: gen_code(0x2800 | val); break;
case KW_DAW: gen_code(0x2e00 | val); break;
case KW_NEGW: gen_code(0x2c00 | val); break;
case KW_SETF: gen_code(0x2a00 | val); break;
}
break;
case KW_TLRD: /* XXXX t,f */
case KW_TLWT:
if(get_expression(&t) != OK)
return FAIL;
if(t < 0 || t > 1)
error(0, "Upper/lower byte specifier out of range");
if(token_type != TOK_COMMA)
{
error(1, "',' expected");
return FAIL;
}
get_token();
if(get_expression(&val) != OK)
return FAIL;
if(val < 0 || val > 0xff)
error(0, "Register file address out of range");
val = (val & 0xff) | (t != 0 ? 0x200 : 0);
switch(op)
{
case KW_TLRD: gen_code(0xa000 | val); break;
case KW_TLWT: gen_code(0xa400 | val); break;
}
break;
case KW_TABLRD: /* XXXX t,i,f */
case KW_TABLWT:
if(get_expression(&t) != OK)
return FAIL;
if(t < 0 || t > 1)
error(0, "Upper/lower byte specifier out of range");
if(token_type != TOK_COMMA)
{
error(1, "',' expected");
return FAIL;
}
get_token();
if(get_expression(&i) != OK)
return FAIL;
if(i < 0 || i > 1)
error(0, "Increment flag out of range");
if(token_type != TOK_COMMA)
{
error(1, "',' expected");
return FAIL;
}
get_token();
if(get_expression(&val) != OK)
return FAIL;
if(val < 0 || val > 0xff)
error(0, "Register file address out of range");
val = (val & 0xff) | (t != 0 ? 0x200 : 0) | (i != 0 ? 0x200 : 0);
switch(op)
{
case KW_TABLRD: gen_code(0xa800 | val); break;
case KW_TABLWT: gen_code(0xac00 | val); break;
}
break;
case KW_CALL:
case KW_GOTO:
case KW_LCALL:
t = 0;
if(token_type == TOK_IDENTIFIER || token_type == TOK_LOCAL_ID)
{
symtype =
(token_type == TOK_IDENTIFIER ? SYMTAB_GLOBAL : SYMTAB_LOCAL);
if(symtype == SYMTAB_LOCAL && local_level == 0)
{
error(1, "Local symbol outside a LOCAL block");
return FAIL;
}
sym = lookup_symbol(token_string, symtype);
if(sym == NULL || sym->type == SYM_FORWARD)
{
if(sym == NULL)
{
sym = add_symbol(token_string, symtype);
sym->type = SYM_FORWARD;
}
val = 0;
add_patch(symtype, sym, PATCH11);
t = 1;
get_token();
goto gen_goto_call;
}
}
if(get_expression(&val) != OK)
return FAIL;
if(val < 0 || val >= prog_mem_size)
error(0, "GOTO/CALL address out of range");
gen_goto_call:
val &= 0x1fff;
switch(op)
{
case KW_CALL: gen_code(0xe000 | val); break;
case KW_GOTO: gen_code(0xc000 | val); break;
case KW_LCALL: gen_code(0xb700 | (val & 0xff)); break;
}
if(t)
list_flags |= LIST_FORWARD;
break;
case KW_TRIS:
error(1, "Unimplemented instruction TRIS");
return FAIL;
break;
/*
* RETLW allows multiple parameters/strings, for generating lookup tables
*/
case KW_RETLW:
for(;;)
{
if(token_type == TOK_STRCONST)
{
for(cp = token_string; *cp != '\0'; cp++)
gen_code(0xb600 | (int)((unsigned char)(*cp)));
get_token();
}
else
{
if(gen_byte_c(0xb600) != OK)
return FAIL;
}
if(token_type != TOK_COMMA)
break;
get_token();
}
break;
case KW_NOP:
gen_code(0x0000);
break;
case KW_CLRW:
gen_code(0x290a); /* actually clrf 0x0a,1 */
break;
case KW_OPTION:
error(1, "Unimplemented instruction OPTION");
return FAIL;
break;
case KW_SLEEP:
gen_code(0x0003);
break;
case KW_CLRWDT:
gen_code(0x0004);
break;
case KW_RETFIE:
gen_code(0x0005);
break;
case KW_RETURN:
gen_code(0x0002);
break;
default:
error(1, "Syntax error");
return FAIL;
}
return OK;
}
syntax highlighted by Code2HTML, v. 0.9.1