;****************************************************************
;**           :
;** Project   : Personal Logic Debugger (PLD)
;** Filename  : PICMACRO.ASM
;** Author    : Don Lekei
;** Status    : Experimental
;** Date      : 08/27/93
;** Purpose   : Define common Macros and Memory segments
;**           :
;****************************************************************
;
;*************************************************************************
;* Define Segments and other CPU SPECIFIC constants
;*
;* Register and code are defined in banks to prevent accidental wrap
;* to next bank. These segment definitions help manage the different
;* memory areas.
;*
;*************************************************************************

        .switch PICDEVICE

        .case   1654
        .cpu    16c54
_RESVEC =       $01FF            	;16c54
IDLOC = _RESVEC+1
FUSELOC = $FFF
        DEFSEG  REGS,  $00, $20         ;initial regs
        DEFSEG  CODE, $000,_RESVEC      ;Base code segment
        DEFSEG  RESET,_RESVEC,_RESVEC+1 ;Reset Vector
	DEFSEG ID,IDLOC,IDLOC+4        ;ID word segment
	DEFSEG FUSES,FUSELOC,FUSELOC+1  ;Config fuses
	
        .else

        .case   1655
        .cpu    16c55
_RESVEC =       $01FF            	;16c55
IDLOC = _RESVEC+1
FUSELOC = $FFF
        DEFSEG  REGS,   $00, $20        ;initial regs
        DEFSEG  CODE0, $000,$100	;Base code segment
        DEFSEG  CODE0J,$100,_RESVEC	;Base GOTO segment
        DEFSEG  RESET,_RESVEC,_RESVEC+1 ;Reset Vector
	DEFSEG ID,IDLOC,IDLOC+4        ;ID word segment
	DEFSEG FUSES,FUSELOC,FUSELOC+1  ;Config fuses
        .else

        .case   1656
        .cpu    16c56
_RESVEC =       $03FF            	;16C56
IDLOC = _RESVEC+1
FUSELOC = $FFF
        DEFSEG  REGS,   $00, $20        ;initial regs
        DEFSEG  CODE0, $000,$100	;Base code segment
        DEFSEG  CODE0J,$100,$200        ;Base GOTO segment
        DEFSEG  CODE1, $200,$300	;Bank 1
        DEFSEG  CODE1J,$300,_RESVEC     ;Bank 1 GOTO segment
        DEFSEG  RESET,_RESVEC,_RESVEC+1 ;Reset Vector
	DEFSEG ID,IDLOC,IDLOC+4        ;ID word segment
	DEFSEG FUSES,FUSELOC,FUSELOC+1  ;Config fuses
        .else

        .case   1657
        .cpu    16c57
_RESVEC =       $07FF            	;16C57
IDLOC = _RESVEC+1
FUSELOC = $FFF
        DEFSEG  REGS,   $00, $20        ;initial regs
        DEFSEG  REGS1,  $30, $40        ;banked regs
        DEFSEG  REGS2,  $50, $60        ;banked regs
        DEFSEG  REGS3,  $70, $80        ;banked regs
        DEFSEG  CODE0, $000,$100        ;Base code segment
        DEFSEG  CODE0J,$100,$200        ;Base GOTO segment
        DEFSEG  CODE1, $200,$300        ;Bank 1
        DEFSEG  CODE1J,$300,$400        ;Bank 1 GOTO segment
        DEFSEG  CODE2, $400,$500        ;bank 2
        DEFSEG  CODE2J,$500,$600        ;bank 2 GOTO segment
        DEFSEG  CODE3, $600,$700        ;bank 3
        DEFSEG  CODE3J,$700,_RESVEC     ;bank 3 GOTO segment
        DEFSEG  RESET,_RESVEC,_RESVEC+1 ;Reset Vector
	DEFSEG ID,IDLOC,IDLOC+4         ;ID word segment
	DEFSEG FUSES,FUSELOC,FUSELOC+1  ;Config fuses
        .else

        .case   1671                    ;16c71 & 84 share these settings...
        .cpu    16c71

	.case   1684			;16c84 enters here...
	.if (PICDEVICE == 1684)
	 .cpu	16c84
	DEFSEG DATA,$2100,$2140	;data EEPROM segment for 16c84
	.endif

_RESVEC =       $000			;16C71/84 RESET VECTOR
_INTVEC =       $004			;START OF INTERRUPT AREA
DATABASE =      $300			;BANK for DATA TABLES
IDLOC 	 = $2000
FUSELOC  = $2007
        DEFSEG  REGS, $00,$30          	;initial regs
	DEFSEG  REGS2,$80,$8C		;special regs - bank2
        DEFSEG  RESET,_RESVEC,_INTVEC   ;Reset Vector

        DEFSEG  CODE,_INTVEC,DATABASE	;Code segment for GOTO/CALL
        DEFSEG  ROMDATA,DATABASE,$400	;Code segment for PC-modify INSTRS
	DEFSEG ID,IDLOC,IDLOC+4         ;ID word segment
	DEFSEG FUSES,FUSELOC,FUSELOC+1  ;Config fuses

	.else
	case	1742
	.cpu	17c42
_RESVEC =       $000			;16C71/84 RESET VECTOR
_INTVEC =       $004			;START OF INTERRUPT AREA
FUSELOC  = $FE00
	DEFSEG FUSES,FUSELOC,FUSELOC+1  ;Config fuses
        DEFSEG  REGS, $18,$100         	;registers
	DEFSEG	CODE, $0, $800		;code area

        .endif

;**********************************************************************
;* 
;* Define Config Bits for various processors
;* 
;**********************************************************************

	.switch PICDEVICE
	.case 1654
	.case 1655
	.case 1656
	.case 1657
_CP	= %00001000		;Code protect (0 = PROTECT)
_WDTE	= %00000100		;WDT 0 = disable
_LPOSC  = 0			;LP Osc select
_XTOSC  = 1                     ;XT Osc select
_HSOSC  = 2                     ;HS Osc select
_RCOSC  = 3                     ;RC Osc select

	.else
	.case 1671
	.case 1684
_CP	= %00010000		;Code protect (0 = PROTECT)
_PWRTE	= %00001000		;Power up timer enable 0=disable
_WDTE	= %00000100		;WDT 0 = disable
_LPOSC  = 0			;LP Osc select
_XTOSC  = 1                     ;XT Osc select
_HSOSC  = 2                     ;HS Osc select
_RCOSC  = 3                     ;RC Osc select
	.else
	.case 1742
_FPMM1	= %00010000		;Extended Microcontroller (0 = CODE PROTECT)
_FPMM2	= %01000000		;Microcontroller mode (0 = CODE PROTECT)
_FPMM3	= %01010000		;Microprocessor mode (0 = CODE PROTECT)
_FWDT1	= %00001100		;WDT prescaler = 1  (0=disabled)
_FWDT64	= %00000100		;WDT prescaler = 1
_FWDT256 = %00001000		;WDT prescaler = 256
_LFOSC  = 0			;LP Osc select
_RCOSC  = 1                     ;RC Osc select
_XTOSC  = 2                     ;XT Osc select
_ECOSC  = 3                     ;EC Osc select (external clock)
	.endif


	.if (PICDEVICE < 1660)
;*** Code/Data bank management *******************************************

..obank = 0     ;keep track of old code bank (power up = 0)
..bankfwd = 0                   ;say bank is valid

;*************************************************************************
;* CODEBANK( target )  -- function macro
;* return the code bank of the target address
;*
;* CODEBANK            -- code macro
;* assume that the code bank is the current page: THIS SHOULD BE CALLED
;* at the begining of every code bank.
;*
;************************************************************************

CODEBANK( .macro *target )      ;return target's bank (0-3)
( (target)/$200 )
        .endm

CODEBANK  .macro *              ;sync bank assumption
..obank =       CODEBANK(*)
..bankfwd = 0                   ;say bank is valid
        .endm

;*************************************************************************
;** NBANK
;** Macro to set bank bits and preserve last setting. Checks for forward
;** ref to disable optimization.
;** Define WarnFWD to enable forward ref warning.
;**
;*************************************************************************
NBANK:  .macro  *[1]                    ;set bank
..deltabank =   [1] ^ ..obank   ;check for changed bits
        .if ('[1.0.1]' == ':')||(..bankfwd)     ;check for forward reference
..deltabank =   (PICDEVICE == 1657) ? 3 : 1     ;force full set/clear
..bankfwd = 1                                   ;flag last bank was fwd ref
        .if isdef(WarnFWD) && PICDEVICE=1657
          .warn "Forward ref in bank change"
        .endif
        .endif

        .if ('[1.0.1]' != ':')          ;check for forward reference
..bankfwd =     0                       ;this one wasn't actually fwd ref
        .endif

        .switch (..deltabank)           ;check for changed bits

        .case   1                       ;bit 0 only changed
         .if ([1] & 1)
          bsf   RA0
         .else
          bcf   RA0
         .endif
        .else

        .case   2                       ;bit 1 only changed
         .if ([1] & 2)
          bsf   RA1
         .else
          bcf   RA1
         .endif
        .else

        .case   3                       ;bit 0 & 1 changed
         .if ([1] & 1)
          bsf   RA0
         .else
          bcf   RA0
         .endif
         .if ([1] & 2)
          bsf   RA1
         .else
          bcf   RA1
         .endif
        .endif
..obank = [1]                           ;record new bank setting
        .endm

;*************************************************************************
;** LGOTO, LCALL
;** Long GOTO and CALL, MACROs TO Generate auto bank switching for
;** 17C56 / 17C57 processors if required
;**
;*************************************************************************
LGOTO:  .macro  *target
..pbank = ..obank                ;save old bank
..pfwd = ..bankfwd
        NBANK   CODEBANK(target) ;set new bank
        GOTO    target
..obank = ..pbank                ;following code will not see the change!
..bankfwd = ..pfwd               ;restore forward ref flag
        .endm

LCALL:  .macro *target
        NBANK   CODEBANK(target) ;set new bank
        .if (target & $100)
         error "Address cannot be called"
        .endif
        CALL    target           ;call routine
        NBANK   CODEBANK(*)      ;set bank to here
        .endm

;*************************************************************************
;** _LCALL
;** Similar to LCALL except bank is not restored (to prevent redundant
;** bank switches in tables of calls.
;**
;*************************************************************************
_LCALL: .macro *target
        NBANK   CODEBANK(target) ;set new bank
        .if (target & $100)
         error "Address cannot be called"
        .endif
        CALL    target           ;call routine
        .endm

;*************************************************************************
;** SPLIT
;** Macro to split code and continue in alternate segment
;**
;*************************************************************************
SPLIT: .macro *[1]              ;split code into alternate segment
        goto [continue]
        .seg [1]
[continue]:
       .endm

;*************************************************************************
;** LSPLIT
;** Split code to FAR segment. NOTE: may take 2,3, or 4 cycles
;**
;*************************************************************************
LSPLIT: .macro  *[1]            ;split code into far segment
        NBANK   CODEBANK([continue]) ;set new bank
        goto [continue]
        .seg [1]
[continue]:
        .endm

;*************************************************************************
;** UNSPLIT
;** Restore segment after LSPLIT. NOTE: may take
;**
;*************************************************************************
UNSPLIT:        .macro *[1]     ;restore old bank and return
        NBANK   CODEBANK([return]) ;set new bank to old segment
        RETLW   [1]
        .oldseg                 ;restore previous segment
[return]:
        .endm
	.endif ;--- end of 16c56/57 bank management code ---

;*************************************************************************
;** port()
;** Returns the address portion (eg. port) of a bitlabel
;**
;*************************************************************************
port( .macro *[1] )     ;return the port of a bit label
(       [1]>>8 )
        .endm

;*************************************************************************
;*
;* SEB & CLB MACROS are not necessary with ASPIC as BSF etc. work with
;* Labels. Using these macros makes it easer to port to MPASM if necessary.
;*
;*************************************************************************

SEB     MACRO   *label           ;set bit
        BSF     label
        ENDM

CLB     MACRO   *label           ;clear bit
        BCF     label
        ENDM


;**********************************************************************
;*
;* Two cycle delay
;*
;**********************************************************************

DEL2    .macro
..del   goto    ..del+1           ;delay 2 cycles
        .endm

;**********************************************************************
;*
;* Indirect call. Requires the line:
;*
;*         CALLW: movwf PCL
;* somewhere in memory.  This assumes that all data is in 1 block and
;* PCLATH never changes.
;*
;**********************************************************************

CALLW	.macro *[1]		;indirect call
	call	CALLW		;
	.endm
