/* * picasm -- pic16bit.c * * Copyright 1995-2004 Timo Rossi, * See the file LICENSE for license terms. * */ #include #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; }