tk.c

// Tested 2014 on ATtiny85, works
#include <avr/io.h>
#include <util/delay.h>

// half of the low byte of the jump address to phaseA or phaseB
#define A 0x10
#define B 0x40
// static unsigned char bigdata[] = {A, B, B, A, A, B, 0};
static unsigned char bigdata[] =  {
    // The first bit is always A, and is shown here (as a comment) for
    // convenience but is not acutally ouput from this array.
    // 30 bits: synchronization sequence.
    /*A,*/ A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
    A, A, A, A, A,
    // 22 bits: const
    B, A, A, A, A, A, B, B, B, A, A, B, B, A, A, A, A, B, A, B, B, A,

    // 33 bits: user key (the only part where cards differ)
    // BEGIN CODE
    A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
    A, A, A, A, A, A, A, A,
    // END CODE

    // 139 bits: const
    A, B, A, B, B, A, A, A, B, A, B, A, B, B, A, B, A, B, A, A, A, A, A, B, B,
    A, A, B, A, B, B, B, A, A, A, B, A, B, B, A, B, B, B, A, A, B, B, A, A, A,
    B, B, A, B, A, B, A, B, A, B, B, B, A, B, A, B, B, B, B, A, A, B, A, A, B,
    A, A, A, B, A, A, A, B, A, A, B, B, B, A, B, B, B, B, A, B, B, A, A, B, A,
    B, B, B, A, A, B, B, B, A, B, B, A, A, B, A, A, A, B, A, B, A, A, B, B, A,
    A, B, B, B, B, B, A, A, A, B, B, B, B, B,
    0}; // rewind to the beginning of sequence, output A (the one that is commented out)
#undef A
#undef B
 
int main(void) {
    unsigned char temp1=0, temp2=0x18;
    unsigned char* data = bigdata;
    asm volatile(""
        ".balign 0x100,,\n\t"
        "rewind:\n\t"
            "; Y = {r29, r28} will be a pointer into the bigdata buffer\n\t"
            "movw r28, %0\n\t"             // 1 cycle
            "; Z = {r31, r30} will be used to jump to phaseA or phaseB based on bigdata[i]\n\t"
            "ldi r31, hi8(pm(phaseA))\n\t" // 1 cycle
            "; ldi r30, lo8(pm(phaseA)) ; will be done by phaseSel\n\t"
            "rjmp phaseA+8\n\t"            // 2 cycles
        "\n"
        ".balign 0x20,,\n\t"
        "phaseA:\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n"
        "phaseAsel:\n\t"
            "ld  r30, Y+\n\t"
            "ijmp\n\t"
        "\n"
        ".balign 0x80,,\n\t"
        "phaseB:\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n\t"
            "out    0x17, %2\n\t"
            "out    0x17, %1\n"
        "phaseBsel:\n\t"
            "ld  r30, Y+\n\t"
            "ijmp\n\t"
        : 
        : "e" (data), "r" (temp1), "r" (temp2)
        : "r28", "r29", "r30", "r31"
    );
    return 0;
}

Makefile

OBJECTS    = tk.o
DEVICE     = attiny85
CLOCK      = 125000

PROGRAMMER = -c avrisp -P /dev/ttyACM0 -v -v -v -F -b 19200
#PROGRAMMER = -c usbtiny -v -F -b 19200
AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE)
COMPILE = avr-gcc -Wall -Os -Iusbdrv -DF_CPU=$(CLOCK) -mmcu=$(DEVICE)
 
main.hex: Makefile main.elf
    rm -f main.hex
    avr-objcopy -j .text -j .data -O ihex main.elf main.hex

main.elf: Makefile $(OBJECTS)
    $(COMPILE) -o main.elf $(OBJECTS)

simulate: main.hex
    echo "avr-gdb main.elf -ex 'target remote :1234' -ex 'layout asm'"
    simavr -g -m attiny85 -f 8000000 -ff main.hex

size: main.elf
    avr-size --format=avr --mcu=$(DEVICE) main.elf

install: main.hex
    $(AVRDUDE) -U flash:w:main.hex:i
 
fuse:
    # fuse bit calculator: http://www.engbedded.com/fusecalc/
    # $(AVRDUDE) -U lfuse:w:0x62:m # original clock
    $(AVRDUDE) -U lfuse:w:0xc0:m # external clock for rfid emulation
 
.c.o:
    $(COMPILE) -c $< -o $@
 
.S.o:
    $(COMPILE) -x assembler-with-cpp -c $< -o $@

pub: tk.c codes-replace.c
    ./pub.sh

clean:
    rm -f main.hex main.elf $(OBJECTS) *~ tk.S
 
# If you have an EEPROM section, you must also create a hex file for the
# EEPROM and add it to the "flash" target.