Repository navigation
Expand file tree
/
Copy pathAngelia.v
More file actions
2803 lines (2281 loc) · 111 KB
/
Copy pathAngelia.v
File metadata and controls
2803 lines (2281 loc) · 111 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/***********************************************************
*
* Angelia
*
************************************************************/
//
// HPSDR - High Performance Software Defined Radio
//
// Angelia code.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// (C) Phil Harman VK6APH/VK6PH, Kirk Weedman KD7IRS 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
/* This program interfaces the LTC2208 to a PC over Ethernet.
The data from the LTC2208 is in 16 bit parallel format and
is valid at the positive edge of the LTC2208 122.88MHz clock.
The data is processed by a CORDIC NCO to produce I and Q
outputs. These are decimated by 640/1280/2560 in CIC and CFIR filters to
give output data at 192/96/48kHz to feed to the PHY and hence via
the Ethernet to a PC.
The program takes microphone/line-in samples from an ADC at 48kHz
and passed them to the PC via Ethernet. The PC process these and returns them as
I&Q signals. These are passed to CIC interpolating filters (x2560) then
to a complex input CORDIC NCO. The ouput of the CORDIC is at the required user
frequency and passed to the final DAC.
The data format over Ethenet is the same as that used my Metis.
Change log:
2 Mar 2012 - Released as V1.3
5 April - Added wide spectrum support. Set serial numbers for Penny and Mercury to zero
- Added support for second receiver - Joe Martin, K5SO
- Released as V1.4
13 April - Fixed bug in TLV320 code that muted audio when Line-in select.
- J13 in selects Apollo and out Alex
- Released as V1.5
14 April - Added user input IO8
- Released as V1.6
21 April - Added support for Alex in auto mode
- tidy LED designations
- Designated V1.7
28 April - Increased Apollo clock from 30kHz to 150kHz
5 July - Fixed sync byte error in Apollo.v and MAC address read error in EEPROM.v
- Increased wide spectrum FIFO from 4k to 16k
13 - Increased wide spectrum FIFO to 32k for testing by DL3HVH
18 - Test code for Hermes VNA, set to one receiver
In VNA mode set the Rx and Tx CORDIC phase words to be equal. Set the I input of the Tx CORDIC to
0 and the Q to 0x7FFF/1.7 to remove the CORDIC gain. Run the VNA when the PTT from the PC is active.
6 Aug - using CIC and CFIR outputs with I of Tx cordic set to 0 and Q to 0x7FFF/1.7 . See line 1307.
11 Sep - Use C&C (when C0 = 0001 001x, C2[7]]) to enable VNA mode.
15 Sep - Set wide spectrum FIFO to 16k. Enabled second receiver.
- Alex/Apollo selected via C&C rather than J13
- released as V1.7
23 Sep - changes by Joe K5SO
- Modified FilterSelect to match USB protocol document v1.42 spec for C2[5] when C0[7:1]=0001001
- Added dual-Rx automatic Alex LPF/HPF filter switching logic
- Added additional Alex LPF filter switching logic during transmit to accommodate SPLT mode operation correctly
- Modified Alex Tx RED LED operation to illuminate when transmitting
- Modified HPF/LPF automatic frequency switch-point logic
- Added manual Alex switching logic
- Added line-in gain control
- Renamed version number to V1.8
28 Oct - changes by Joe K5SO
- Added 0-31 dB step option for input attenuator
- Renamed version number to V1.9
27 Nov - added TimeQuest Hermes.sdc timing constraint file
- commented out the Apollo module
- implemented four receivers
- renamed the version number to v4.5
- reduced the number of receivers to two once again
- added back the Apollo module
- used a new TimeQuest .sdc file from Phil
- fixed bug with automatic Alex filter selection
- renamed the version number to v4.6
29 Nov - increased # of receivers to four
- modified the Alex switching code
- renamed version to v2.0
6 Dec - added 5 receivers, using Alex VE3NEA's rx modules
- modified Alex automatic switching
8 Dec - fixed bug with Rx 5 operation
14 December - modified the receiver module to yield 6 dB greater overall gain, to match Mercury rx module gain
17 Dec - Modified Rx_MAC to use a FIFO to convert from nibble to byte.
- Enabled directed ARP rather than just broadcast
30 Dec - added Alex T/R relay disable option (C&C bit C3[7] when C0=0001_001x, 0=T/R relay enabled, 1=T/R relay disabled)
- added abilty to set/read IP address without being in Bootloader mode.
- now using Quartus II V12.1
- released as v2.1
8 Jan 2013 - fixed ethernet ARP request response bug
- modified Apollo code so PTT timer works
- changed FSM from 1 Hot to User Encoded so Apollo code works.
- Changed Apollo PLL clock from 150kHz to 30kHz.
- released as v2.2
26 - Replaced FIR with Polyphase FIR. Modified variCIC to decimate from 2...40. Increased max sampling rate to 960kHz
- Reduced receivers to 4 with sampling rates of 48/96/192/384ksps.
- Added UDP/IP set IP address
10 - Modified Polyphase filter.
- Increased time out for ARP and ping
- 4 receivers with 48/96/192/384ksps.
12 - 5 receivers - 96% full
16 - released as version 2.3
2 Mar - Added ARP/Ping time out mod from Metis.
- replace pin defs ready for 1000T code - released as same version
7 May - fixed Alex 6m preamp switching bug
- reduced the Alex SPI bus speed by half to permit longer ribbon cable connections to Alex,
- assigned unused Rx freqs to the Tx freq,
- changed the 1.5MHz HPF filter switchover freq to 1416 KHz and the 80m LPF switchover freq
to 2400 KHz to accommodate "stitched" mode rx at up to 384 ksps sampling rates,
- changed version number to 2.4
27 May - temporary predistortion version - assigned Tx output to Rx5 input - changed version to v0.4
1 Nov - Move DAC data to Rx 2 for testing. Carrier +18dBm, noise floor approx -125dBm - works well.
- Replace CIC with cFIR and CIC from HiQSDR. Works OK, need to swap I&Q. 92% full.
18 Nov - Swap I&Q. OK
- Move DAC data to Rx5. All OK
20 - Try by2/by4 on Rx4 only. All OK
- Try by2/by4 on Rx5 as well. No
21 - Edit sdc file to remove frequency path. OK now
25 - Edit sdc file to set DACD outputs with -9. Not sure this is better (Warren reports OK), perhaps use posedge of clock on DACD.
26 - Use positive edge of clock on DACD and -2 in sdc file. Rx1 jumps for Warren
2 Dec - Revert to negeative edge and -9. Meets timing. Reduce gain of by4 FIR buy 7.2dB to match other FIR gain. All OK
4 - Revert By4 gain to unity and increase other FIR to unity. Reduce peak frequency error by making error symetrical.
6 - Increase cFIR to 1024 coefficients.
9 - Alternative cFIR with same gain as previously.
11 - Corrected cFIR address counter. Works OK.
12 - Test Warrens CFIR coefficients. Reduce by4 gain by 7.2dB.
13 - Testing truncation on output data of interpolating FIR. No effect.
18 - Enabled VNA features from Hermes V2.5 development and select Rx5 on Rx
**********************
27 Dec 2013 - ported Hermes design to Angelia hardware...K5SO
- increased number of receivers to 7
- added support for dual ADCs
- added support for independent attenuator control for inputs to ADC1 & ADC2
- set version number to v2.1
10 Jan 2014 - fixed intermittent hang problem by using Tx_clock in the ARP/PING Always statement (~line 900)
- set version number to v2.2
1 Feb 2014 - fixed bug with Rx2 freq assignment via common_Merc_freq bit via C&C byte stream; affected diversity ops
- changed Rx5 phase word and input source to depend upon T/R state
- changed version number to v2.5
3 Feb 2014 - modified LPF switch point to assign the 17/15m LPF on 12m
- changed version number to v2.6
6 Feb 2014 - fixed bug in ASMI module that prevented HPSDRProgrammer from working properly
- changed version number to v2.7
7 Feb 2014 - reduced the EEPROM erase time, in ASMI_interface.v, when loading firmware via ethernet connection
- changed version number to v2.8
9 Feb 2014 - added code to double buffer data to the SPI Alex bus across differing clock domains to
improve reliability in filter switching in Alex and ANAN-100D PA
- changed version number to v2.9
6 Mar 2014 - Fully constrained the firmware design with constaints in the Angelia.sdc file, added delays to meet timing on
all failing paths, timing is met 100%
- changed version number to v3.0
17 Apr 2014 - Added firmware CW sidetone and RF generation. Fixed bug in frequency phase word that caused 1/2Hz error
- constrained the firmware design, closed timing, new Angelia.sdc constraints file
- changed version number to V3.1
8 May 2014 - added Iambic keyer. Enable keying using I[1:0] mapped to dot:dash so that CWX can use the keyer.
- changed version number to V3.2
10 May 2014 - fixed bug in iambic.v
- changed version number to v3.3
27 May 2014 - Added PC control of ADC assignment to the seven receivers
when C0 = 0001_110x,
C1[1:0] = assign ADCn to RX1: 00 = ADC0, 01 = ADC1
C1[3:2] = assign ADCn to RX2: 00 = ADC0, 01 = ADC1
C1[5:4] = assign ADCn to RX3: 00 = ADC0, 01 = ADC1
C1[7:6] = assign ADCn to RX4: 00 = ADC0, 01 = ADC1
C2[1:0] = assign ADCn to RX5: 00 = ADC0, 01 = ADC1, except on Tx assign Tx DAC as input to RX5
C2[3:2] = assign ADCn to RX6: 00 = ADC0, 01 = ADC1
C2[5:4] = assign ADCn to RX7: 00 = ADC0, 01 = ADC1
Note: in the case that the ADC control bits are 11, which Orion uses to select
ADC3, ADC1 is used instead as ADC3 does not exist on Angelia.
- changed the version number to v3.4
6 Jun 2014 - Added PC control of "atten_on_Tx" via C&C bits C3[4:0] when C0 = 0001_110x
- Changed version number to v3.5
15 Jun 2014 - Added support for ADC overflow alerting for ADC2 in TXFC module
- Changed version number to v3.6
23 Jun 2014 - Fixed bug with ADC2 overflow status reporting, in TXFC module
- Changed version number to v3.7
29 Jun 2014 - Fixed bug with Ref Power reporting by adjusting "set_max_delay" path constraint as follows:
-from PLL_IF_inst|altpll_component|auto_generated|pll1|clk[0] -to LTC2208_122MHz 49
(which is 1 nanosecond longer than the 48 nSec delay the Quartus II timing wizard automatically applied)
- Changed version number to v3.8
1 Jul 2014 - Fixed Tx spur bug by increasing the delay above to 50 nSec instead, in the Angelia.sdc file as follows:
set_max_delay -from PLL_IF_inst|altpll_component|auto_generated|pll1|clk[0] -to LTC2208_122MHz 50
- Changed version number to v3.9
24 Jul 2014 - Increased timing margins on numerous paths to make the design more robust with respect to running on different
ANAN-100D radios
- Changed version number to v4.0
28 Jul 2014 - Fixed broken logic linkage between ACC-PORT external PPT input and PPT OUT which also fixed
non-break-in-CW-mode PTT operation
- Fixed Tx spurs and sporadic CW stoppage by changing internal timing
- Fixed no REV power reading on Tx
- Changed version number to v4.1
18 Aug 2014 - Adjusted timing slightly (less margin on positive slack by 2nSec) on signal paths from sidetone_clock
domain to LTC2208_122MHz domain and increased maximum setup delay by 1 nSec on signal paths from
PLL_IF_inst|altpll_component|auto_generated|pll1|clk[0] domain to
PLL_IF_inst|altpll_component|auto_generated|pll1|clk[2] domain in an effort to
cure CW sidetone stopping on some radios after 20 minutes of operation
- Changed version number to v4.2
14 Dec 2014 - Fixed intermittent PTT to Alex/PA board problems by sending Alex/PA relay data three times
via the SPI bus when the Alex data changes, ensuring positive relay control to all
Alex/PA relays
- Changed version number to v4.3
23 Dec 2014 - Changed timing to reduce noise output on Tx and cure other noise issues on some radios.
- Changed version number to v4.4
16 Jan 2015 - Changed FPGA_PTT to use a de-bounced PTT input with the other inputs.
- Changed back to sending Alex data one time on the ALEX SPI bus each time any Alex data changes.
- Changed version number to v4.5
30 Jan 2015 - Set Alex relays to off at power on.
- Merged clocking, CW generataion and I2S audio from new protocol code.
- Temp disable Apollo interface.
- Changed version number to v4.6
4 Feb 2015 - Changed DAC clock edge to posedge to test for Tx spurious
5 Feb 2015 - Clock DAC data at 90 degrees to ensure data is stable
- Replaced C122_clk_3 entries with C122_clk entries instead (C122_clk_3 is non-existent)
- Changed version number to v4.7
11 Feb 2015 - Fixed Line-In bug in mic_I2S.v
15 Feb 2015 - Changed clock phase shift from 90 degrees to 15 degrees to clock data into
the TX DAC
- Changed version number to v4.8
25 Apr 2015 - Fixed Line-In bug in TLV320_SPI.v
- Changed version number to v4.9
30 Apr 2015 - Added external CW keying capability to iambic.v module via digital input IO4
while iambic CW mode is selected (pin 9 on J16 Angelia, pin 9 rear panel accy
jack on ANAN-100D) , key to ground, unkey is +3.3VDC via pull up resistor on Angelia board,
IO4 input is debounced
- Changed version number to v5.0
10 Jun 2015 - fixed bug with Rx2 phase word assignment that caused random initial phase relationship between
Rx1 and Rx2 on powerup of Angelia in diversity mode
- Changed version number to v5.1
*** change global clock name ****
NOTES:
LEDs:
DEBUG_LED1 - Lights when an Ethernet broadcast is detected
DEBUG_LED2 - Lights when traffic to the boards MAC address is detected
DEBUG_LED3 - Lights when detect a received sequence error or ASMI is busy
DEBUG_LED4 - Displays state of PHY negotiations - fast flash if no Ethernet connection, slow flash if 100T and on if 1000T
DEBUG_LED5 - Lights when the PHY receives Ethernet traffic
DEBUG_LED6 - Lights when the PHY transmits Ethernet traffic
DEBUG_LED7 - Displays state of DHCP negotiations or static IP - on if ACK, slow flash if NAK, fast flash if time out
and long then short flash if static IP
DEBUG_LED8 - Lights when sync (0x7F7F7F) received from PC
DEBUG_LED9 - Lights when a Metis discovery packet is received
DEBUG_LED10 - Lights when a Metis discovery packet reply is sent
Status_LED - Flashes once per second
*/
//---------------------------------------------------------
// Quartus V11.1sp2 Notes
//---------------------------------------------------------
/*
In order to get this code to compile without timing errors under
Quartus V11.1sp2 I needed to use the following settings:
- Timing Analysis Settings - Use Classic
- Analysis and Synthesis Settings\Power Up Dont Care [not checked]
- Analysis and Synthesis Settings\Restructure Multiplexers [OFF]
- Analysis and Synthesis Settings\State Machine Processing = User Encoding
- Fitter Settings\Optimise fast-corner timing [ON]
- Restructure Multiplexers = OFF
- Perform Physical Synthesis for Combinational Logic for Performance = ON
- Perform Register Duplication for Performance = ON
- Perform Register Retiming for Performance = ON
*/
module Angelia(
//clock afc
input _122MHz, //122.88MHz from VCXO
input OSC_10MHZ, //10MHz reference in
output FPGA_PLL, //122.88MHz VCXO contol voltage
//attenuator (DAT-31-SP+)
output ATTN_DATA, //data for input attenuator
output ATTN_DATA_2,
output ATTN_CLK, //clock for input attenuator
output ATTN_CLK_2,
output ATTN_LE, //Latch enable for input attenuator
output ATTN_LE_2,
//rx adc (LTC2208)
input [15:0]INA, //samples from LTC2208
input [15:0]INA_2, //samples from LTC2208 #2
input LTC2208_122MHz, //122.88MHz from LTC2208_122MHz pin
input LTC2208_122MHz_2, //122.88MHz from #2 LTC2208_122MHz pin
input OVERFLOW, //high indicates LTC2208 have overflow
input OVERFLOW_2, //high indicates LTC2208 have overflow
output RAND, //high turns ramdom on
output RAND_2, //high turns ramdom on
output PGA, //high turns LTC2208 internal preamp on
output PGA_2, //high turns LTC2208 internal preamp on
output DITH, //high turns LTC2208 dither on
output DITH_2, //high turns LTC2208 dither on
output SHDN, //x shuts LTC2208 off
output SHDN_2, //x shuts LTC2208 off
//tx adc (AD9744ARU)
output reg DAC_ALC, //sets Tx DAC output level
output reg signed [13:0]DACD, //Tx DAC data bus
//audio codec (TLV320AIC23B)
output CBCLK,
output CLRCIN,
output CLRCOUT,
output CDIN,
output CMCLK, //Master Clock to TLV320
output CMODE, //sets TLV320 mode - I2C or SPI
output nCS, //chip select on TLV320
output MOSI, //SPI data for TLV320
output SSCK, //SPI clock for TLV320
input CDOUT, //Mic data from TLV320
//phy rgmii (KSZ9021RL)
output [3:0]PHY_TX,
output PHY_TX_EN, //PHY Tx enable
output PHY_TX_CLOCK, //PHY Tx data clock
input [3:0]PHY_RX,
input RX_DV, //PHY has data flag
input PHY_RX_CLOCK, //PHY Rx data clock
input PHY_CLK125, //125MHz clock from PHY PLL
input PHY_INT_N, //interrupt (n.c.)
output PHY_RESET_N,
input CLK_25MHZ, //25MHz clock (n.c.)
//phy mdio (KSZ9021RL)
inout PHY_MDIO, //data line to PHY MDIO
output PHY_MDC, //2.5MHz clock to PHY MDIO
//eeprom (25AA02E48T-I/OT)
output SCK, // clock on MAC EEPROM
output SI, // serial in on MAC EEPROM
input SO, // SO on MAC EEPROM
output CS, // CS on MAC EEPROM
//eeprom (M25P16VMW6G)
output NCONFIG, //when high causes FPGA to reload from eeprom EPCS16
//12 bit adc's (ADC78H90CIMT)
output ADCMOSI,
output ADCCLK,
input ADCMISO,
output nADCCS,
//alex/apollo spi
output SPI_SDO, //SPI data to Alex or Apollo
input SPI_SDI, //SPI data from Apollo
output SPI_SCK, //SPI clock to Alex or Apollo
output J15_5, //SPI Rx data load strobe to Alex / Apollo enable
output J15_6, //SPI Tx data load strobe to Alex / Apollo ~reset
//misc. i/o
input PTT, //PTT active low
input KEY_DOT, //dot input from J11
input KEY_DASH, //dash input from J11
output FPGA_PTT, //high turns Q4 on for PTTOUT
input MODE2, //jumper J13 on Angelia, 1 if removed
input ANT_TUNE, //atu
output IO1, //high to mute AF amp
input IO2, //PTT, used by Apollo
//user digital inputs
input IO4,
input IO5,
input IO6,
input IO8,
//user outputs
output USEROUT0,
output USEROUT1,
output USEROUT2,
output USEROUT3,
output USEROUT4,
output USEROUT5,
output USEROUT6,
//debug led's
output Status_LED,
output DEBUG_LED1,
output DEBUG_LED2,
output DEBUG_LED3,
output DEBUG_LED4,
output DEBUG_LED5,
output DEBUG_LED6,
output DEBUG_LED7,
output DEBUG_LED8,
output DEBUG_LED9,
output DEBUG_LED10,
// RAM
output wire RAM_A0,
output wire RAM_A1,
output wire RAM_A2,
output wire RAM_A3,
output wire RAM_A4,
output wire RAM_A5,
output wire RAM_A6,
output wire RAM_A7,
output wire RAM_A8,
output wire RAM_A9,
output wire RAM_A10,
output wire RAM_A11,
output wire RAM_A12,
output wire RAM_A13
);
assign USEROUT0 = IF_OC[0];
assign USEROUT1 = IF_OC[1];
assign USEROUT2 = IF_OC[2];
assign USEROUT3 = IF_OC[3];
assign USEROUT4 = IF_OC[4];
assign USEROUT5 = IF_OC[5];
assign USEROUT6 = IF_OC[6];
assign RAND = IF_RAND;
assign RAND_2 = IF_RAND;
assign PGA = 0; // 1 = gain of 3dB, 0 = gain of 0dB
assign PGA_2 = 0;
assign DITH = IF_DITHER;
assign DITH_2 = IF_DITHER;
assign SHDN = 1'b0; // normal LTC2208 operation
assign SHDN_2 = 1'b0;
assign NCONFIG = IP_write_done || reset_FPGA;
// enable AF Amp
assign IO1 = 1'b0; // low to enable, high to mute
parameter M_TPD = 4;
parameter IF_TPD = 2;
parameter Angelia_version = 8'd51; // Serial number of this version
localparam Penny_serialno = 8'd00; // Use same value as equ1valent Penny code
localparam Merc_serialno = 8'd00; // Use same value as equivalent Mercury code
localparam RX_FIFO_SZ = 4096; // 16 by 4096 deep RX FIFO
localparam TX_FIFO_SZ = 1024; // 16 by 1024 deep TX FIFO
localparam SP_FIFO_SZ = 16384; // 16 by 16,384 deep SP FIFO
localparam read_reg_address = 5'd31; // PHY register to read from - gives connect speed and fully duplex
//--------------------------------------------------------------
// Reset Lines - C122_rst, IF_rst, SPI_Alex_reset
//--------------------------------------------------------------
wire IF_rst;
wire SPI_Alex_rst;
assign IF_rst = (!IF_locked || reset); // hold code in reset until PLLs are locked & PHY operational
assign PHY_RESET_N = 1'b1; // Allow PYH to run for now
// transfer IF_rst to 122.88MHz clock domain to generate C122_rst
cdc_sync #(1)
reset_C122 (.siga(IF_rst), .rstb(IF_rst), .clkb(C122_clk), .sigb(C122_rst)); // 122.88MHz clock domain reset
cdc_sync #(1)
reset_Alex (.siga(IF_rst), .rstb(IF_rst), .clkb(CBCLK), .sigb(SPI_Alex_rst)); // SPI_clk domain reset
//---------------------------------------------------------
// CLOCKS
//---------------------------------------------------------
wire C122_clk = LTC2208_122MHz;
wire C122_clk_2 = LTC2208_122MHz_2;
wire IF_clk;
wire CLRCLK;
assign CLRCIN = CLRCLK;
assign CLRCOUT = CLRCLK;
wire Apollo_clk;
wire IF_locked;
wire C122_cbrise;
// Generate IF_clk (48MHz), CMCLK (12.288MHz), CBCLK(3.072MHz) and CLRCLK (48kHz) from 122.88MHz using PLL
// NOTE: CBCLK is generated at 180 degress so that LRCLK occurs on negative edge of BCLK
PLL_IF PLL_IF_inst (.inclk0(C122_clk), .c0(IF_clk), .c1(CMCLK), .c2(CBCLK), .c3(CLRCLK), .locked(IF_locked));
pulsegen pulse (.sig(CBCLK), .rst(IF_rst), .clk(!CMCLK), .pulse(C122_cbrise)); // pulse on rising edge of BCLK for Rx/Tx frequency calculations
//----------------------------PHY Clocks-------------------
wire C125_clk; assign C125_clk = PHY_CLK125; // use PHY 125MHz clock for system clock
wire Tx_clock;
wire Tx_clock_2;
wire C125_locked; // high when PLL locked
wire PHY_data_clock;
wire PHY_speed; // 0 = 100T, 1 = 1000T
wire EEPROM_clock; // 2.5MHz
// use PLL to generate 2.5MHz, 25MHz and 12.5MHz from 125MHz
// C0 = 2.5MHz, C1 = 25MHz, C2 = 12.5MHz
PLL_clocks PLL_clocks_inst(.areset(), .inclk0(C125_clk), .c0(EEPROM_clock), .c1(Tx_clock), .c2(Tx_clock_2), .locked(C125_locked));
assign PHY_TX_CLOCK = ~Tx_clock;
assign PHY_speed = 1'b0; // high for 1000T, low for 100T; force 100T for now
// select data clock speed based on JP2 and speed that network is running at
// assign PHY_data_clock = (PHY_speed & speed_1000T) ? PHY_RX_CLOCK : PHY_RX_CLOCK_2;
// generate PHY_RX_CLOCK/2 for 100T
reg PHY_RX_CLOCK_2;
always @ (posedge PHY_RX_CLOCK) PHY_RX_CLOCK_2 <= ~PHY_RX_CLOCK_2;
// force 100T for now
assign PHY_data_clock = PHY_RX_CLOCK_2;
//------------------------------------------------------------
// Reset and initialisation
//------------------------------------------------------------
/*
Hold the code in reset whilst we do the following:
Get the boards MAC address from the EEPROM.
Then setup the PHY registers and read from the PHY until it indicates it has
negotiated a speed. Read connection speed and that we are running full duplex.
LED0 incates PHY status - fast flash if no Ethernet connection, slow flash if 100T and on if 1000T
Then wait a second (for the network to stabilise) then attempt to obtain an IP address using DHCP
- supplied address is in YIADDR. If the DHCP request either times out, or results in a NAK, retry four
additional times with a 2 second delay between each retry.
If after the retries a DHCP assigned IP address is not available use an APIPA IP address or an assigned one
from Flash.
Inhibit replying to a Metis Discovery request until an IP address has been applied.
LED6 indicates the result of DHCP - on if ACK, slow flash if NAK, fast flash if time out and
long then short flash if static IP
Once an IP address has been assigned set IP_valid flag. When set enables a response to a Discovery request.
Wait for a Metis discovery frame - once received enable HPSDR data to PC.
Enable rest of code.
*/
reg reset;
reg [4:0]start_up;
reg [47:0]This_MAC; // holds the MAC address of this Metis board
reg read_MAC;
wire MAC_ready;
reg DHCP_start;
reg [24:0]delay;
reg duplex; // set when we are connected full duplex
reg speed_100T; // set when we are connected at 100MHz
reg speed_1000T; // set when we are connected at 1GHz
reg Tx_reset; // when set prevents HPSDR UDP/IP Tx data being sent
reg [2:0]DHCP_retries; // DHCP retry counter
reg IP_valid; // set when Metis has a valid IP address assigned by DHCP or APIPA
reg Assigned_IP_valid; // set if IP address assigned by PC is not 0.0.0.0. or 255.255.255.255
reg use_IPIPA; // set when no DHCP or assigned IP available so use APIAP
reg read_IP_address; // set when we wish to read IP address from EEPROM
always @ (posedge Tx_clock_2)
begin
case (start_up)
// get the MAC address for this board
0: begin
IP_valid <= 1'b0; // clear IP valid flag
Assigned_IP_valid <= 1'b0; // clear IP in flash memory valid
reset <= 1'b1;
Tx_reset <= 1'b1; // prevent I&Q data Tx until all initialised
read_MAC <= 1'b1;
use_IPIPA <= 0; // clear IPIPA flag
start_up <= start_up + 1'b1;
end
// wait until we have read the EEPROM then the IP address
1: begin
if (MAC_ready) begin // MAC_ready goes high when EEPROM read
read_MAC <= 0;
read_IP_address <= 1'b1; // set read IP flag
start_up <= start_up + 1'b1;
end
else start_up <= 1'b1;
end
// read the IP address from EEPROM then set up the PHY
2: begin
if (IP_ready) begin
read_IP_address <= 0;
write_PHY <= 1'b1; // set write to PHY flag
start_up <= start_up + 1'b1;
end
else start_up <= 2;
end
// check the IP address read from the flash memory is valid. Set up the PHY MDIO registers
3: begin
if (AssignIP != 0 && AssignIP != 32'hFF_FF_FF_FF)
Assigned_IP_valid <= 1'b1;
if (write_done) begin
write_PHY <= 0; // clear write PHY flag so it does not run again
duplex <= 0; // clear duplex and speed flags
speed_100T <= 0;
speed_1000T <= 0;
read_PHY <= 1'b1; // set read from PHY flag
start_up <= start_up + 1'b1;
end
else start_up <= 3; // loop here till write is done
end
// loop reading PHY Register 31 bits [3],[5] & [6] to determine if final connection is full duplex at 100T or 1000T.
// Set speed and duplex bits.
// If an IP address has been assigned (i.e. != 0) then continue else
// once connected delay 1 second before trying DHCP to give network time to stabilise.
4: begin
if (read_done && (register_data[5] || register_data[6])) begin
duplex <= register_data[3]; // get connection status and speed
speed_100T <= register_data[5];
speed_1000T <= register_data[6];
read_PHY <= 0; // clear read PHY flag so it does not run again
reset <= 0;
if (duplex) begin // loop here is not fully duplex network connection
// if an IP address has been assigned then skip DHCP etc
if (Assigned_IP_valid) start_up <= 6;
// allow rest of code to run now so we can get IP address. If
else if (delay == 12500000) begin // delay 1 second so that PHY is ready for DHCP transaction
DHCP_start <= 1'b1; // start DHCP process
if (time_out) // loop until the DHCP module has cleared its time_out flag
start_up <= 4;
else begin
delay <= 0; // reset delay for DHCP retries
start_up <= start_up + 1'b1;
end
end
else delay <= delay + 1'b1;
end
end
else start_up <= 4; // keep reading Register 1 until we have a valid speed and full duplex
end
// get an IP address from the DHCP server, move to next state if successful, retry 3 times if NAK or time out.
5: begin
DHCP_start <= 0;
if (DHCP_ACK) // have DHCP assigned IP address so continue
start_up <= start_up + 1'b1;
else if (DHCP_NAK || time_out) begin // try again 3 more times with 1 second delay between attempts
if (DHCP_retries == 3) begin // no more DHCP retries so use IPIPA address and continue
use_IPIPA <= 1'b1;
start_up <= start_up + 1'b1;
end
else begin
DHCP_retries <= DHCP_retries + 1'b1; // try DHCP again
start_up <= 4;
end
end
else start_up <= 5;
end
// Have a valid IP address and a full duplex PHY connection so enable Tx code
6: begin
IP_valid <= 1'b1; // we now have a valid IP address so can respond to Discovery requests etc
Tx_reset <= 0; // release reset so UDP/IP Tx code can run
start_up <= start_up + 1'b1;
read_PHY <= 1'b1; // set read from PHY flag
end
// loop checking we still have a Network connection by reading speed from PHY registers - restart if network connection lost
7: begin
if (read_done) begin
read_PHY <= 0;
if (register_data[5] || register_data[6])
start_up <= 6; // network connection OK
else start_up <= 0; // lost network connection so re-start
end
end
default: start_up <= 0;
endcase
end
//----------------------------------------------------------------------------------
// read and write to the EEPROM (NOTE: Max clock frequency is 20MHz)
//----------------------------------------------------------------------------------
wire IP_ready;
wire write_IP;
EEPROM EEPROM_inst(.clock(EEPROM_clock), .read_MAC(read_MAC), .read_IP(read_IP_address), .write_IP(write_IP),
.IP_to_write(IP_to_write), .CS(CS), .SCK(SCK), .SI(SI), .SO(SO), .This_MAC(This_MAC),
.This_IP(AssignIP), .MAC_ready(MAC_ready), .IP_ready(IP_ready), .IP_write_done(IP_write_done));
//------------------------------------------------------------------------------------
// If DHCP provides an IP address for Metis use that else use a random APIPA address
//------------------------------------------------------------------------------------
// Use an APIPA address of 169.254.(last two bytes of the MAC address)
wire [31:0] This_IP;
wire [31:0]AssignIP; // IP address read from EEPROM
assign This_IP = Assigned_IP_valid ? AssignIP :
use_IPIPA ? {8'd169, 8'd254, This_MAC[15:0]} : YIADDR;
//----------------------------------------------------------------------------------
// Read/Write the PHY MDIO registers (NOTE: Max clock frequency is 2.5MHz)
//----------------------------------------------------------------------------------
wire write_done;
reg write_PHY;
reg read_PHY;
wire PHY_clock;
wire read_done;
wire [15:0]register_data;
wire PHY_MDIO_clk;
assign PHY_MDIO_clk = EEPROM_clock;
MDIO MDIO_inst(.clk(PHY_MDIO_clk), .write_PHY(write_PHY), .write_done(write_done), .read_PHY(read_PHY),
.clock(PHY_MDC), .MDIO_inout(PHY_MDIO), .read_done(read_done),
.read_reg_address(read_reg_address), .register_data(register_data),.speed(PHY_speed));
//----------------------------------------------------------------------------------
// Renew the DHCP supplied IP address at half the lease period
//----------------------------------------------------------------------------------
/*
Request a DHCP IP address at IP_lease/2 seconds if we have a valid DHCP assigned IP address.
The IP_lease is obtained from the DHCP server and returned during the DHCP ACK.
This is the number of seconds that the IP lease is valid.
Divide this value by 2 then multiply by the clock rate to give the delay time.
If an IP_lease time of zero is received then the lease time is set to 24 days.
*/
wire [51:0]lease_time;
assign lease_time = (IP_lease == 0) ? 52'h7735_8C8C_A6C0 : (IP_lease >> 1) * 12500000; // 24 days if no lease time given
// assign lease_time = (IP_lease == 0) ? 52'h7735_8C8C_A6C0 : (52'd4 * 52'd12500000); // every 4 seconds for testing
reg [24:0]IP_delay;
reg DHCP_renew;
reg [3:0]renew_DHCP_retries;
reg [51:0]renew_counter;
reg [24:0]renew_timer;
reg [2:0]renew;
reg printf;
reg DHCP_request_renew;
reg second_time; // set if can't get a DHCP IP address after two tries.
reg DHCP_discover_broadcast; // last ditch attempt so do a discovery broadcast
always @(posedge Tx_clock_2)
begin
case (renew)
0: begin
renew_timer <= 0;
if (DHCP_ACK) begin // only run if we have a valid DHCP supplied IP address
if (renew_counter == lease_time )begin
renew_counter <= 0;
renew <= renew + 1'b1;
end
else renew_counter <= renew_counter + 1'b1;
end
else renew <= 0;
end
// Renew DHCP IP address
1: begin
if (second_time)
renew <= 4;
else begin
DHCP_request_renew <= 1'b1;
renew <= renew + 1'b1;
end
end
// delay so the request is seen then return
2: renew <= renew + 1'b1;
// get an IP address from the DHCP server, move to next state if successful, if not reset lease timer to 1/4 previous value
3: begin
DHCP_request_renew <= 0;
if (renew_timer != 2 * 12500000) begin // delay for 2 seconds before we look for ACK, NAK or time_out
renew_timer <= renew_timer + 1'b1;
renew <= 3;
end
else begin
if (DHCP_NAK || time_out) begin // did not renew so set timer to lease_time/4
second_time <= 1'b1;
renew_counter = (lease_time - lease_time >> 4); // i.e. 0.75 * lease_time
renew <= 0;
end
else begin
renew_counter <= 0; // did renew so reset counter and continue.
renew <= 0;
end
end
end
// have not got an IP address the second time we tryed so use a broadcast and loop here
4: begin
DHCP_discover_broadcast <= 1'b1; // do a DHCP discovery
renew <= renew + 1'b1;
end
// if we get a DHCP_ACK then continue else give up
5: begin
DHCP_discover_broadcast <= 0;
if (renew_timer != 2 * 12500000) begin // delay for 2 seconds before we look for ACK, NAK or time_out
renew_timer <= renew_timer + 1'b1;
renew <= 5;
end
else if (DHCP_NAK || time_out) // did not renew so give up
renew <= 5;
else begin // did renew so continue
second_time <= 0;
renew <= 0;
end
end
default: renew <= 0;
endcase
end
//----------------------------------------------------------------------------------
// See if we can get an IP address using DHCP
//----------------------------------------------------------------------------------
wire time_out;
wire DHCP_request;
DHCP DHCP_inst(Tx_clock_2, (DHCP_start || DHCP_discover_broadcast), DHCP_renew, DHCP_discover , DHCP_offer, time_out, DHCP_request, DHCP_ACK);
//---------------------------------------------------------
// Set up TLV320 using SPI
//---------------------------------------------------------
TLV320_SPI TLV (.clk(CMCLK), .CMODE(CMODE), .nCS(nCS), .MOSI(MOSI), .SSCK(SSCK), .boost(IF_Mic_boost), .line(IF_Line_In), .line_in_gain(IF_Line_In_Gain));
//-----------------------------------------------------
// Rx_MAC - PHY Receive Interface
//-----------------------------------------------------
wire [7:0]ping_data[0:59];
wire [15:0]Port;
wire [15:0]Discovery_Port; // PC port doing a Discovery
wire broadcast;
wire ARP_request;
wire ping_request;
wire Rx_enable;
wire this_MAC; // set when packet addressed to this MAC
wire DHCP_offer; // set when we get a valid DHCP_offer
wire [31:0]YIADDR; // DHCP supplied IP address for this board
wire [31:0]DHCP_IP; // IP address of DHCP server offering IP address
wire DHCP_ACK, DHCP_NAK;
wire [31:0]PC_IP; // IP address of the PC we are connecting to
wire [31:0]Discovery_IP; // IP address of the PC doing a Discovery
wire [47:0]PC_MAC; // MAC address of the PC we are connecting to
wire [47:0]Discovery_MAC; // MAC address of the PC doing a Discovery
wire [31:0]Use_IP; // Assigned IP address, if zero then use DHCP
wire METIS_discovery; // pulse high when Metis_discovery received
wire [47:0]ARP_PC_MAC; // MAC address of PC requesting ARP
wire [31:0]ARP_PC_IP; // IP address of PC requesting ARP
wire [47:0]Ping_PC_MAC; // MAC address of PC requesting ping
wire [31:0]Ping_PC_IP; // IP address of PC requesting ping
wire [15:0]Length; // Lenght of frame - used by ping
wire data_match; // for debug use
wire PHY_100T_state; // used as system clock at 100T
wire [7:0] Rx_fifo_data; // byte from PHY to send to Rx_fifo
wire rs232_write_strobe;
wire seq_error; // set when we receive a sequence error
wire run; // set to send data to PC
wire wide_spectrum; // set to send wide spectrum data
wire [31:0]IP_lease; // holds IP lease in seconds from DHCP ACK packet
wire [47:0]DHCP_MAC; // MAC address of DHCP server
wire erase; // set when we receive an erase EPCS16 command
wire erase_ACK; // set when ASMI interface acks the erase command
wire [31:0]num_blocks; // number of 256 byte blocks to save in EPCS16
wire EPCS_FIFO_enable; // EPCS fifo write enable
wire IP_write_done;
wire [31:0] IP_to_write;
Rx_MAC Rx_MAC_inst (.PHY_RX_CLOCK(PHY_RX_CLOCK), .PHY_data_clock(PHY_data_clock),.RX_DV(RX_DV), .PHY_RX(PHY_RX),
.broadcast(broadcast), .ARP_request(ARP_request), .ping_request(ping_request),
.Rx_enable(Rx_enable), .this_MAC(this_MAC), .Rx_fifo_data(Rx_fifo_data), .ping_data(ping_data),
.DHCP_offer(DHCP_offer),
.This_MAC(This_MAC), .YIADDR(YIADDR), .DHCP_ACK(DHCP_ACK), .DHCP_NAK(DHCP_NAK),
.METIS_discovery(METIS_discovery), .METIS_discover_sent(METIS_discover_sent), .PC_IP(PC_IP), .PC_MAC(PC_MAC),
.This_IP(This_IP), .Length(Length), .PHY_100T_state(PHY_100T_state),
.ARP_PC_MAC(ARP_PC_MAC), .ARP_PC_IP(ARP_PC_IP), .Ping_PC_MAC(Ping_PC_MAC),
.Ping_PC_IP(Ping_PC_IP), .Port(Port), .seq_error(seq_error), .data_match(data_match),
.run(run), .IP_lease(IP_lease), .DHCP_IP(DHCP_IP), .DHCP_MAC(DHCP_MAC),
.erase(erase), .erase_ACK(erase_ACK), .num_blocks(num_blocks), .EPCS_FIFO_enable(EPCS_FIFO_enable),
.wide_spectrum(wide_spectrum), .IP_write_done(IP_write_done), .write_IP(write_IP),
.IP_to_write(IP_to_write)
);
//-----------------------------------------------------
// Tx_MAC - PHY Transmit Interface
//-----------------------------------------------------
wire [10:0] PHY_Tx_rdused;
wire LED;
wire Tx_fifo_rdreq;
wire ARP_sent;
wire DHCP_discover;
reg [7:0] RS232_data;
reg RS232_Tx;
wire DHCP_request_sent;
wire DHCP_discover_sent;
wire METIS_discover_sent;
wire Tx_CTL;
wire [3:0]TD;
Tx_MAC Tx_MAC_inst (.Tx_clock(Tx_clock), .Tx_clock_2(Tx_clock_2), .IF_rst(IF_rst),
.Send_ARP(Send_ARP),.ping_reply(ping_reply),.PHY_Tx_data(PHY_Tx_data),
.PHY_Tx_rdused(PHY_Tx_rdused), .ping_data(ping_data), .LED(LED),
.Tx_fifo_rdreq(Tx_fifo_rdreq),.Tx_CTL(PHY_TX_EN), .ARP_sent(ARP_sent),
.ping_sent(ping_sent), .TD(PHY_TX),.DHCP_request(DHCP_request),
.DHCP_discover_sent(DHCP_discover_sent), .This_MAC(This_MAC),
.DHCP_discover(DHCP_discover), .DHCP_IP(DHCP_IP), .DHCP_request_sent(DHCP_request_sent),
.METIS_discovery(METIS_discovery), .PC_IP(PC_IP), .PC_MAC(PC_MAC), .Length(Length),
.Port(Port), .This_IP(This_IP), .METIS_discover_sent(METIS_discover_sent),
.ARP_PC_MAC(ARP_PC_MAC), .ARP_PC_IP(ARP_PC_IP), .Ping_PC_IP(Ping_PC_IP),
.Ping_PC_MAC(Ping_PC_MAC), .speed_100T(1'b1), .Tx_reset(Tx_reset),
.run(run), .IP_valid(IP_valid), .printf(printf), .IP_lease(IP_lease),
.DHCP_MAC(DHCP_MAC), .DHCP_request_renew(DHCP_request_renew),
.erase_done(erase_done), .erase_done_ACK(erase_done_ACK), .send_more(send_more),
.send_more_ACK(send_more_ACK), .Angelia_version(Angelia_version),
.sp_fifo_rddata(sp_fifo_rddata), .sp_fifo_rdreq(sp_fifo_rdreq),
.sp_fifo_rdused(), .wide_spectrum(wide_spectrum), .have_sp_data(sp_data_ready),
.AssignIP(AssignIP)
);
//------------------------ sequence ARP and Ping requests -----------------------------------
reg Send_ARP;
reg ping_reply;
reg ping_sent;
reg [16:0]times_up; // time out counter so code wont hang here
reg [1:0] state;
parameter IDLE = 2'd0,
ARP = 2'd1,
PING = 2'd2;
//always @ (posedge PHY_RX_CLOCK)
always @ (posedge Tx_clock)
begin
case (state)
IDLE: begin
times_up <= 0;
Send_ARP <= 0;
ping_reply <= 0;
if (ARP_request) state <= ARP;
else if (ping_request) state <= PING;
end
ARP: begin
Send_ARP <= 1'b1;
if (ARP_sent || times_up > 100000) state <= IDLE;
times_up <= times_up + 17'd1;
end
PING: begin
ping_reply <= 1'b1;
if (ping_sent || times_up > 100000) state <= IDLE;
times_up <= times_up + 17'd1;
end
default: state = IDLE;
endcase
end