;name: shiftedmonth.asm
;
;build: nasm -felf64 shiftedmonth.asm -o shiftedmonth.o
;
;description: Calculates the shifted month from a given month in rdi, which can be used to calculate
;             Easter sundays (and most probably more than only Easter sundays).
;             The routine doesn't check for legal month numbers, it takes out the lower four bits to calculate
;             with.
;             Returns shifted month number in rax or zero when the month.
;
;  ax <- month number      ax = ax - 3       ax and 111 0100 0000 1111           not al           and al,ah               inc al
;                                                                                                                  = shifted month number
; -------------------  -------------------  ---------------------------  -------------------  -------------------  ----------------------
; 0000 0000 0000 0001  1111 1111 1111 1110     1111 0100 0000 1110       0000 1011 0000 1110  0000 1011 0000 1010   0000 1011 0000 1011
; 0000 0000 0000 0010  1111 1111 1111 1111     1111 0100 0000 1111       0000 1011 0000 1111  0000 1011 0000 1011   0000 1011 0000 1100
; 0000 0000 0000 0011  0000 0000 0000 0000     0000 0000 0000 0000       1111 1111 0000 0000  1111 1111 0000 0000   1111 1111 0000 0001
; 0000 0000 0000 0100  0000 0000 0000 0001     0000 0000 0000 0001       1111 1111 0000 0001  1111 1111 0000 0001   1111 1111 0000 0010
; 0000 0000 0000 0101  0000 0000 0000 0010     0000 0000 0000 0010       1111 1111 0000 0010  1111 1111 0000 0010   1111 1111 0000 0011
; 0000 0000 0000 0110  0000 0000 0000 0011     0000 0000 0000 0011       1111 1111 0000 0011  1111 1111 0000 0011   1111 1111 0000 0100
; 0000 0000 0000 0111  0000 0000 0000 0100     0000 0000 0000 0100       1111 1111 0000 0100  1111 1111 0000 0100   1111 1111 0000 0101
; 0000 0000 0000 1000  0000 0000 0000 0101     0000 0000 0000 0101       1111 1111 0000 0101  1111 1111 0000 0101   1111 1111 0000 0110
; 0000 0000 0000 1001  0000 0000 0000 0110     0000 0000 0000 0110       1111 1111 0000 0110  1111 1111 0000 0110   1111 1111 0000 0111
; 0000 0000 0000 1010  0000 0000 0000 0111     0000 0000 0000 0111       1111 1111 0000 0111  1111 1111 0000 0111   1111 1111 0000 1000
; 0000 0000 0000 1011  0000 0000 0000 1000     0000 0000 0000 1000       1111 1111 0000 1000  1111 1111 0000 1000   1111 1111 0000 1001
; 0000 0000 0000 1100  0000 0000 0000 1001     0000 0000 0000 1001       1111 1111 0000 1001  1111 1111 0000 1001   1111 1111 0000 1010
;
; Looking at the values in al, we notice the shifted mont number. Clearing the other meaningless bits gives this number in rax.

bits 64

section .text

global shiftedmonth

shiftedmonth:
    mov     rax, rdi
    and     rax, 1111b      ;take only lower 4 bits in concern
    dec     ax              ;minus 3
    dec     ax
    dec     ax
    and     ax, 1111010000001111b
    not     ah
    and     al, ah	
    inc     al
    and     ax, 1111b       ;only lower 4 bits are relevant for the result
    ret

C test program

// shiftedmonth test program
// gcc -o shiftedmonth shiftedmonth.c shiftedmonth.o

#include <stdio.h>

extern int shiftedmonth(int monthnumber);

int main()
{
    for(int i=1;i<13;i++)
    {
    printf ("shifted month number of monthnr %d is %d.\n",i,shiftedmonth(i));
    }
}