Assembly code is somewhere I don't want to go. It is a nightmare and the algorithm I'm handling sometimes fries my head.
Back in 1998 I did program a receiver-transmitter for a Direct Sequence Spread spectrum modulation in a TM3240C54x. I happen to have found the code of it. There is the taylor series for cos(x), sin(x), cos(4x), sin(4x), I used since theres is not enough memory for a look-up table and if you use 8-bits for that, the noise is too high for the demod operations.
The receiver used a complex I-Q demodulating loop
.title "Receptor DS-SS"
.mmregs ;memory mapped registers
.setsect ".text", 0x200,0 ;Inicio del codigo ejecutable
.setsect "vectors", 0x180,0 ;Inicio del espacio para vectores
.setsect ".data", 0x2000,0
;-----definiciÛn de constantes
flag_rcv .set 0x0001 ; flag que se§aliza la recepci¢n de un dato
kv .set 0x0002 ; constante del VCO
phi .set 0x4F35 ; frecuencia discreta central del VCO
; phi=2*pi*fc*Ts (1.4Khz)
n_taps .set 15 ; numero de taps del filtro paso bajo del lazo
buff_length .set 15*9 ; longitud del buffer para el c¢digo PN
; usado en la rutina acq.
umbral_iq .set 17100 ; umbral para la rutina acq.
.copy "const.dat" ; Copia la secciÛn de constantes.
.sect "vectors"
.copy "vectors1.asm"
;-----inicio del programa principal
.text ; secciÛn de programa
start:
intm=1 ; no permito interrupciones.
call AC01INIT ; configura el conversor A/D.
pmst = #01a0h ; processor mode status register
sp = #27fah ; init stack pointer
imr = #240h ; unmask TDM RINT and HPIINT(host port interface)
intm = 0 ; globally enable all interrupts
sxm = 1 ; ExtensiÛn de signo activada.
*(flags)=#0
AR0 = #1 ; importante para las instrucciones MAC.
inicio TC=bitf(*(flags),flag_rcv) ; barrera -> se espera hasta que
nop
if (NTC) goto inicio ; podamos procesar otro dato
*(flags) ^= #flag_rcv ; pone a cero el flag de recibido
T = *(samplerx) ; T = muestra recibida
nop
A = T * *(vcocout) ; multiplica la entrada por la salida
; del oscilador I.
*(f_data1) = hi(A) ; introduce la salida del
; multiplicador en el filtro I
T = *(samplerx)
nop
A = T * *(vcosout) ; multiplica la entrada por la salida
; del oscilador Q.
*(f_data2) = hi(A) ; introduce la salida del
; multiplicador en el filtro Q
call filtrar ; funci¢n de filtrado(I/Q)
A = *(lp1) ; Toma la salida del filtro I
*(b_2) = A ; y la introduce en buff2.
A = *(lp2) ; Toma la salida del filtro Q
*(b_3) = A ; y la introduce en buff3.
call acq1 ; rutinas que filtran con el cÛdigo PN local.
call acq2
*(update) = #0xffff ; Desactiva la seÒal de actualizaciÛn.
A = *(filt_out1) ; Suma en mÛdulo las salidas de los filtros
A = |A| ; que dan la correlaciÛn.
B = A
A = *(filt_out2)
A = |A|
A = A + B
*(i2q2) = A
A = A - #umbral_iq ; comprueba el umbral.
nop
if (ALT) goto no_update
nop
*(update) = #0x5000 ; seÒaliza la actualizaciÛn de la salida de los
; bloques acq1 y acq2.
no_update T = *(ultimo1) ; T = salida del bloque acq1.
A = T * #0x7fff
B = *(ultimo2) * hi(A)
call vco
T = *(ultimo2)
*(sampletx) = T
goto inicio
filtrar:
push(AR0) ; guarda AR0 en la pila
; filtro 1
AR0 = #f_data1_end
A = #0
repeat (#(n_taps-1))
macd(*AR0-,h0,A)
*(lp1) = hi(A)
; filtro 2
AR0 = #f_data2_end
A = #0
repeat (#(n_taps-1))
macd(*AR0-,h0,A)
*(lp2) = hi(A)
AR0 = pop() ; recupera AR0 de la pila
return_enable
vco: ;realiza la funci¢n del VCO
push(AR3)
AR3 = #vcomem
A = B << -6 ; entrada en B
T = #kv
A = T * hi(A)
A = A + #phi ; A = phi
A = A + dbl(*AR3) ;A = phi + entrada del VCO + valor de vcomem anterior
call modpi ;reduce 'A' a modulo pi
dbl(*AR3) = A ;guarda 'A' en 'vcomem'
A = A<<-2 ;desplazamiento a la derecha
;para dividir por cuatro el argumento
*(cosarg) = A
*(sinarg) = A
call coseno
call seno
AR3 = pop()
return_enable
modpi: ;reduce a modulo pi la variable 'vcomem'
push(AR1)
push(AR2)
AR1 = #dospi
AR2 = #pi
*(camsig) = #0
if (AGEQ) goto loop1
*(camsig) = #1
A = |A|
loop1 B = A
B = B - dbl(*AR2)
nop
nop
if (BLEQ) goto fin ;goto fin si -pi<= B <=pi
A = A - dbl(*AR1) ;si B esta fuera del rango resta 2*pi a 'A'.
goto loop1
fin TC= (*(camsig)==#1)
nop
nop
if (TC) execute(1) ;si cambiÈ el signo al principio,
A=-A ;volver a cambiar.
AR2=pop()
AR1=pop()
return_enable
coseno: ;calcula cos(4x) a partir de cos(x)
;Necesario ya que el argumento de la funci¢n cos() es vcomem
;dividido por 4.
call cos
A = *(cresult) * *(cresult)
A = A -#0x7fff <<16
A = T * hi(A)
nop
nop
A = T * hi(A)
A = A << -13
A = A + #0x7fff
*(vcocout) = A
return_enable
seno: ;calcula el sen(4x) a partir de sin(x).
call sin
A = #0
A = *(cresult) * *(cresult)
nop
A = A << 1
A = A - #0x7fff << 16
T = *(cresult)
A = T * hi(A)
nop
nop
T = *(sresult)
A = T * hi(A)
A = A << -14
*(vcosout) = A
return_enable
cos: ;calcula el coseno con la serie de Taylor
;argumento cosarg entre -1 rad y 1 rad.
push(AR2)
push(AR3)
push(AR4)
AR2 = #cosarg
AR3 = #c_coffs
AR4 = #C_1
A = *AR2+ * *AR2+
*AR2 = hi(A)
|| B = *AR4<<16 ;
A = B - *AR2+ * *AR3+
A = T * hi(A)
*AR2 = hi(A)
A = B - *AR2- * *AR3+
B = *AR2+ * hi(A)
*AR2 = hi(B)
|| B = *AR4<<16
A = B - *AR2- * *AR3+
A = A <<-1
A = -A
B = *AR2+ * hi(A)
B = B + *AR4 <<16
*AR2=hi(B)
AR4 = pop()
AR3 = pop()
AR2 = pop()
return_enable
sin: ; calcula en seno con la serie de Taylor
; argumento sinarg entre (-1 rad y 1 rad).
push(AR2)
push(AR3)
push(AR4)
AR2 = #sinarg
AR3 = #s_coffs
AR4 = #C_1
A = *AR2+ * *AR2+
*AR2 = hi(A)
|| B = *AR4<<16 ;
A = B - *AR2+ * *AR3+
A = T * hi(A)
*AR2 = hi(A)
A = B - *AR2- * *AR3+
B = *AR2+ * hi(A)
*AR2 = hi(B)
|| B = *AR4<<16
A = B - *AR2- * *AR3+
B = *AR2+ * hi(A)
*AR2 = hi(B)
|| B = *AR4<<16 ;
A = B - *AR2- * *AR3+
B = *(sinarg) * hi(A)
*(sresult) = hi(B)
AR4 = pop()
AR3 = pop()
AR2 = pop()
return_enable
acq1: ;rutina que correla con la secuencia PN local.
push(AR1) ;guarda en la pila AR1
AR1 = #b_2end ;retrasa las muestras de buff2
repeat(#(buff_length-1))
delay(*AR1-)
A = #0
repeat(#(buff_length-1)) ;calcula el producto de la entrada y del
;c¢digo local est·tico
macp(*AR1+, #b_1, A)
*(filt_out1) = hi(A)
A = *(update)
A = A - #0x9
nop
nop
if (ALT) goto end_acq1
nop
T = *(filt_out1)
*(ultimo1) = T
end_acq1
AR1 = pop()
return_enable
acq2: ;rutina que correla con la secuencia PN local.
push(AR1) ;guarda en la pila AR1
AR1 = #b_3end ;retrasa las muestras de buff2
repeat(#(buff_length-1))
delay(*AR1-)
A = #0
repeat(#(buff_length-1)) ;calcula el producto de la entrada y del
;cÛdigo local est·tico.
macp(*AR1+, #b_1, A)
*(filt_out2) = hi(A)
A = *(update)
nop
nop
if (ALT) goto end_acq2
T = *(filt_out2)
*(ultimo2) = T
end_acq2
AR1 = pop()
return_enable
transmit:
B=trcv
*(samplerx)=B
*(sampletx) &= #0xfffc ;elimina los bits de control.
A=*(sampletx)
tdxr=A
*(flags) |= #flag_rcv ;seÒalizar que se ha recibido un dato
return_enable
.copy "ac01ini1.asm" ;configuraciÛn del conversor A/D.
.end