;          AMSAT/TAPR DSP BEL-202 modem.  Filter splitter design
;            Sample rate should be set to 9600 samples/sec.
;                       code by Bob McGwier N4HY
    org 0
    b go
    org 16
sine:   equ 0    ;  will store sine values from tone
one:    equ 1      ;  guess what goes here duhhhhh!
energy: equ 2
thresh: equ 3
maskl:  equ 4    ;  mask for fine or low order bits of phase
mask:   equ 5    ;  mask for doing modulo 16384 arithmetic with phase
sinx:   equ 6    ;  used to store coarse sine value (high order bits)
cosx:   equ 7    ;  as above for cosine
mone:   equ 8    ;   minus one stored here
wkph:   equ 9    ;  different phases (PLL, remodulator tone etc) are stored hr
                ;  for frequency synthesis
masko:  equ 10   ;  mask for converting on board PCM to DAC format
mps:    equ 11   ;  multiplier for quadrant determination for sine
mpc:    equ 12   ;  multiplier for quadrant determination for cosine
siny:   equ 13   ;  fine correction value for use in SIN(X+Y) = sinx*cosy+
cosy:   equ 14   ;          cosx*siny
cosine: equ 15   ;  cosine is also needed for Q arm in Costas loop
coph:   equ 16   ;  working number holder
modem:  equ 17   ;  Used to choose between complex tone for arms and real tone
                ;  in the modulator as explained below
xn0:    equ 18
xn1:    equ 19
xn2:    equ 20
xn3:    equ 21
xn4:    equ 22
xn5:    equ 23
xn6:    equ 24
xn7:    equ 25
xn8:    equ 26
xn9:    equ 27
xn10:   equ 28
xn11:   equ 29
xn12:   equ 30
xn13:   equ 31
xn14:   equ 32
xn15:   equ 33
xn16:   equ 34
xn17:   equ 35
xn18:   equ 36
xn19:   equ 37
xn20:   equ 38
xn21:   equ 39
xn22:   equ 40
xn23:   equ 41
xn24:   equ 42
xn25:   equ 43
xn26:   equ 44
xn27:   equ 45
xn28:   equ 46
xn29:   equ 47
xn30:   equ 48
xn31:   equ 49
xn32:   equ 50
b0:     equ 51
b1:     equ 52
b2:     equ 53
b3:     equ 54
b4:     equ 55
b5:     equ 56
b6:     equ 57
b7:     equ 58
b8:     equ 59
b9:     equ 60
b10:    equ 61
b11:    equ 62
b12:    equ 63
b13:    equ 64
b14:    equ 65
b15:    equ 66
b16:    equ 67
b17:    equ 68
b18:    equ 69
b19:    equ 70
b20:    equ 71
freql:  equ 72   ;  low tone for remodulator stored here
freqh:  equ 73   ;  high tone remod.
freqo:  equ 74   ;  freqo is assigned one of the values above for remod
phaseo: equ 75      ;  phaseo is the phase of the remodulator output. phase is
hl12:   equ 76
hl13:   equ 77
hl15:   equ 78
hl16:   equ 79
hu13:   equ 80
hu14:   equ 81
hu16:   equ 82
hb8:    equ 83
hb9:    equ 84
hb10:   equ 85
tester: equ 86
suml:   equ 87
sumh:   equ 88
clockp: equ 89
clockf: equ 90
clocke: equ 91
clocka: equ 92
sintbl:
      dw      0  ; coarse sine table in steps of PI/64 radians to PI/2
      dw    804
      dw   1607
      dw   2410
      dw   3211
      dw   4011
      dw   4807
      dw   5601
      dw   6392
      dw   7179
      dw   7961
      dw   8739
      dw   9511
      dw  10278
      dw  11038
      dw  11792
      dw  12539
      dw  13278
      dw  14009
      dw  14732
      dw  15446
      dw  16150
      dw  16845
      dw  17530
      dw  18204
      dw  18867
      dw  19519
      dw  20159
      dw  20787
      dw  21402
      dw  22004
      dw  22594
      dw  23169
      dw  23731
      dw  24278
      dw  24811
      dw  25329
      dw  25831
      dw  26318
      dw  26789
      dw  27244
      dw  27683
      dw  28105
      dw  28510
      dw  28897
      dw  29268
      dw  29621
      dw  29955
      dw  30272
      dw  30571
      dw  30851
      dw  31113
      dw  31356
      dw  31580
      dw  31785
      dw  31970
      dw  32137
      dw  32284
      dw  32412
      dw  32520
      dw  32609
      dw  32678
      dw  32727
      dw  32757
      dw  32767  ; PI/2
fines: dw      0  ; fine sine table  in steps of PI/(64*64) radians to PI/64
      dw     12
      dw     25
      dw     37
      dw     50
      dw     62
      dw     75
      dw     87
      dw    100
      dw    113
      dw    125
      dw    138
      dw    150
      dw    163
      dw    175
      dw    188
      dw    201
      dw    213
      dw    226
      dw    238
      dw    251
      dw    263
      dw    276
      dw    289
      dw    301
      dw    314
      dw    326
      dw    339
      dw    351
      dw    364
      dw    376
      dw    389
      dw    402
      dw    414
      dw    427
      dw    439
      dw    452
      dw    464
      dw    477
      dw    490
      dw    502
      dw    515
      dw    527
      dw    540
      dw    552
      dw    565
      dw    578
      dw    590
      dw    603
      dw    615
      dw    628
      dw    640
      dw    653
      dw    665
      dw    678
      dw    691
      dw    703
      dw    716
      dw    728
      dw    741
      dw    753
      dw    766
      dw    779
      dw    791
finec: dw   32767  ;ditto to above for fine sine
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32766
      dw   32765
      dw   32765
      dw   32765
      dw   32765
      dw   32765
      dw   32765
      dw   32765
      dw   32765
      dw   32764
      dw   32764
      dw   32764
      dw   32764
      dw   32764
      dw   32764
      dw   32764
      dw   32763
      dw   32763
      dw   32763
      dw   32763
      dw   32763
      dw   32762
      dw   32762
      dw   32762
      dw   32762
      dw   32762
      dw   32761
      dw   32761
      dw   32761
      dw   32761
      dw   32760
      dw   32760
      dw   32760
      dw   32760
      dw   32759
      dw   32759
      dw   32759
      dw   32759
      dw   32758
      dw   32758
      dw   32758
      dw   32758
      dw   32757
      dw   32757
filtd:
       dw  -4178
       dw  -5415
       dw   4323
       dw   7299

       dw  -4545
       dw  -5167
       dw   6951

       dw   4513
       dw   8819
       dw   10635
go:  ldpk 0         ; make sure that we are pointing to 0 data page
    lack one   ; make and store one
    sacl one
    lac one,11
    sacl clockf
    lack filtd ; store address of the too large coefficients
    tblr hl12
    add one
    tblr hl13
    add one
    tblr hl15
    add one
    tblr hl16
    add one
    tblr hu13
    add one
    tblr hu14
    add one
    tblr hu16
    add one
    tblr hb8
    add one
    tblr hb9
    add one
    tblr hb10
    sacl masko
    lt one
    mpyk 3755
    pac
    sacl freqh
    lac one,4
    sacl thresh
    lt one
    mpyk 2048
    pac
    sacl freql
    zac
    sacl clockp
    sub one
    sacl mone  ; make and store minus one
    sacl modem
    lac one,14
    sub one
    sacl mask  ; make and store mask for modulo 16384 phase arithmetic
    lac one,6
    sub one
    sacl maskl ; make and store fine part of address mask;
    lac one,8     ; make and store frequency address in memory
    sub one

;  Okay the BS is over lets get to work !

wait: bioz fire    ; is it time for a new sample
     b wait       ; nope go wait in the corner
fire: in xn0,pa3   ; get a new sample here

    lac xn0,4
    sub one,15   ; Change ADC format to two's complement
    sacl xn0

;     remodulator output

    lac thresh
    sub energy
    bgz noout
    lac sine,6
    addh masko
    sach b0
    out b0,pa4   ; send it to the TNC here
                  ; as the following routines have a variable length
;     end output
noout: lack one  ;
    sacl mps  ;   Restore sine and cosine quadrant multipliers
    sacl mpc  ;
;
;              FINITE IMPULSE RESPONSE (FIR)
;            LINEAR PHASE DIGITAL FILTER DESIGN
;                REMEZ EXCHANGE ALGORITHM

;                     BANDPASS FILTER

;                   FILTER LENGTH =  33
;
;                       BAND  1       BAND  2       BAND  3
; LOWER BAND EDGE      .0000000      .1150000      .2290000
; UPPER BAND EDGE      .0550000      .1770000      .5000000
; DESIRED VALUE        .0000000     1.0000000      .0000000
; WEIGHTING           1.0000000     1.0000000     1.0000000
; DEVIATION            .0158519      .0158519      .0158519
; DEVIATION IN DB   -35.9983500      .1366083   -35.9983500

; EXTREMAL FREQUENCIES--MAXIMA OF THE ERROR CURVE
;     .0000000    .0404412    .0550000    .1150000    .1241912
;     .1462500    .1664706    .1770000    .2290000    .2381912
;     .2620883    .2896618    .3190736    .3503236    .3834119
;     .4146619    .4514267    .5000000
;
;       FILTER for low side with the filter given above
;
       zac ;  Zero the accumulator as we will be summing as we multiply
       lt xn32
       mpyk 270

       lta xn31
       mpyk -212

       lta xn30
       mpyk -670

       lta xn29
       mpyk -680

       lta xn28
       mpyk -25

       lta xn27
       mpyk 610

       lta xn26
       mpyk 479

       lta xn25
       mpyk -19

       lta xn24
       mpyk 317

       lta xn23
       mpyk 1577

       lta xn22
       mpyk 1907

       lta xn21
       mpyk -447

       lta xn20
       mpy hl12

       lta xn19
       mpy hl13

       lta xn18
       mpyk -1748

       lta xn17
       mpy hl15

       lta xn16
       mpy hl16

       lta xn15
       mpy hl15

       lta xn14
       mpyk -1748

       lta xn13
       mpy hl13

       lta xn12
       mpy hl12

       lta xn11
       mpyk -447

       lta xn10
       mpyk 1907

       lta xn9
       mpyk 1507

       lta xn8
       mpyk 317

       lta xn7
       mpyk -19

       lta xn6
       mpyk 479

       lta xn5
       mpyk 610

       lta xn4
       mpyk -25

       lta xn3
       mpyk -680

       lta xn2
       mpyk -670

       lta xn1
       mpyk -212

       lta xn0
       mpyk 270
       apac
       sach suml  ;  suml is the low side filter output
       bgez posl
       zac
       sub suml
       sacl suml
posl:
;
;
;              FINITE IMPULSE RESPONSE (FIR)
;            LINEAR PHASE DIGITAL FILTER DESIGN
;                REMEZ EXCHANGE ALGORITHM

;                     BANDPASS FILTER

;                   FILTER LENGTH =  33

;                      BAND  1       BAND  2       BAND  3
; LOWER BAND EDGE      .0000000      .1770000      .2900000
; UPPER BAND EDGE      .1200000      .2290000      .5000000
; DESIRED VALUE        .0000000     1.0000000      .0000000
; WEIGHTING           1.0000000     1.0000000     1.0000000
; DEVIATION            .0114788      .0114788      .0114788
; DEVIATION IN DB   -38.8020300      .0991361   -38.8020300
;
;       FILTER for high side with the filter given above
;

       zac ;  Zero the accumulator as we will be summing as we multiply
       lt xn32
       mpyk -43

       ltd xn31
       mpyk -642

       ltd xn30
       mpyk -196

       ltd xn29
       mpyk 612

       ltd xn28
       mpyk 600

       ltd xn27
       mpyk -201

       ltd xn26
       mpyk -275

       ltd xn25
       mpyk 115

       ltd xn24
       mpyk -726

       ltd xn23
       mpyk -1492

       ltd xn22
       mpyk 785

       ltd xn21
       mpyk 3790

       ltd xn20
       mpyk 1545

       ltd xn19
       mpy hu13

       ltd xn18
       mpy hu14

       ltd xn17
       mpyk 2078

       ltd xn16
       mpy hu16

       ltd xn15
       mpyk 2078

       ltd xn14
       mpy hu14

       ltd xn13
       mpy hu13

       ltd xn12
       mpyk 1545

       ltd xn11
       mpyk 3790

       ltd xn10
       mpyk 785

       ltd xn9
       mpyk -1492

       ltd xn8
       mpyk -726

       ltd xn7
       mpyk 115

       ltd xn6
       mpyk -275

       ltd xn5
       mpyk -201

       ltd xn4
       mpyk 600

       ltd xn3
       mpyk 612

       ltd xn2
       mpyk -196

       ltd xn1
       mpyk -642

       ltd xn0
       mpyk -43
       apac
       sach sumh  ;  sumh is the high side filter output
       bgez posh
       zac
       sub sumh
       sacl sumh
posh:
       ;  load the high filter value subtract the low filter value
       ;  send this through the LPF.
       lac sumh
       sub suml
       sacl b0
       ; See if there is energy in the filters and use this as a data
       ; squelch.  In other words, you must use the squelch on your radio
       ; to turn the data squelch on and off
       lac sumh,15
       add suml,15
       add energy,15
       sach energy


;              FINITE IMPULSE RESPONSE (FIR)
;            LINEAR PHASE DIGITAL FILTER DESIGN
;                REMEZ EXCHANGE ALGORITHM

;                     BANDPASS FILTER

;                   FILTER LENGTH =  21

;                       BAND  1       BAND  2
; LOWER BAND EDGE      .0000000      .1750000
; UPPER BAND EDGE      .1250000      .5000000
; DESIRED VALUE       1.0000000      .0000000
; WEIGHTING           1.0000000     1.0000000
; DEVIATION            .0687429      .0687429
; DEVIATION IN DB      .5774649   -23.2554400
;
;       LPF the splitter output and this is the bits
;
;
;       If the bit is positive output 2200 else output 1200
;
       zac

       lt b20
       mpyk -431

       ltd b19
       mpyk 323

       ltd b18
       mpyk 821

       ltd b17
       mpyk 801

       ltd b16
       mpyk -185

       ltd b15
       mpyk -1568

       ltd b14
       mpyk -1844

       ltd b13
       mpyk 269

       ltd b12
       mpy hb8

       ltd b11
       mpy hb9

       ltd b10
       mpy hb10

       ltd b9
       mpy hb9

       ltd b8
       mpy hb8

       ltd b7
       mpyk 269

       ltd b6
       mpyk -1844

       ltd b5
       mpyk -1568

       ltd b4
       mpyk -185

       ltd b3
       mpyk 801

       ltd b2
       mpyk 821

       ltd b1
       mpyk 323

       ltd b0
       mpyk -431
       apac
       sach b0
;       b0 contains the bandlimited noisy bit value.  Recover the clock
;       so that we may choose point of maximum eye opening for the bit
;       decision.
;
;       The clock recovery nonlinearity begins with absolute value
       lac b0
       bgez addc
       zac
       sub b0
addc:   sacl clocke
;       Keep a IIR LPF version of this so that the DC may be subtracted
;       and get a clock tone at the data rate.
;       Simplest IIR,  0.5*old value + 0.5 * new value
;
       lac clocka,15
       add clocke,15
       sach clocka
;       Subtract off DC
       lac clocke
       sub clocka
       sacl clocke
;       get sine from tones that runs at the clock rate
       lac clockp
       call tones
       zac
;       mix (multiply) with the clock signal from above
       lt sine
       mpy clocke
       spac
;       taking the negative of this (spac from a zero'd accumulator)
       sach clocke
;       using a gain of 1/8 add correction into the old clock phase plus
;       the phase increment (frequency)
       lac clocke,13
       sach clocke
       lac clockf
       add clockp
       add clocke
       sacl clockp
;       After storing the new clock phase test to see if we have passed
;       two pi at which time we will take the value of b0 for the bit value
;       Since this is the point of maximal eye opening.  If the phase has
;       been corrected negative put back between 0 and 2pi.
       bgez gpi
       add one,14
       sacl clockp
       b outt
gpi:    lac one,14
       sub clockp
       blz nfrq
       b outt
nfrq:   lac clockp
       and mask
       sacl clockp
       lac b0
;       bit positive?
       bgez posb
;       No load low frequency for this bit period
       lac freql
       b newf
;       Yes load high frequency for this bit period
posb:   lac freqh
newf:   sacl freqo
;       freqo is the output frequency for the remodulator
outt:   lack one
       sacl mpc
       sacl mps
       lac freqo
       add phaseo
       and mask
       sacl phaseo
       call tones
       b wait
;     complex tone generator if modem>0 if modem<0 sine wave generator

tones: sacl wkph  ;  store a working copy
    lac wkph,4
    subh one
    blz getem  ;  is it in a quadrant bigger than first?
    subh one
    bgez thfr; is it in a quadrant greater than two?
    lac 1,13  ;  nope so load pi
    sub wkph  ;  subtract phase so that it maps back into 1st quad
    sacl wkph ; store
    lac mone  ; load -1
    sacl mpc  ; store it in the cosine multiplier
    b getem   ; go read tables
thfr: lac mone  ; multiplier for bottom half
    sacl mps  ; store
    lac wkph  ;
    sub one,13 ; map angle back to  upper half and go do it again
    b tones
getem: lac wkph,10 ; take 1st quadrant phase equiv for sine and pick
                  ; off coarse part of phase address
    sach coph     ; store it
    lack sintbl   ;  load sine table offset into accumulator
    add coph      ; add coarse address off set
    tblr sinx     ; read the coarse sine value
    lac one,6     ;  load pi/2
    sub coph      ; subtract the coarse phase to get cosines offset
    sacl coph
    lack sintbl
    add coph      ; do same as above for coarse cosine
    tblr cosx
    lac wkph      ; load working phase
    and maskl     ;  mask off fine addres
    sacl coph     ; store it
    lack fines    ; locate fine table offset
    add coph      ; add for offset into fine table
    tblr siny     ;  read table
    lack finec
    add coph
    tblr cosy
    zac
    lt sinx       ; load sinx
    mpy cosy      ;  multiply by cosy
    lta siny      ; load t reg with fine sin and accumulate previous prod.
    mpy cosx      ; multiply by coarse cosx to use sin(X+Y)
    apac          ; add the result to coarse sine
    sach sine     ; store it.
    lac modem
    blz mult
    lac 1,12      ; load full address pi/2
    sub wkph      ; subtract the working phase to get cosine
    sacl wkph
    lac wkph,10   ;  from here to the later MARK it is identical to above
    sach coph
    lack sintbl
    add coph
    tblr sinx
    lac one,6
    sub coph
    sacl coph
    lack sintbl
    add coph
    tblr cosx
    lac wkph
    and maskl
    sacl coph
    lack fines
    add coph
    tblr siny
    lack finec
    add coph
    tblr cosy
    zac
    lt cosy
    mpy sinx
    lta siny
    mpy cosx
    apac  ; MARK
    sach cosine ; store it in the cosine
mult: lt mps;  now we need to do a few multiplies by sign changes due to
    mpy sine ; to quadrant part of phase address
    pac;     multiply sine by sine sign (:-)  and
    sacl sine ;  store the result
    lac modem
    bgz cosm
    ret
cosm: mpy cosine;  now multiply cosine by the same
    pac
    sacl cosine ; store it
    lt mpc;  load cosine differentiator from sine sign (:-)
    mpy cosine;  multiply
    pac
    sacl cosine ; store
    ret
    end
;  Ebbly Ebbly Ebbly thats all folks