USBasp/firmware/tpi.S

259 lines
4.6 KiB
ArmAsm

/**
* \brief Size-optimized code for TPI
* \file tpi.s
* \author S³awomir Fraœ
*/
#include <avr/io.h>
#include "tpi_defs.h"
#define TPI_CLK_PORT PORTB
#define TPI_CLK_DDR DDRB
#define TPI_CLK_BIT 5
#define TPI_DATAOUT_PORT PORTB
#define TPI_DATAOUT_DDR DDRB
#define TPI_DATAOUT_BIT 3
#ifdef TPI_WITH_OPTO
# define TPI_DATAIN_PIN PINB
# define TPI_DATAIN_DDR DDRB
# define TPI_DATAIN_BIT 4
#else
# define TPI_DATAIN_PIN PINB
# define TPI_DATAIN_BIT 3
#endif
.comm tpi_dly_cnt, 2
/**
* TPI init
*/
.global tpi_init
tpi_init:
/* CLK <= out */
sbi _SFR_IO_ADDR(TPI_CLK_DDR), TPI_CLK_BIT
#ifdef TPI_WITH_OPTO
/* DATAIN <= pull-up */
cbi _SFR_IO_ADDR(TPI_DATAIN_DDR), TPI_DATAIN_BIT
sbi _SFR_IO_ADDR(TPI_DATAIN_PORT), TPI_DATAIN_BIT
/* DATAOUT <= high */
sbi _SFR_IO_ADDR(TPI_DATAOUT_DDR), TPI_DATAOUT_BIT
sbi _SFR_IO_ADDR(TPI_DATAOUT_PORT), TPI_DATAOUT_BIT
#else
/* DATA <= pull-up */
cbi _SFR_IO_ADDR(TPI_DATAOUT_DDR), TPI_DATAOUT_BIT
sbi _SFR_IO_ADDR(TPI_DATAOUT_PORT), TPI_DATAOUT_BIT
#endif
/* 32 bits */
ldi r21, 32
1:
rcall tpi_bit_h
dec r21
brne 1b
ret
/**
* Update PR
* in: r25:r24 <= PR
* lost: r18-r21,r24,r30-r31
*/
tpi_pr_update:
movw r20, r24
ldi r24, TPI_OP_SSTPR(0)
rcall tpi_send_byte
mov r24, r20
rcall tpi_send_byte
ldi r24, TPI_OP_SSTPR(1)
rcall tpi_send_byte
mov r24, r21
// rjmp tpi_send_byte
/**
* Send one byte
* in: r24 <= byte
* lost: r18-r19,r30-r31
*/
.global tpi_send_byte
tpi_send_byte:
/* start bit */
rcall tpi_bit_l
/* 8 data bits */
ldi r18, 8
ldi r19, 0
1:
// parity
eor r19, r24
// get bit, shift
bst r24, 0
lsr r24
// send
rcall tpi_bit
dec r18
brne 1b
/* parity bit */
bst r19, 0
rcall tpi_bit
/* 2 stop bits */
rcall tpi_bit_h
// rjmp tpi_bit_h
/**
* Exchange of one bit
* in: T <= bit_in
* out: T => bit_out
* lost: r30-r31
*/
tpi_bit_h:
set
tpi_bit:
/* TPIDATA = T */
#ifdef TPI_WITH_OPTO
// DATAOUT = high (opto should allow TPIDATA to be pulled low by external device)
// if(T == 0)
// DATAOUT = low
sbi _SFR_IO_ADDR(TPI_DATAOUT_PORT), TPI_DATAOUT_BIT
brts 1f
tpi_bit_l:
cbi _SFR_IO_ADDR(TPI_DATAOUT_PORT), TPI_DATAOUT_BIT
1:
#else
// DATAOUT = pull-up
// if(T == 0)
// DATAOUT = low
cbi _SFR_IO_ADDR(TPI_DATAOUT_DDR), TPI_DATAOUT_BIT
sbi _SFR_IO_ADDR(TPI_DATAOUT_PORT), TPI_DATAOUT_BIT
brts 1f
tpi_bit_l:
cbi _SFR_IO_ADDR(TPI_DATAOUT_PORT), TPI_DATAOUT_BIT
sbi _SFR_IO_ADDR(TPI_DATAOUT_DDR), TPI_DATAOUT_BIT
1:
#endif
/* delay(); */
lds r30, tpi_dly_cnt
lds r31, tpi_dly_cnt+1
1:
sbiw r30, 1
brsh 1b
/* TPICLK = 1 */
sbi _SFR_IO_ADDR(TPI_CLK_PORT), TPI_CLK_BIT
/* T = TPIDATA */
in r30, _SFR_IO_ADDR(TPI_DATAIN_PIN)
bst r30, TPI_DATAIN_BIT
/* delay(); */
lds r30, tpi_dly_cnt
lds r31, tpi_dly_cnt+1
1:
sbiw r30, 1
brsh 1b
/* TPICLK = 0 */
cbi _SFR_IO_ADDR(TPI_CLK_PORT), TPI_CLK_BIT
ret
/**
* Receive one byte
* out: r24 => byte
* lost: r18-r19,r30-r31
*/
.global tpi_recv_byte
tpi_recv_byte:
/* waitfor(start_bit, 192); */
ldi r18, 192
1:
rcall tpi_bit_h
brtc .tpi_recv_found_start
dec r18
brne 1b
/* no start bit: set return value */
.tpi_break_ret0:
ldi r24, 0
/* send 2 breaks (24++ bits) */
ldi r18, 26
1:
rcall tpi_bit_l
dec r18
brne 1b
/* send hi */
rjmp tpi_bit_h
// ----
.tpi_recv_found_start:
/* recv 8bits(+calc.parity) */
ldi r18, 8
ldi r19, 0
1:
rcall tpi_bit_h
lsr r24
bld r24, 7
eor r19, r24
dec r18
brne 1b
/* recv parity */
rcall tpi_bit_h
bld r18, 7
eor r19, r18
brmi .tpi_break_ret0
/* recv stop bits */
rcall tpi_bit_h
rjmp tpi_bit_h
/**
* Read Block
*/
.global tpi_read_block
tpi_read_block:
// X <= dptr
movw XL, r22
// r23 <= len
mov r23, r20
/* set PR */
rcall tpi_pr_update
/* read data */
.tpi_read_loop:
ldi r24, TPI_OP_SLD_INC
rcall tpi_send_byte
rcall tpi_recv_byte
st X+, r24
dec r23
brne .tpi_read_loop
ret
/**
* Write block
*/
.global tpi_write_block
tpi_write_block:
// X <= sptr
movw XL, r22
// r23 <= len
mov r23, r20
/* set PR */
rcall tpi_pr_update
/* write data */
.tpi_write_loop:
ldi r24, TPI_OP_SOUT(NVMCMD)
rcall tpi_send_byte
ldi r24, NVMCMD_WORD_WRITE
rcall tpi_send_byte
ldi r24, TPI_OP_SST_INC
rcall tpi_send_byte
ld r24, X+
rcall tpi_send_byte
.tpi_nvmbsy_wait:
ldi r24, TPI_OP_SIN(NVMCSR)
rcall tpi_send_byte
rcall tpi_recv_byte
andi r24, NVMCSR_BSY
brne .tpi_nvmbsy_wait
dec r23
brne .tpi_write_loop
ret