;*******************************************************************
;  ENIGMA.ASM
;  Intelligent Parallel-port encryption dongle based on a 3-rotor
;  German WWII Enigma machine algorithm
;
;  Professor M. Csele, Niagara College, Canada
;  http://technology.niagarac.on.ca/people/mcsele/Enigma.html
;
;  Revision History:
;    1.0 - 2003/12/12, Original version for use with MPASM 2.1
;    1.1 - 2007/04/26, Updated for MPLAB 7.5x (new CONFIG)
;*******************************************************************
;   Target: PIC16F84 MCU     Assembler/IDE: MPLAB 7.5x
;
;   Hardware:
;   Port B
;   RB0 - RB4       Plaintext character Input 0x00 to 0x2F.
;   RB5             Hi/Lo nibble select: Lo=Lo nibble, Hi=Hi nibble
;   RB6             Ready output - high indicates code is available
;   RB7             Strobe Input - High causes conversion to begin
;
;   Port A
;   RA0 - RA4       Ciphertext character Output 0x00 to 0x2F.
;                   Remember to add a 2K2 pull-up resistor to RA4
;
;   Notes:
;   Input and output characters are not ASCII but rather a simple code
;   where 0x00 represents 'A' and 0x19 (25 dec) represents 'Z'.  The
;   Enigma only supports characters A-Z.
;*******************************************************************
;   Define type of processor to use and include file of standard EQUs
;
        LIST P=16F84
        include "P16F84.INC"

		;Configuration - RC Oscillator, WDT Off, PowerUp On
		__CONFIG	_CP_OFF&_WDT_OFF&_RC_OSC&_PWRTE_ON


;Define Registers Used
Rotor1Position   equ    11   ;Incremental pointers to calculate as
Rotor2Position   equ    12   ;rotors rotate after each character
Rotor3Position   equ    13   ;enciphered (Offset)

InputRotorPosition equ   14   ;Actual computed rotor positions
InputRotorResult   equ   15
TempRotorPosition  equ   16   ;Actual computed rotor positions
TempRotorResult    equ   17

Rotor1Output      equ   20   ;Actual output from rotor prior to mapping w/offset
Rotor2Output      equ   21   ;Actual output from rotor prior to mapping w/offset
Rotor3Output      equ   22   ;Actual output from rotor prior to mapping w/offset

;Define Port B Lines Used
HI_NIBBLE     equ    5       ;Input. Lo=Lo 4 bits, Hi=Hi 4 bits
STROBE        equ    7       ;Output. Lo-&gt;Hi starts conversion
READY         equ    6       ;Hi=ready/data available

        org 0
        goto    main          ;Jump over rotor tables

;Rotor Tables: these act to transpose characters as did the mechanical
;              rotors in the original machine
Rotor1Forward
     addwf     PCL,f
     retlw     .14       ;Char  0  mapping
     retlw     .15       ;Char  1  mapping
     retlw     .7        ;Char  2  mapping
     retlw     .9        ;Char  3  mapping
     retlw     .24       ;Char  4  mapping
     retlw     .16       ;Char  5  mapping
     retlw     .18       ;Char  6  mapping
     retlw     .8        ;Char  7  mapping
     retlw     .17       ;Char  8  mapping
     retlw     .0        ;Char  9  mapping
     retlw     .10       ;Char  10  mapping
     retlw     .21       ;Char  11  mapping
     retlw     .6        ;Char  12  mapping
     retlw     .2        ;Char  13  mapping
     retlw     .19       ;Char  14  mapping
     retlw     .25       ;Char  15  mapping
     retlw     .4        ;Char  16  mapping
     retlw     .5        ;Char  17  mapping
     retlw     .1        ;Char  18  mapping
     retlw     .23       ;Char  19  mapping
     retlw     .12       ;Char  20  mapping
     retlw     .22       ;Char  21  mapping
     retlw     .13       ;Char  22  mapping
     retlw     .20       ;Char  23  mapping
     retlw     .11       ;Char  24  mapping
     retlw     .3        ;Char  25  mapping

Rotor2Forward
     addwf     PCL,f
     retlw     .19       ;Char  0  mapping
     retlw     .16       ;Char  1  mapping
     retlw     .12       ;Char  2  mapping
     retlw     .15       ;Char  3  mapping
     retlw     .24       ;Char  4  mapping
     retlw     .1        ;Char  5  mapping
     retlw     .7        ;Char  6  mapping
     retlw     .6        ;Char  7  mapping
     retlw     .3        ;Char  8  mapping
     retlw     .20       ;Char  9  mapping
     retlw     .2        ;Char  10  mapping
     retlw     .5        ;Char  11  mapping
     retlw     .9        ;Char  12  mapping
     retlw     .10       ;Char  13  mapping
     retlw     .21       ;Char  14  mapping
     retlw     .22       ;Char  15  mapping
     retlw     .13       ;Char  16  mapping
     retlw     .4        ;Char  17  mapping
     retlw     .8        ;Char  18  mapping
     retlw     .11       ;Char  19  mapping
     retlw     .14       ;Char  20  mapping
     retlw     .25       ;Char  21  mapping
     retlw     .23       ;Char  22  mapping
     retlw     .17       ;Char  23  mapping
     retlw     .0        ;Char  24  mapping
     retlw     .18       ;Char  25  mapping

Rotor3Forward
     addwf     PCL,f
     retlw     .2        ;Char  0  mapping
     retlw     .25       ;Char  1  mapping
     retlw     .13       ;Char  2  mapping
     retlw     .5        ;Char  3  mapping
     retlw     .23       ;Char  4  mapping
     retlw     .0        ;Char  5  mapping
     retlw     .10       ;Char  6  mapping
     retlw     .18       ;Char  7  mapping
     retlw     .9        ;Char  8  mapping
     retlw     .14       ;Char  9  mapping
     retlw     .11       ;Char  10  mapping
     retlw     .3        ;Char  11  mapping
     retlw     .7        ;Char  12  mapping
     retlw     .20       ;Char  13  mapping
     retlw     .4        ;Char  14  mapping
     retlw     .19       ;Char  15  mapping
     retlw     .16       ;Char  16  mapping
     retlw     .6        ;Char  17  mapping
     retlw     .8        ;Char  18  mapping
     retlw     .17       ;Char  19  mapping
     retlw     .12       ;Char  20  mapping
     retlw     .24       ;Char  21  mapping
     retlw     .22       ;Char  22  mapping
     retlw     .1        ;Char  23  mapping
     retlw     .21       ;Char  24  mapping
     retlw     .15       ;Char  25  mapping

Reflector
     addwf     PCL,f
     retlw     .23       ;Reflecting Rotor mapping to  0
     retlw     .11       ;Reflecting Rotor mapping to  1
     retlw     .5        ;Reflecting Rotor mapping to  2
     retlw     .12       ;Reflecting Rotor mapping to  3
     retlw     .8        ;Reflecting Rotor mapping to  4
     retlw     .2        ;Reflecting Rotor mapping to  5
     retlw     .7        ;Reflecting Rotor mapping to  6
     retlw     .6        ;Reflecting Rotor mapping to  7
     retlw     .4        ;Reflecting Rotor mapping to  8
     retlw     .14       ;Reflecting Rotor mapping to  9
     retlw     .16       ;Reflecting Rotor mapping to  10
     retlw     .1        ;Reflecting Rotor mapping to  11
     retlw     .3        ;Reflecting Rotor mapping to  12
     retlw     .18       ;Reflecting Rotor mapping to  13
     retlw     .9        ;Reflecting Rotor mapping to  14
     retlw     .24       ;Reflecting Rotor mapping to  15
     retlw     .10       ;Reflecting Rotor mapping to  16
     retlw     .25       ;Reflecting Rotor mapping to  17
     retlw     .13       ;Reflecting Rotor mapping to  18
     retlw     .21       ;Reflecting Rotor mapping to  19
     retlw     .22       ;Reflecting Rotor mapping to  20
     retlw     .19       ;Reflecting Rotor mapping to  21
     retlw     .20       ;Reflecting Rotor mapping to  22
     retlw     .0        ;Reflecting Rotor mapping to  23
     retlw     .15       ;Reflecting Rotor mapping to  24
     retlw     .17       ;Reflecting Rotor mapping to  25

Rotor1Reverse
     addwf     PCL,f
     retlw     .9        ;Char  0  mapping for reverse rotor
     retlw     .18       ;Char  1  mapping for reverse rotor
     retlw     .13       ;Char  2  mapping for reverse rotor
     retlw     .25       ;Char  3  mapping for reverse rotor
     retlw     .16       ;Char  4  mapping for reverse rotor
     retlw     .17       ;Char  5  mapping for reverse rotor
     retlw     .12       ;Char  6  mapping for reverse rotor
     retlw     .2        ;Char  7  mapping for reverse rotor
     retlw     .7        ;Char  8  mapping for reverse rotor
     retlw     .3        ;Char  9  mapping for reverse rotor
     retlw     .10       ;Char  10  mapping for reverse rotor
     retlw     .24       ;Char  11  mapping for reverse rotor
     retlw     .20       ;Char  12  mapping for reverse rotor
     retlw     .22       ;Char  13  mapping for reverse rotor
     retlw     .0        ;Char  14  mapping for reverse rotor
     retlw     .1        ;Char  15  mapping for reverse rotor
     retlw     .5        ;Char  16  mapping for reverse rotor
     retlw     .8        ;Char  17  mapping for reverse rotor
     retlw     .6        ;Char  18  mapping for reverse rotor
     retlw     .14       ;Char  19  mapping for reverse rotor
     retlw     .23       ;Char  20  mapping for reverse rotor
     retlw     .11       ;Char  21  mapping for reverse rotor
     retlw     .21       ;Char  22  mapping for reverse rotor
     retlw     .19       ;Char  23  mapping for reverse rotor
     retlw     .4        ;Char  24  mapping for reverse rotor
     retlw     .15       ;Char  25  mapping for reverse rotor

Rotor2Reverse
     addwf     PCL,f
     retlw     .24       ;Char  0  mapping for reverse rotor
     retlw     .5        ;Char  1  mapping for reverse rotor
     retlw     .10       ;Char  2  mapping for reverse rotor
     retlw     .8        ;Char  3  mapping for reverse rotor
     retlw     .17       ;Char  4  mapping for reverse rotor
     retlw     .11       ;Char  5  mapping for reverse rotor
     retlw     .7        ;Char  6  mapping for reverse rotor
     retlw     .6        ;Char  7  mapping for reverse rotor
     retlw     .18       ;Char  8  mapping for reverse rotor
     retlw     .12       ;Char  9  mapping for reverse rotor
     retlw     .13       ;Char  10  mapping for reverse rotor
     retlw     .19       ;Char  11  mapping for reverse rotor
     retlw     .2        ;Char  12  mapping for reverse rotor
     retlw     .16       ;Char  13  mapping for reverse rotor
     retlw     .20       ;Char  14  mapping for reverse rotor
     retlw     .3        ;Char  15  mapping for reverse rotor
     retlw     .1        ;Char  16  mapping for reverse rotor
     retlw     .23       ;Char  17  mapping for reverse rotor
     retlw     .25       ;Char  18  mapping for reverse rotor
     retlw     .0        ;Char  19  mapping for reverse rotor
     retlw     .9        ;Char  20  mapping for reverse rotor
     retlw     .14       ;Char  21  mapping for reverse rotor
     retlw     .15       ;Char  22  mapping for reverse rotor
     retlw     .22       ;Char  23  mapping for reverse rotor
     retlw     .4        ;Char  24  mapping for reverse rotor
     retlw     .21       ;Char  25  mapping for reverse rotor

Rotor3Reverse
     addwf     PCL,f
     retlw     .5        ;Char  0  mapping for reverse rotor
     retlw     .23       ;Char  1  mapping for reverse rotor
     retlw     .0        ;Char  2  mapping for reverse rotor
     retlw     .11       ;Char  3  mapping for reverse rotor
     retlw     .14       ;Char  4  mapping for reverse rotor
     retlw     .3        ;Char  5  mapping for reverse rotor
     retlw     .17       ;Char  6  mapping for reverse rotor
     retlw     .12       ;Char  7  mapping for reverse rotor
     retlw     .18       ;Char  8  mapping for reverse rotor
     retlw     .8        ;Char  9  mapping for reverse rotor
     retlw     .6        ;Char  10  mapping for reverse rotor
     retlw     .10       ;Char  11  mapping for reverse rotor
     retlw     .20       ;Char  12  mapping for reverse rotor
     retlw     .2        ;Char  13  mapping for reverse rotor
     retlw     .9        ;Char  14  mapping for reverse rotor
     retlw     .25       ;Char  15  mapping for reverse rotor
     retlw     .16       ;Char  16  mapping for reverse rotor
     retlw     .19       ;Char  17  mapping for reverse rotor
     retlw     .7        ;Char  18  mapping for reverse rotor
     retlw     .15       ;Char  19  mapping for reverse rotor
     retlw     .13       ;Char  20  mapping for reverse rotor
     retlw     .24       ;Char  21  mapping for reverse rotor
     retlw     .22       ;Char  22  mapping for reverse rotor
     retlw     .4        ;Char  23  mapping for reverse rotor
     retlw     .21       ;Char  24  mapping for reverse rotor
     retlw     .1        ;Char  25  mapping for reverse rotor


main
        movlw   b'10111111'   ;Make Port B all inputs except RB6
        tris    PORTB         ; using the TRIState command

        movlw   0             ;Make Port A all outputs
        tris    PORTA

        clrf    Rotor1Position  ;Start at 'AAA' rotor position
        clrf    Rotor2Position
        clrf    Rotor3Position

        bcf     PORTB,READY	  ;Not Ready

loop
		  ;Ensure STROBE is LOW to catch Lo-&gt;Hi transition
        btfsc   PORTB,STROBE
        goto    loop

        bsf     PORTB,READY     ;Ready to accept data / last data available
		                          ;indicated only after strobe goes low
		  					  
        ;Wait for STROBE to go high to start next encipher
WaitForHiStrobe		  
        btfss   PORTB,STROBE
        goto    WaitForHiStrobe

        bcf     PORTB,READY     ;Busy processing
		  
        ;Look Up plaintext char at Port B (5 LSB lines)
        movf    PORTB,w
        andlw   b'00011111'

;ROTOR 1 FORWARD
		  ;Step 1) Map the INPUT char to the rotor input terminal
        ;Add Offset (Rotor1Position) to the input in Mod-26
        addwf   Rotor1Position,w
        movwf   InputRotorPosition  ;Save result
		  movlw   .26
		  subwf   InputRotorPosition,w
        movwf   InputRotorResult
        ;If original position(pointer) was &lt; 26 then the result is &lt;0
        ;so use the original value which is in range 0-25
        btfsc   InputRotorResult,7  ;If result is negative, original
        goto    Rotor1PositionOk   ; was &lt;26 so just use it
        ;If the original was &gt;26 it is NOW mod-26 (&lt;26).  Use that instead
        movf    InputRotorResult,w
        movwf   InputRotorPosition
Rotor1PositionOk
        ;Step 2) Transpose character via the rotor itself
        movf    InputRotorPosition,w
        call    Rotor1Forward      ;Transpose in forward direction
        movwf   Rotor1Output
        ;Step 3) Map the rotor output terminal to the correct char
        ;Subtract the offset from the output terminal in MOD-26
        movf    Rotor1Position,w
        subwf   Rotor1Output,w     ;w=Output-w
        movwf   TempRotorResult
        ;If negative, process as mod-26 by adding 26 to negative result
        btfss   TempRotorResult,7
        goto    Rotor1OutputMappedOk
        addlw   .26                ;e.g. 0xFF(-1)+.26=.25
        movwf   TempRotorResult
Rotor1OutputMappedOk
        ;DONE! Input char is mapped by rotor and rotor position
        movf    TempRotorResult,w

;ROTOR 2 FORWARD
		  ;Step 1) Map the INPUT char to the rotor input terminal
        ;Add Offset (Rotor2Position) to the input in Mod-26
        addwf   Rotor2Position,w
        movwf   InputRotorPosition  ;Save result
		  movlw   .26
		  subwf   InputRotorPosition,w
        movwf   InputRotorResult
        ;If original position(pointer) was &lt; 26 then the result is &lt;0
        ;so use the original value which is in range 0-25
        btfsc   InputRotorResult,7  ;If result is negative, original
        goto    Rotor2PositionOk   ; was &lt;26 so just use it
        ;If the original was &gt;26 it is NOW mod-26 (&lt;26).  Use that instead
        movf    InputRotorResult,w
        movwf   InputRotorPosition
Rotor2PositionOk
        ;Step 2) Transpose character via the rotor itself
        movf    InputRotorPosition,w
        call    Rotor2Forward      ;Transpose in forward direction
        movwf   Rotor2Output
        ;Step 3) Map the rotor output terminal to the correct char
        ;Subtract the offset from the output terminal in MOD-26
        movf    Rotor2Position,w
        subwf   Rotor2Output,w     ;w=Output-w
        movwf   TempRotorResult
        ;If negative, process as mod-26 by adding 26 to negative result
        btfss   TempRotorResult,7
        goto    Rotor2OutputMappedOk
        addlw   .26                ;e.g. 0xFF(-1)+.26=.25
        movwf   TempRotorResult
Rotor2OutputMappedOk
        ;DONE! Input char is mapped by rotor and rotor position
        movf    TempRotorResult,w

;ROTOR 3 FORWARD
		  ;Step 1) Map the INPUT char to the rotor input terminal
        ;Add Offset (Rotor3Position) to the input in Mod-26
        addwf   Rotor3Position,w
        movwf   InputRotorPosition  ;Save result
		  movlw   .26
		  subwf   InputRotorPosition,w
        movwf   InputRotorResult
        ;If original position(pointer) was &lt; 26 then the result is &lt;0
        ;so use the original value which is in range 0-25
        btfsc   InputRotorResult,7  ;If result is negative, original
        goto    Rotor3PositionOk   ; was &lt;26 so just use it
        ;If the original was &gt;26 it is NOW mod-26 (&lt;26).  Use that instead
        movf    InputRotorResult,w
        movwf   InputRotorPosition
Rotor3PositionOk
        ;Step 2) Transpose character via the rotor itself
        movf    InputRotorPosition,w
        call    Rotor3Forward      ;Transpose in forward direction
        movwf   Rotor3Output
        ;Step 3) Map the rotor output terminal to the correct char
        ;Subtract the offset from the output terminal in MOD-26
        movf    Rotor3Position,w
        subwf   Rotor3Output,w     ;w=Output-w
        movwf   TempRotorResult
        ;If negative, process as mod-26 by adding 26 to negative result
        btfss   TempRotorResult,7
        goto    Rotor3OutputMappedOk
        addlw   .26                ;e.g. 0xFF(-1)+.26=.25
        movwf   TempRotorResult
Rotor3OutputMappedOk
        ;DONE! Input char is mapped by rotor and rotor position
        movf    TempRotorResult,w

;REFLECT enciphered code back into the rotors for reverse pass
        call    Reflector

;ROTOR 3 REVERSE
        ;Same process as used for forward except reverse transpose table
		  ;Step 1) Map the INPUT char to the rotor output terminal
        ;Add Offset (Rotor3Position) to the input in Mod-26
        addwf   Rotor3Position,w
        movwf   InputRotorPosition  ;Save result
		  movlw   .26
		  subwf   InputRotorPosition,w
        movwf   InputRotorResult
        ;If original position(pointer) was &lt; 26 then the result is &lt;0
        ;so use the original value which is in range 0-25
        btfsc   InputRotorResult,7  ;If result is negative, original
        goto    Rotor3RevPositionOk   ; was &lt;26 so just use it
        ;If the original was &gt;26 it is NOW mod-26 (&lt;26).  Use that instead
        movf    InputRotorResult,w
        movwf   InputRotorPosition
Rotor3RevPositionOk
        ;Step 2) Transpose character via the rotor itself
        movf    InputRotorPosition,w
        call    Rotor3Reverse      ;Transpose in reverse direction
        movwf   Rotor3Output
        ;Step 3) Map the rotor input terminal to the correct char
        ;Subtract the offset from the output terminal in MOD-26
        movf    Rotor3Position,w
        subwf   Rotor3Output,w     ;w=Output-w
        movwf   TempRotorResult
        ;If negative, process as mod-26 by adding 26 to negative result
        btfss   TempRotorResult,7
        goto    Rotor3RevOutputMappedOk
        addlw   .26                ;e.g. 0xFF(-1)+.26=.25
        movwf   TempRotorResult
Rotor3RevOutputMappedOk
        ;DONE! Input char is mapped by rotor and rotor position
        movf    TempRotorResult,w

;ROTOR 2 REVERSE
        ;Same process as used for forward except reverse transpose table
		  ;Step 1) Map the INPUT char to the rotor output terminal
        ;Add Offset (Rotor2Position) to the input in Mod-26
        addwf   Rotor2Position,w
        movwf   InputRotorPosition  ;Save result
		  movlw   .26
		  subwf   InputRotorPosition,w
        movwf   InputRotorResult
        ;If original position(pointer) was &lt; 26 then the result is &lt;0
        ;so use the original value which is in range 0-25
        btfsc   InputRotorResult,7  ;If result is negative, original
        goto    Rotor2RevPositionOk   ; was &lt;26 so just use it
        ;If the original was &gt;26 it is NOW mod-26 (&lt;26).  Use that instead
        movf    InputRotorResult,w
        movwf   InputRotorPosition
Rotor2RevPositionOk
        ;Step 2) Transpose character via the rotor itself
        movf    InputRotorPosition,w
        call    Rotor2Reverse      ;Transpose in reverse direction
        movwf   Rotor2Output
        ;Step 3) Map the rotor input terminal to the correct char
        ;Subtract the offset from the output terminal in MOD-26
        movf    Rotor2Position,w
        subwf   Rotor2Output,w     ;w=Output-w
        movwf   TempRotorResult
        ;If negative, process as mod-26 by adding 26 to negative result
        btfss   TempRotorResult,7
        goto    Rotor2RevOutputMappedOk
        addlw   .26                ;e.g. 0xFF(-1)+.26=.25
        movwf   TempRotorResult
Rotor2RevOutputMappedOk
        ;DONE! Input char is mapped by rotor and rotor position
        movf    TempRotorResult,w

;ROTOR 1 REVERSE
        ;Same process as used for forward except reverse transpose table
		  ;Step 1) Map the INPUT char to the rotor output terminal
        ;Add Offset (Rotor1Position) to the input in Mod-26
        addwf   Rotor1Position,w
        movwf   InputRotorPosition  ;Save result
		  movlw   .26
		  subwf   InputRotorPosition,w
        movwf   InputRotorResult
        ;If original position(pointer) was &lt; 26 then the result is &lt;0
        ;so use the original value which is in range 0-25
        btfsc   InputRotorResult,7  ;If result is negative, original
        goto    Rotor1RevPositionOk   ; was &lt;26 so just use it
        ;If the original was &gt;26 it is NOW mod-26 (&lt;26).  Use that instead
        movf    InputRotorResult,w
        movwf   InputRotorPosition
Rotor1RevPositionOk
        ;Step 2) Transpose character via the rotor itself
        movf    InputRotorPosition,w
        call    Rotor1Reverse      ;Transpose in reverse direction
        movwf   Rotor1Output
        ;Step 3) Map the rotor input terminal to the correct char
        ;Subtract the offset from the output terminal in MOD-26
        movf    Rotor1Position,w
        subwf   Rotor1Output,w     ;w=Output-w
        movwf   TempRotorResult
        ;If negative, process as mod-26 by adding 26 to negative result
        btfss   TempRotorResult,7
        goto    Rotor1RevOutputMappedOk
        addlw   .26                ;e.g. 0xFF(-1)+.26=.25
        movwf   TempRotorResult
Rotor1RevOutputMappedOk
        ;DONE! Input char is mapped by rotor and rotor position
        movf    TempRotorResult,w

        ;Output ciphertext to Port A.  Ready indication at start of loop
        movwf   PORTA

        ;INCREMENT rotors like an odometer on MOD 26
        incf    Rotor1Position,f
        movf    Rotor1Position,w
        sublw   .26                     ;Check if Pointer &gt; 25
        btfss   STATUS,Z
        goto    Rotor1PositionIncOk

        clrf    Rotor1Position
        incf    Rotor2Position,f
        movf    Rotor2Position,w
        sublw   .26                     ;Check if Pointer &gt; 25
        btfss   STATUS,Z
        goto    Rotor2PositionIncOk

        clrf    Rotor2Position
        incf    Rotor3Position,f
        movf    Rotor3Position,w
        sublw   .26                     ;Check if Pointer &gt; 25
        btfss   STATUS,Z
        goto    Rotor3PositionIncOk

        clrf    Rotor3Position

Rotor3PositionIncOk
Rotor2PositionIncOk
Rotor1PositionIncOk
        goto    loop

       END


