aboutsummaryrefslogblamecommitdiff
path: root/bench/tb_mmm_dual_x8.v
blob: 1188f9205e430dcd65777b8f5ac31f90f6056a57 (plain) (tree)
1
2
3
4
5
6
7
8
9
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








                                            























































































































































































































































































































































                                                                                                                   
                                           








                                                             
                                           









                                                          



                                                         



                                                        

                                                       





























                                                           
                                       








                                                  

                                                     


                                                     

                                                    




















                                                      
                                       



























                                                      












                                                   




                                            
                                       



                                                  

                                                



                                                    

                                                  
        




                                                   
    




                                                     










                                                      
























                                                       





























































































































































































































































































































































































































                                                                                                                                                                                                                           
`timescale 1ns / 1ps

module tb_mmm_dual_x8;


    //
    // Headers
    //
    `include "../rtl/modexpng_parameters.vh"


    //
    // Clock
    //
    `define CLK_FREQUENCY_MHZ   (100.0)
    `define CLK_PERIOD_NS       (1000.0 / `CLK_FREQUENCY_MHZ)
    `define CLK_PERIOD_HALF_NS  (0.5 * `CLK_PERIOD_NS)
    
	reg clk = 1'b0;

    always begin
        #`CLK_PERIOD_HALF_NS clk = 1'b1;
        #`CLK_PERIOD_HALF_NS clk = 1'b0;
    end
    
    
    //
    // Reset
    //
    reg rst = 1'b1;
    

    //
    // Test Vectors
    //
    localparam                  PQ_NUM_WORDS       = 32;
    localparam [OP_ADDR_W -1:0] PQ_WORD_INDEX_LAST = PQ_NUM_WORDS - 1;
    
    localparam P_LADDER_MODE = 1'b0;
    
    reg [WORD_EXT_W -1:0] P_T1     [0:PQ_NUM_WORDS -1];
    reg [WORD_EXT_W -1:0] P_T2     [0:PQ_NUM_WORDS -1];

    reg [WORD_EXT_W -1:0] P_N      [0:PQ_NUM_WORDS -1];
    reg [WORD_EXT_W -1:0] P_N_COEFF[0:PQ_NUM_WORDS   ];

    reg [WORD_EXT_W -1:0] P_X_AB   [0:2*PQ_NUM_WORDS -1];
    reg [WORD_EXT_W -1:0] P_Y_AB   [0:2*PQ_NUM_WORDS -1];

    reg [WORD_EXT_W -1:0] P_X_Q    [0:PQ_NUM_WORDS];
    reg [WORD_EXT_W -1:0] P_Y_Q    [0:PQ_NUM_WORDS];

    reg [WORD_EXT_W -1:0] P_X_M    [0:2*PQ_NUM_WORDS];
    reg [WORD_EXT_W -1:0] P_Y_M    [0:2*PQ_NUM_WORDS];

    reg [WORD_EXT_W -1:0] P_X      [0:PQ_NUM_WORDS -1];
    reg [WORD_EXT_W -1:0] P_Y      [0:PQ_NUM_WORDS -1];
    

    //
    // Test Vector Components
    //
    initial begin
        //
        P_T1[ 0] = 18'h191c5; P_T1[ 1] = 18'h1a118; P_T1[ 2] = 18'h16e06; P_T1[ 3] = 18'h0ea68;
        P_T1[ 4] = 18'h12944; P_T1[ 5] = 18'h0c242; P_T1[ 6] = 18'h2fc64; P_T1[ 7] = 18'h14efc;
        P_T1[ 8] = 18'h113da; P_T1[ 9] = 18'h16ff7; P_T1[10] = 18'h1ef0c; P_T1[11] = 18'h18580;
        P_T1[12] = 18'h1a62c; P_T1[13] = 18'h352b7; P_T1[14] = 18'h114f4; P_T1[15] = 18'h1c53e;
        P_T1[16] = 18'h0c63e; P_T1[17] = 18'h0dd14; P_T1[18] = 18'h2fba8; P_T1[19] = 18'h1b8e4;
        P_T1[20] = 18'h2d944; P_T1[21] = 18'h10290; P_T1[22] = 18'h1d276; P_T1[23] = 18'h327b0;
        P_T1[24] = 18'h1c0c4; P_T1[25] = 18'h100a8; P_T1[26] = 18'h2a9ab; P_T1[27] = 18'h0e694;
        P_T1[28] = 18'h10798; P_T1[29] = 18'h1ae91; P_T1[30] = 18'h38d4c; P_T1[31] = 18'h00808;
        //
        P_T2[ 0] = 18'h1193b; P_T2[ 1] = 18'h0de9c; P_T2[ 2] = 18'h0b993; P_T2[ 3] = 18'h0d2cd;
        P_T2[ 4] = 18'h106ad; P_T2[ 5] = 18'h076da; P_T2[ 6] = 18'h10cab; P_T2[ 7] = 18'h15cd5;
        P_T2[ 8] = 18'h15425; P_T2[ 9] = 18'h16287; P_T2[10] = 18'h0fd64; P_T2[11] = 18'h06ee0;
        P_T2[12] = 18'h1b0c9; P_T2[13] = 18'h01a5e; P_T2[14] = 18'h1855c; P_T2[15] = 18'h17bf9;
        P_T2[16] = 18'h1c83c; P_T2[17] = 18'h158ed; P_T2[18] = 18'h086df; P_T2[19] = 18'h16676;
        P_T2[20] = 18'h0a0f8; P_T2[21] = 18'h14545; P_T2[22] = 18'h09641; P_T2[23] = 18'h16863;
        P_T2[24] = 18'h17e20; P_T2[25] = 18'h0d457; P_T2[26] = 18'h05a9b; P_T2[27] = 18'h1a4cf;
        P_T2[28] = 18'h1582a; P_T2[29] = 18'h1686c; P_T2[30] = 18'h1394e; P_T2[31] = 18'h0bdbc;
        //
        P_N[ 0] = 18'h00f97; P_N[ 1] = 18'h018bb; P_N[ 2] = 18'h08a44; P_N[ 3] = 18'h00858;
        P_N[ 4] = 18'h06647; P_N[ 5] = 18'h0042c; P_N[ 6] = 18'h0fa09; P_N[ 7] = 18'h0c8d3;
        P_N[ 8] = 18'h0bbc7; P_N[ 9] = 18'h0e2dd; P_N[10] = 18'h017fd; P_N[11] = 18'h0ef4a;
        P_N[12] = 18'h002ef; P_N[13] = 18'h090c1; P_N[14] = 18'h032db; P_N[15] = 18'h028b1;
        P_N[16] = 18'h05f0a; P_N[17] = 18'h0ebfd; P_N[18] = 18'h017ca; P_N[19] = 18'h09587;
        P_N[20] = 18'h0d266; P_N[21] = 18'h0563c; P_N[22] = 18'h041af; P_N[23] = 18'h0433f;
        P_N[24] = 18'h08e83; P_N[25] = 18'h0bc19; P_N[26] = 18'h000b2; P_N[27] = 18'h05b53;
        P_N[28] = 18'h00e5d; P_N[29] = 18'h09bc5; P_N[30] = 18'h0a822; P_N[31] = 18'h0efff;
        //
        P_N_COEFF[ 0] = 18'h09fd9; P_N_COEFF[ 1] = 18'h0b367; P_N_COEFF[ 2] = 18'h0e467; P_N_COEFF[ 3] = 18'h0de24;
        P_N_COEFF[ 4] = 18'h02022; P_N_COEFF[ 5] = 18'h0f0e8; P_N_COEFF[ 6] = 18'h02919; P_N_COEFF[ 7] = 18'h09901;
        P_N_COEFF[ 8] = 18'h0da43; P_N_COEFF[ 9] = 18'h0023b; P_N_COEFF[10] = 18'h0ebf8; P_N_COEFF[11] = 18'h0f04e;
        P_N_COEFF[12] = 18'h0942f; P_N_COEFF[13] = 18'h029e9; P_N_COEFF[14] = 18'h07cb0; P_N_COEFF[15] = 18'h08c25;
        P_N_COEFF[16] = 18'h04e60; P_N_COEFF[17] = 18'h05cdc; P_N_COEFF[18] = 18'h0dff7; P_N_COEFF[19] = 18'h0279b;
        P_N_COEFF[20] = 18'h0610d; P_N_COEFF[21] = 18'h0f04a; P_N_COEFF[22] = 18'h001dc; P_N_COEFF[23] = 18'h03429;
        P_N_COEFF[24] = 18'h0f78c; P_N_COEFF[25] = 18'h0c3e2; P_N_COEFF[26] = 18'h00ed8; P_N_COEFF[27] = 18'h039c0;
        P_N_COEFF[28] = 18'h02ac2; P_N_COEFF[29] = 18'h0f703; P_N_COEFF[30] = 18'h0c54e; P_N_COEFF[31] = 18'h022d9;
        P_N_COEFF[32] = 18'h0f994;
        //
        P_X_AB[ 0] = 18'h0c199; P_X_AB[ 1] = 18'h0957a; P_X_AB[ 2] = 18'h070ad; P_X_AB[ 3] = 18'h0e5a6;
        P_X_AB[ 4] = 18'h0fec9; P_X_AB[ 5] = 18'h00b73; P_X_AB[ 6] = 18'h09c72; P_X_AB[ 7] = 18'h0cdf0;
        P_X_AB[ 8] = 18'h08755; P_X_AB[ 9] = 18'h07560; P_X_AB[10] = 18'h084b1; P_X_AB[11] = 18'h0ad3f;
        P_X_AB[12] = 18'h074fe; P_X_AB[13] = 18'h04d74; P_X_AB[14] = 18'h00e16; P_X_AB[15] = 18'h0d3b3;
        P_X_AB[16] = 18'h0d418; P_X_AB[17] = 18'h02f12; P_X_AB[18] = 18'h0c301; P_X_AB[19] = 18'h0be2b;
        P_X_AB[20] = 18'h08222; P_X_AB[21] = 18'h0056c; P_X_AB[22] = 18'h01c7c; P_X_AB[23] = 18'h0bc95;
        P_X_AB[24] = 18'h03427; P_X_AB[25] = 18'h0c65a; P_X_AB[26] = 18'h089ac; P_X_AB[27] = 18'h02117;
        P_X_AB[28] = 18'h0ff7d; P_X_AB[29] = 18'h01cde; P_X_AB[30] = 18'h02709; P_X_AB[31] = 18'h01c56;
        P_X_AB[32] = 18'h0f35a; P_X_AB[33] = 18'h08ce6; P_X_AB[34] = 18'h0a8e5; P_X_AB[35] = 18'h0d6d4;
        P_X_AB[36] = 18'h06868; P_X_AB[37] = 18'h09105; P_X_AB[38] = 18'h0219e; P_X_AB[39] = 18'h0bc40;
        P_X_AB[40] = 18'h00e0a; P_X_AB[41] = 18'h07783; P_X_AB[42] = 18'h0187a; P_X_AB[43] = 18'h0b922;
        P_X_AB[44] = 18'h02609; P_X_AB[45] = 18'h0c64b; P_X_AB[46] = 18'h06b4b; P_X_AB[47] = 18'h04b79;
        P_X_AB[48] = 18'h0fed6; P_X_AB[49] = 18'h03eac; P_X_AB[50] = 18'h04cac; P_X_AB[51] = 18'h0d47d;
        P_X_AB[52] = 18'h045fd; P_X_AB[53] = 18'h04fa8; P_X_AB[54] = 18'h0597c; P_X_AB[55] = 18'h0a10d;
        P_X_AB[56] = 18'h0bf44; P_X_AB[57] = 18'h08671; P_X_AB[58] = 18'h0112a; P_X_AB[59] = 18'h08ccf;
        P_X_AB[60] = 18'h0cae5; P_X_AB[61] = 18'h04d94; P_X_AB[62] = 18'h0b95a; P_X_AB[63] = 18'h00040;
        //
        P_X_Q[ 0] = 18'h021b1; P_X_Q[ 1] = 18'h0d2db; P_X_Q[ 2] = 18'h0754b; P_X_Q[ 3] = 18'h01fc1;
        P_X_Q[ 4] = 18'h063f7; P_X_Q[ 5] = 18'h086e5; P_X_Q[ 6] = 18'h0bcea; P_X_Q[ 7] = 18'h02260;
        P_X_Q[ 8] = 18'h0c54c; P_X_Q[ 9] = 18'h0e298; P_X_Q[10] = 18'h05d07; P_X_Q[11] = 18'h0f978;
        P_X_Q[12] = 18'h0e742; P_X_Q[13] = 18'h0a3f0; P_X_Q[14] = 18'h0b31e; P_X_Q[15] = 18'h041b7;
        P_X_Q[16] = 18'h06ed9; P_X_Q[17] = 18'h03ac5; P_X_Q[18] = 18'h0f8eb; P_X_Q[19] = 18'h0c619;
        P_X_Q[20] = 18'h067e9; P_X_Q[21] = 18'h00350; P_X_Q[22] = 18'h00376; P_X_Q[23] = 18'h02ebf;
        P_X_Q[24] = 18'h0b125; P_X_Q[25] = 18'h05f7d; P_X_Q[26] = 18'h0f121; P_X_Q[27] = 18'h07ba4;
        P_X_Q[28] = 18'h03050; P_X_Q[29] = 18'h0642e; P_X_Q[30] = 18'h0c2fc; P_X_Q[31] = 18'h0dfcf;
        P_X_Q[32] = 18'h03f9e;
        //
        P_X_M[ 0] = 18'h03e67; P_X_M[ 1] = 18'h06a85; P_X_M[ 2] = 18'h08f52; P_X_M[ 3] = 18'h01a59;
        P_X_M[ 4] = 18'h00136; P_X_M[ 5] = 18'h0f48c; P_X_M[ 6] = 18'h0638d; P_X_M[ 7] = 18'h0320f;
        P_X_M[ 8] = 18'h078aa; P_X_M[ 9] = 18'h08a9f; P_X_M[10] = 18'h07b4e; P_X_M[11] = 18'h052c0;
        P_X_M[12] = 18'h08b01; P_X_M[13] = 18'h0b28b; P_X_M[14] = 18'h0f1e9; P_X_M[15] = 18'h02c4c;
        P_X_M[16] = 18'h02be7; P_X_M[17] = 18'h0d0ed; P_X_M[18] = 18'h03cfe; P_X_M[19] = 18'h041d4;
        P_X_M[20] = 18'h07ddd; P_X_M[21] = 18'h0fa93; P_X_M[22] = 18'h0e383; P_X_M[23] = 18'h0436a;
        P_X_M[24] = 18'h0cbd8; P_X_M[25] = 18'h039a5; P_X_M[26] = 18'h07653; P_X_M[27] = 18'h0dee8;
        P_X_M[28] = 18'h00082; P_X_M[29] = 18'h0e321; P_X_M[30] = 18'h0d8f6; P_X_M[31] = 18'h0e3a9;
        P_X_M[32] = 18'h00ca5; P_X_M[33] = 18'h035ed; P_X_M[34] = 18'h02b8f; P_X_M[35] = 18'h063bd;
        P_X_M[36] = 18'h0ec9f; P_X_M[37] = 18'h0b8bb; P_X_M[38] = 18'h00389; P_X_M[39] = 18'h0ca27;
        P_X_M[40] = 18'h0bea7; P_X_M[41] = 18'h0df1e; P_X_M[42] = 18'h0d685; P_X_M[43] = 18'h0cc1b;
        P_X_M[44] = 18'h036c4; P_X_M[45] = 18'h01ce9; P_X_M[46] = 18'h0c43b; P_X_M[47] = 18'h05f58;
        P_X_M[48] = 18'h02c77; P_X_M[49] = 18'h03a12; P_X_M[50] = 18'h0eea8; P_X_M[51] = 18'h0ac31;
        P_X_M[52] = 18'h05838; P_X_M[53] = 18'h093ac; P_X_M[54] = 18'h0fd54; P_X_M[55] = 18'h06e13;
        P_X_M[56] = 18'h002e2; P_X_M[57] = 18'h06af4; P_X_M[58] = 18'h0ea18; P_X_M[59] = 18'h083b3;
        P_X_M[60] = 18'h059f7; P_X_M[61] = 18'h016d3; P_X_M[62] = 18'h0c3ad; P_X_M[63] = 18'h0dbfc;
        P_X_M[64] = 18'h03ba4;
        //
        P_Y_AB[ 0] = 18'h0d567; P_Y_AB[ 1] = 18'h0dbf1; P_Y_AB[ 2] = 18'h024b3; P_Y_AB[ 3] = 18'h0bb34;
        P_Y_AB[ 4] = 18'h03ad4; P_Y_AB[ 5] = 18'h08997; P_Y_AB[ 6] = 18'h0d369; P_Y_AB[ 7] = 18'h0ebbc;
        P_Y_AB[ 8] = 18'h09502; P_Y_AB[ 9] = 18'h01b76; P_Y_AB[10] = 18'h0a28f; P_Y_AB[11] = 18'h0c577;
        P_Y_AB[12] = 18'h05f2f; P_Y_AB[13] = 18'h08c45; P_Y_AB[14] = 18'h0dbb8; P_Y_AB[15] = 18'h036bf;
        P_Y_AB[16] = 18'h05086; P_Y_AB[17] = 18'h0437e; P_Y_AB[18] = 18'h08e3d; P_Y_AB[19] = 18'h0ec97;
        P_Y_AB[20] = 18'h0195c; P_Y_AB[21] = 18'h02e75; P_Y_AB[22] = 18'h0d94f; P_Y_AB[23] = 18'h0ce1e;
        P_Y_AB[24] = 18'h0fd8d; P_Y_AB[25] = 18'h0ec03; P_Y_AB[26] = 18'h058a0; P_Y_AB[27] = 18'h05fc4;
        P_Y_AB[28] = 18'h0f83f; P_Y_AB[29] = 18'h09a60; P_Y_AB[30] = 18'h0f047; P_Y_AB[31] = 18'h05ee6;
        P_Y_AB[32] = 18'h02a39; P_Y_AB[33] = 18'h08b08; P_Y_AB[34] = 18'h0f66d; P_Y_AB[35] = 18'h0b2fb;
        P_Y_AB[36] = 18'h02f3f; P_Y_AB[37] = 18'h092b2; P_Y_AB[38] = 18'h09b4e; P_Y_AB[39] = 18'h0ce4f;
        P_Y_AB[40] = 18'h04428; P_Y_AB[41] = 18'h00483; P_Y_AB[42] = 18'h0f595; P_Y_AB[43] = 18'h031cb;
        P_Y_AB[44] = 18'h0d292; P_Y_AB[45] = 18'h0ded9; P_Y_AB[46] = 18'h0ef15; P_Y_AB[47] = 18'h0da51;
        P_Y_AB[48] = 18'h0ed93; P_Y_AB[49] = 18'h03969; P_Y_AB[50] = 18'h05efc; P_Y_AB[51] = 18'h004e7;
        P_Y_AB[52] = 18'h09434; P_Y_AB[53] = 18'h02b91; P_Y_AB[54] = 18'h0d3db; P_Y_AB[55] = 18'h0c4cf;
        P_Y_AB[56] = 18'h09d34; P_Y_AB[57] = 18'h0cea8; P_Y_AB[58] = 18'h0de0d; P_Y_AB[59] = 18'h0f190;
        P_Y_AB[60] = 18'h0b95a; P_Y_AB[61] = 18'h0bd8a; P_Y_AB[62] = 18'h079a6; P_Y_AB[63] = 18'h005f6;
        //
        P_Y_Q[ 0] = 18'h0dd4f; P_Y_Q[ 1] = 18'h084f9; P_Y_Q[ 2] = 18'h00105; P_Y_Q[ 3] = 18'h0cdff;
        P_Y_Q[ 4] = 18'h0973c; P_Y_Q[ 5] = 18'h0440c; P_Y_Q[ 6] = 18'h0450b; P_Y_Q[ 7] = 18'h09e70;
        P_Y_Q[ 8] = 18'h0d686; P_Y_Q[ 9] = 18'h0e21a; P_Y_Q[10] = 18'h02d26; P_Y_Q[11] = 18'h0b117;
        P_Y_Q[12] = 18'h08556; P_Y_Q[13] = 18'h002ee; P_Y_Q[14] = 18'h0083d; P_Y_Q[15] = 18'h079fa;
        P_Y_Q[16] = 18'h0f25d; P_Y_Q[17] = 18'h0cd26; P_Y_Q[18] = 18'h0bb7e; P_Y_Q[19] = 18'h07676;
        P_Y_Q[20] = 18'h0f4bb; P_Y_Q[21] = 18'h02b87; P_Y_Q[22] = 18'h02909; P_Y_Q[23] = 18'h05e2d;
        P_Y_Q[24] = 18'h09c80; P_Y_Q[25] = 18'h098f3; P_Y_Q[26] = 18'h0f08b; P_Y_Q[27] = 18'h0255b;
        P_Y_Q[28] = 18'h0fbe5; P_Y_Q[29] = 18'h0ae8e; P_Y_Q[30] = 18'h0ba22; P_Y_Q[31] = 18'h0f2ea;
        P_Y_Q[32] = 18'h0530e;
        //
        P_Y_M[ 0] = 18'h02a99; P_Y_M[ 1] = 18'h0240e; P_Y_M[ 2] = 18'h0db4c; P_Y_M[ 3] = 18'h044cb;
        P_Y_M[ 4] = 18'h0c52b; P_Y_M[ 5] = 18'h07668; P_Y_M[ 6] = 18'h02c96; P_Y_M[ 7] = 18'h01443;
        P_Y_M[ 8] = 18'h06afd; P_Y_M[ 9] = 18'h0e489; P_Y_M[10] = 18'h05d70; P_Y_M[11] = 18'h03a88;
        P_Y_M[12] = 18'h0a0d0; P_Y_M[13] = 18'h073ba; P_Y_M[14] = 18'h02447; P_Y_M[15] = 18'h0c940;
        P_Y_M[16] = 18'h0af79; P_Y_M[17] = 18'h0bc81; P_Y_M[18] = 18'h071c2; P_Y_M[19] = 18'h01368;
        P_Y_M[20] = 18'h0e6a3; P_Y_M[21] = 18'h0d18a; P_Y_M[22] = 18'h026b0; P_Y_M[23] = 18'h031e1;
        P_Y_M[24] = 18'h00272; P_Y_M[25] = 18'h013fc; P_Y_M[26] = 18'h0a75f; P_Y_M[27] = 18'h0a03b;
        P_Y_M[28] = 18'h007c0; P_Y_M[29] = 18'h0659f; P_Y_M[30] = 18'h00fb8; P_Y_M[31] = 18'h0a119;
        P_Y_M[32] = 18'h0d5c6; P_Y_M[33] = 18'h09926; P_Y_M[34] = 18'h0d69f; P_Y_M[35] = 18'h085cd;
        P_Y_M[36] = 18'h0591a; P_Y_M[37] = 18'h0e6dd; P_Y_M[38] = 18'h0981f; P_Y_M[39] = 18'h087b4;
        P_Y_M[40] = 18'h015b3; P_Y_M[41] = 18'h09421; P_Y_M[42] = 18'h0ea9d; P_Y_M[43] = 18'h013af;
        P_Y_M[44] = 18'h096ac; P_Y_M[45] = 18'h06f86; P_Y_M[46] = 18'h0cab7; P_Y_M[47] = 18'h06ab1;
        P_Y_M[48] = 18'h0903e; P_Y_M[49] = 18'h06203; P_Y_M[50] = 18'h0751a; P_Y_M[51] = 18'h02fce;
        P_Y_M[52] = 18'h0d0c9; P_Y_M[53] = 18'h00522; P_Y_M[54] = 18'h096f8; P_Y_M[55] = 18'h03aee;
        P_Y_M[56] = 18'h0a034; P_Y_M[57] = 18'h0e52e; P_Y_M[58] = 18'h07b7b; P_Y_M[59] = 18'h06bad;
        P_Y_M[60] = 18'h0016d; P_Y_M[61] = 18'h01315; P_Y_M[62] = 18'h02586; P_Y_M[63] = 18'h0e73a;
        P_Y_M[64] = 18'h04ddd;
        //
        P_X[ 0] = 18'h0c2d4; P_X[ 1] = 18'h0d474; P_X[ 2] = 18'h13a91; P_X[ 3] = 18'h15507;
        P_X[ 4] = 18'h149c0; P_X[ 5] = 18'h02527; P_X[ 6] = 18'h18667; P_X[ 7] = 18'h0ccb1;
        P_X[ 8] = 18'h156a1; P_X[ 9] = 18'h0eeff; P_X[10] = 18'h1853d; P_X[11] = 18'h05ccd;
        P_X[12] = 18'h0e334; P_X[13] = 18'h12f86; P_X[14] = 18'h0aad1; P_X[15] = 18'h12b4d;
        P_X[16] = 18'h078be; P_X[17] = 18'h13b54; P_X[18] = 18'h180ae; P_X[19] = 18'h09e35;
        P_X[20] = 18'h0e354; P_X[21] = 18'h156d0; P_X[22] = 18'h10f20; P_X[23] = 18'h0c226;
        P_X[24] = 18'h0f165; P_X[25] = 18'h0fb42; P_X[26] = 18'h11082; P_X[27] = 18'h124dc;
        P_X[28] = 18'h06467; P_X[29] = 18'h17d07; P_X[30] = 18'h0dc3c; P_X[31] = 18'h03ba4;
        //
        P_Y[ 0] = 18'h1242f; P_Y[ 1] = 18'h1cd0c; P_Y[ 2] = 18'h138c8; P_Y[ 3] = 18'h08859;
        P_Y[ 4] = 18'h1798f; P_Y[ 5] = 18'h1336d; P_Y[ 6] = 18'h15603; P_Y[ 7] = 18'h059db;
        P_Y[ 8] = 18'h098a4; P_Y[ 9] = 18'h1e032; P_Y[10] = 18'h0457a; P_Y[11] = 18'h1693e;
        P_Y[12] = 18'h14e5f; P_Y[13] = 18'h1b9cc; P_Y[14] = 18'h14502; P_Y[15] = 18'h17dd1;
        P_Y[16] = 18'h09b6c; P_Y[17] = 18'h0d416; P_Y[18] = 18'h034b5; P_Y[19] = 18'h164fd;
        P_Y[20] = 18'h030b3; P_Y[21] = 18'h16ad3; P_Y[22] = 18'h0ffbd; P_Y[23] = 18'h13d68;
        P_Y[24] = 18'h1b3d6; P_Y[25] = 18'h15988; P_Y[26] = 18'h15d3d; P_Y[27] = 18'h0bac7;
        P_Y[28] = 18'h0d09f; P_Y[29] = 18'h09f2c; P_Y[30] = 18'h0ed30; P_Y[31] = 18'h04ddd;
        //
    end
    
    
    //
    // Enable, Ready
    //
    reg  ena = 1'b0;
    wire rdy;
    
    
    //
    // Settings
    //
    reg                  p_ladder_mode;
    reg [OP_ADDR_W -1:0] word_index_last;
    reg [OP_ADDR_W -1:0] word_index_last_minus1;


    //
    // Script
    //
    integer i;
    initial begin

        wait_clock_ticks(10);
        rst = 1'b0;
        wait_clock_ticks(10);
        
        word_index_last = PQ_WORD_INDEX_LAST;
        word_index_last_minus1 = word_index_last - 1'b1;
        
        p_prefill;
        
        p_ladder_mode = P_LADDER_MODE;
        
        wait_clock_ticks(10);
        
        ena = 1'b1;
        wait_clock_ticks(1);
        ena = 1'b0;
    
        while (!rdy)
            wait_clock_ticks(1);
  
        wait_clock_ticks(1000);
        p_verify_ab;
        p_verify_q;
        p_verify_m;
        p_verify_p;
    end


    //
    // Storage Interfaces
    //
    wire                    wr_wide_xy_ena;
    wire [BANK_ADDR_W -1:0] wr_wide_xy_bank;
    wire [  OP_ADDR_W -1:0] wr_wide_xy_addr;
    wire [ WORD_EXT_W -1:0] wr_wide_x_din;
    wire [ WORD_EXT_W -1:0] wr_wide_y_din;

    wire                    wr_narrow_xy_ena;
    wire [BANK_ADDR_W -1:0] wr_narrow_xy_bank;
    wire [  OP_ADDR_W -1:0] wr_narrow_xy_addr;
    wire [ WORD_EXT_W -1:0] wr_narrow_x_din;
    wire [ WORD_EXT_W -1:0] wr_narrow_y_din;

    wire                                     rd_wide_xy_ena;
    wire                                     rd_wide_xy_ena_aux;
    wire [                 BANK_ADDR_W -1:0] rd_wide_xy_bank;
    wire [                 BANK_ADDR_W -1:0] rd_wide_xy_bank_aux;
    wire [NUM_MULTS_HALF * OP_ADDR_W   -1:0] rd_wide_xy_addr;
    wire [                 OP_ADDR_W   -1:0] rd_wide_xy_addr_aux;
    wire [NUM_MULTS_HALF * WORD_EXT_W  -1:0] rd_wide_x_dout;
    wire [NUM_MULTS_HALF * WORD_EXT_W  -1:0] rd_wide_y_dout;
    wire [                 WORD_EXT_W  -1:0] rd_wide_x_dout_aux;
    wire [                 WORD_EXT_W  -1:0] rd_wide_y_dout_aux;
    
    wire                                     rd_narrow_xy_ena;
    wire [                 BANK_ADDR_W -1:0] rd_narrow_xy_bank;
    wire [                 OP_ADDR_W   -1:0] rd_narrow_xy_addr;
    wire [                 WORD_EXT_W  -1:0] rd_narrow_x_dout;
    wire [                 WORD_EXT_W  -1:0] rd_narrow_y_dout;
    
    reg                    ext_wide_xy_ena = 1'b0;
    reg [BANK_ADDR_W -1:0] ext_wide_xy_bank;
    reg [  OP_ADDR_W -1:0] ext_wide_xy_addr;
    reg [ WORD_EXT_W -1:0] ext_wide_x_din;
    reg [ WORD_EXT_W -1:0] ext_wide_y_din;

    reg                    ext_narrow_xy_ena = 1'b0;
    reg [BANK_ADDR_W -1:0] ext_narrow_xy_bank;
    reg [  OP_ADDR_W -1:0] ext_narrow_xy_addr;
    reg [ WORD_EXT_W -1:0] ext_narrow_x_din;
    reg [ WORD_EXT_W -1:0] ext_narrow_y_din;

    //
    // Recombinator Interface
    //
    wire [BANK_ADDR_W -1:0] rcmb_wide_xy_bank;
    wire [  OP_ADDR_W -1:0] rcmb_wide_xy_addr;
    wire [ WORD_EXT_W -1:0] rcmb_wide_x_dout;
    wire [ WORD_EXT_W -1:0] rcmb_wide_y_dout;
    wire                    rcmb_wide_xy_valid;

    wire [BANK_ADDR_W -1:0] rcmb_narrow_xy_bank;
    wire [  OP_ADDR_W -1:0] rcmb_narrow_xy_addr;
    wire [ WORD_EXT_W -1:0] rcmb_narrow_x_dout;
    wire [ WORD_EXT_W -1:0] rcmb_narrow_y_dout;
    wire                    rcmb_narrow_xy_valid;

    wire [BANK_ADDR_W -1:0] rcmb_final_xy_bank;
    wire [  OP_ADDR_W -1:0] rcmb_final_xy_addr;
    wire [ WORD_EXT_W -1:0] rcmb_final_x_dout;
    wire [ WORD_EXT_W -1:0] rcmb_final_y_dout;
    wire                    rcmb_final_xy_valid;

    //
    // Reductor Interface
    //
    wire [BANK_ADDR_W -1:0] rdct_wide_xy_bank;
    wire [  OP_ADDR_W -1:0] rdct_wide_xy_addr;
    wire [ WORD_EXT_W -1:0] rdct_wide_x_dout;
    wire [ WORD_EXT_W -1:0] rdct_wide_y_dout;
    wire                    rdct_wide_xy_valid;

    wire [BANK_ADDR_W -1:0] rdct_narrow_xy_bank;
    wire [  OP_ADDR_W -1:0] rdct_narrow_xy_addr;
    wire [ WORD_EXT_W -1:0] rdct_narrow_x_dout;
    wire [ WORD_EXT_W -1:0] rdct_narrow_y_dout;
    wire                    rdct_narrow_xy_valid;

    //
    // Reductor Control/Status
    //
    wire rdct_ena;
    wire rdct_rdy;
    
    //
    // UUT
    //
    modexpng_mmm_dual uut
    (
        .clk                        (clk),
        .rst_n                      (~rst),
        
        .ena                        (ena),
        .rdy                        (rdy),
        
        .ladder_mode                (p_ladder_mode),
        .word_index_last            (word_index_last),
        .word_index_last_minus1     (word_index_last_minus1),
        .force_unity_b              (1'b0),
        .only_reduce                (1'b0),
        .just_multiply              (1'b0),
        
        .sel_wide_in                (BANK_WIDE_A),
        .sel_narrow_in              (BANK_NARROW_A),
        
        .rd_wide_xy_ena             (rd_wide_xy_ena),
        .rd_wide_xy_ena_aux         (rd_wide_xy_ena_aux),
        .rd_wide_xy_bank            (rd_wide_xy_bank),
        .rd_wide_xy_bank_aux        (rd_wide_xy_bank_aux),
        .rd_wide_xy_addr            (rd_wide_xy_addr),
        .rd_wide_xy_addr_aux        (rd_wide_xy_addr_aux),
        .rd_wide_x_din              (rd_wide_x_dout),
        .rd_wide_y_din              (rd_wide_y_dout),
        .rd_wide_x_din_aux          (rd_wide_x_dout_aux),
        .rd_wide_y_din_aux          (rd_wide_y_dout_aux),

        .rd_narrow_xy_ena           (rd_narrow_xy_ena),
        .rd_narrow_xy_bank          (rd_narrow_xy_bank),
        .rd_narrow_xy_addr          (rd_narrow_xy_addr),
        .rd_narrow_x_din            (rd_narrow_x_dout),
        .rd_narrow_y_din            (rd_narrow_y_dout),
        
        .rcmb_wide_xy_bank          (rcmb_wide_xy_bank),
        .rcmb_wide_xy_addr          (rcmb_wide_xy_addr),
        .rcmb_wide_x_dout           (rcmb_wide_x_dout),
        .rcmb_wide_y_dout           (rcmb_wide_y_dout),
        .rcmb_wide_xy_valid         (rcmb_wide_xy_valid),

        .rcmb_narrow_xy_bank        (rcmb_narrow_xy_bank),
        .rcmb_narrow_xy_addr        (rcmb_narrow_xy_addr),
        .rcmb_narrow_x_dout         (rcmb_narrow_x_dout),
        .rcmb_narrow_y_dout         (rcmb_narrow_y_dout),
        .rcmb_narrow_xy_valid       (rcmb_narrow_xy_valid),
        
        .rcmb_xy_bank               (rcmb_final_xy_bank),
        .rcmb_xy_addr               (rcmb_final_xy_addr),
        .rcmb_x_dout                (rcmb_final_x_dout),
        .rcmb_y_dout                (rcmb_final_y_dout),
        .rcmb_xy_valid              (rcmb_final_xy_valid),
        
        .rdct_ena                   (rdct_ena),
        .rdct_rdy                   (rdct_rdy)
    );
    
    
    //
    // Reductor
    //    
    modexpng_reductor reductor
    (
        .clk                    (clk),
        .rst_n                  (~rst),
        
        .ena                    (rdct_ena),
        .rdy                    (rdct_rdy),
        
        .word_index_last        (word_index_last),
        
        .sel_wide_out           (BANK_WIDE_B),
        .sel_narrow_out         (BANK_NARROW_B),

        .rd_wide_x_din_aux      (rd_wide_x_dout_aux),
        .rd_wide_y_din_aux      (rd_wide_y_dout_aux),
        
        .rcmb_final_xy_bank     (rcmb_final_xy_bank),
        .rcmb_final_xy_addr     (rcmb_final_xy_addr),
        .rcmb_final_x_din       (rcmb_final_x_dout),
        .rcmb_final_y_din       (rcmb_final_y_dout),
        .rcmb_final_xy_valid    (rcmb_final_xy_valid),
        
        .rdct_wide_xy_bank      (rdct_wide_xy_bank),
        .rdct_wide_xy_addr      (rdct_wide_xy_addr),
        .rdct_wide_x_dout       (rdct_wide_x_dout),
        .rdct_wide_y_dout       (rdct_wide_y_dout),
        .rdct_wide_xy_valid     (rdct_wide_xy_valid),
        
        .rdct_narrow_xy_bank    (rdct_narrow_xy_bank),
        .rdct_narrow_xy_addr    (rdct_narrow_xy_addr),
        .rdct_narrow_x_dout     (rdct_narrow_x_dout),
        .rdct_narrow_y_dout     (rdct_narrow_y_dout),
        .rdct_narrow_xy_valid   (rdct_narrow_xy_valid)
    );

    //
    // Storage Block
    //
    modexpng_storage_block storage_block
    (
        .clk                    (clk),
        .rst_n                  (~rst),

        .wr_wide_xy_ena         (wr_wide_xy_ena),
        .wr_wide_xy_bank        (wr_wide_xy_bank),
        .wr_wide_xy_addr        (wr_wide_xy_addr),
        .wr_wide_x_din          (wr_wide_x_din),
        .wr_wide_y_din          (wr_wide_y_din),

        .wr_narrow_xy_ena       (wr_narrow_xy_ena),
        .wr_narrow_xy_bank      (wr_narrow_xy_bank),
        .wr_narrow_xy_addr      (wr_narrow_xy_addr),
        .wr_narrow_x_din        (wr_narrow_x_din),
        .wr_narrow_y_din        (wr_narrow_y_din),

        .rd_wide_xy_ena         (rd_wide_xy_ena),
        .rd_wide_xy_ena_aux     (rd_wide_xy_ena_aux),
        .rd_wide_xy_bank        (rd_wide_xy_bank),
        .rd_wide_xy_bank_aux    (rd_wide_xy_bank_aux),
        .rd_wide_xy_addr        (rd_wide_xy_addr),
        .rd_wide_xy_addr_aux    (rd_wide_xy_addr_aux),
        .rd_wide_x_dout         (rd_wide_x_dout),
        .rd_wide_y_dout         (rd_wide_y_dout),
        .rd_wide_x_dout_aux     (rd_wide_x_dout_aux),
        .rd_wide_y_dout_aux     (rd_wide_y_dout_aux),

        .rd_narrow_xy_ena       (rd_narrow_xy_ena),
        .rd_narrow_xy_bank      (rd_narrow_xy_bank),
        .rd_narrow_xy_addr      (rd_narrow_xy_addr),
        .rd_narrow_x_dout       (rd_narrow_x_dout),
        .rd_narrow_y_dout       (rd_narrow_y_dout),
        
        .wrk_wide_xy_ena        (1'b0),
        .wrk_wide_xy_bank       (),
        .wrk_wide_xy_addr       (),
        .wrk_wide_x_dout        (),
        .wrk_wide_y_dout        (),
    
        .wrk_narrow_xy_ena      (1'b0),
        .wrk_narrow_xy_bank     (),
        .wrk_narrow_xy_addr     (),
        .wrk_narrow_x_dout      (),
        .wrk_narrow_y_dout      ()
    );

    modexpng_storage_manager storage_manager
    (
        .clk                    (clk),
        .rst_n                  (~rst),
        
        .wr_wide_xy_ena         (wr_wide_xy_ena),
        .wr_wide_xy_bank        (wr_wide_xy_bank),
        .wr_wide_xy_addr        (wr_wide_xy_addr),
        .wr_wide_x_dout         (wr_wide_x_din),
        .wr_wide_y_dout         (wr_wide_y_din),
    
        .wr_narrow_xy_ena       (wr_narrow_xy_ena),
        .wr_narrow_xy_bank      (wr_narrow_xy_bank),
        .wr_narrow_xy_addr      (wr_narrow_xy_addr),
        .wr_narrow_x_dout       (wr_narrow_x_din),
        .wr_narrow_y_dout       (wr_narrow_y_din),
        
        .io_wide_xy_ena         (ext_wide_xy_ena),
        .io_wide_xy_bank        (ext_wide_xy_bank),
        .io_wide_xy_addr        (ext_wide_xy_addr),
        .io_wide_x_din          (ext_wide_x_din),
        .io_wide_y_din          (ext_wide_y_din),
    
        .io_narrow_xy_ena       (ext_narrow_xy_ena),
        .io_narrow_xy_bank      (ext_narrow_xy_bank),
        .io_narrow_xy_addr      (ext_narrow_xy_addr),
        .io_narrow_x_din        (ext_narrow_x_din),
        .io_narrow_y_din        (ext_narrow_y_din),
        
        .rcmb_wide_xy_bank      (rcmb_wide_xy_bank),
        .rcmb_wide_xy_addr      (rcmb_wide_xy_addr),
        .rcmb_wide_x_din        (rcmb_wide_x_dout),
        .rcmb_wide_y_din        (rcmb_wide_y_dout),
        .rcmb_wide_xy_ena       (rcmb_wide_xy_valid),

        .rcmb_narrow_xy_bank    (rcmb_narrow_xy_bank),
        .rcmb_narrow_xy_addr    (rcmb_narrow_xy_addr),
        .rcmb_narrow_x_din      (rcmb_narrow_x_dout),
        .rcmb_narrow_y_din      (rcmb_narrow_y_dout),
        .rcmb_narrow_xy_ena     (rcmb_narrow_xy_valid),
        
        .rdct_wide_xy_bank      (),
        .rdct_wide_xy_addr      (),
        .rdct_wide_x_din        (),
        .rdct_wide_y_din        (),
        .rdct_wide_xy_valid     (1'b0),
        
        .rdct_narrow_xy_bank    (),
        .rdct_narrow_xy_addr    (),
        .rdct_narrow_x_din      (),
        .rdct_narrow_y_din      (),
        .rdct_narrow_xy_valid   (1'b0),
    
        .wrk_wide_xy_ena        (1'b0),
        .wrk_wide_xy_bank       (),
        .wrk_wide_xy_addr       (),
        .wrk_wide_x_din         (),
        .wrk_wide_y_din         (),
        
        .wrk_narrow_xy_ena      (1'b0),
        .wrk_narrow_xy_bank     (),
        .wrk_narrow_xy_addr     (),
        .wrk_narrow_x_din       (),
        .wrk_narrow_y_din       ()
    );


    //
    // p_prefill()
    //
    task p_prefill;
        begin
        
            ext_wide_xy_ena   = 1'b1;
            ext_narrow_xy_ena = 1'b1;

            for (i=0; i<PQ_NUM_WORDS; i=i+1) begin
                ext_wide_xy_bank = BANK_WIDE_A;
                ext_wide_xy_addr = i[OP_ADDR_W-1:0];
                ext_wide_x_din   = P_T1[i];
                ext_wide_y_din   = P_T2[i];
                
                ext_narrow_xy_bank = BANK_NARROW_A;
                ext_narrow_xy_addr = i[OP_ADDR_W-1:0];
                ext_narrow_x_din   = P_T1[i];
                ext_narrow_y_din   = P_T2[i];
                
                wait_clock_tick;
            end

            for (i=0; i<PQ_NUM_WORDS; i=i+1) begin
                ext_wide_xy_bank = BANK_WIDE_N;
                ext_wide_xy_addr = i[OP_ADDR_W-1:0];
                ext_wide_x_din   = P_N[i];
                ext_wide_y_din   = P_N[i];

                ext_narrow_xy_bank = BANK_NARROW_COEFF;
                ext_narrow_xy_addr = i[OP_ADDR_W-1:0];
                ext_narrow_x_din   = P_N_COEFF[i];
                ext_narrow_y_din   = P_N_COEFF[i];
                
                wait_clock_tick;
            end

            ext_wide_xy_ena  = 1'b0;
            ext_wide_xy_bank = BANK_DNC;
            ext_wide_xy_addr = OP_ADDR_DNC;
            ext_wide_x_din   = WORD_EXT_DNC;
            ext_wide_y_din   = WORD_EXT_DNC;
            
            for (i=32; i<33; i=i+1) begin
                ext_narrow_xy_bank = BANK_NARROW_EXT;
                ext_narrow_xy_addr = OP_ADDR_EXT_COEFF;
                ext_narrow_x_din   = P_N_COEFF[i];
                ext_narrow_y_din   = P_N_COEFF[i];
                
                wait_clock_tick;
            end

            ext_narrow_xy_ena  = 1'b0;
            ext_narrow_xy_bank = BANK_DNC;
            ext_narrow_xy_addr = OP_ADDR_DNC;
            ext_narrow_x_din   = WORD_EXT_DNC;
            ext_narrow_y_din   = WORD_EXT_DNC;
                        
        end
    endtask
    
    
    //
    // wait_clock_tick()
    //
    task wait_clock_tick;
        #`CLK_PERIOD_NS;
    endtask

    
    //
    // wait_clock_ticks()
    //
    task wait_clock_ticks;
        input integer num_ticks;
        integer _n;
        for (_n=0; _n<num_ticks; _n=_n+1)
            wait_clock_tick;
    endtask

    
    //
    // Debug Interceptor
    //
    reg [WORD_EXT_W-1:0] P_X_AB_READ[0:2*PQ_NUM_WORDS-1];
    reg [WORD_EXT_W-1:0] P_Y_AB_READ[0:2*PQ_NUM_WORDS-1];
    
    reg [WORD_EXT_W-1:0] P_X_Q_READ[0:PQ_NUM_WORDS];
    reg [WORD_EXT_W-1:0] P_Y_Q_READ[0:PQ_NUM_WORDS];

    reg [WORD_EXT_W-1:0] P_X_M_READ[0:2*PQ_NUM_WORDS];
    reg [WORD_EXT_W-1:0] P_Y_M_READ[0:2*PQ_NUM_WORDS];
    
    reg [WORD_EXT_W-1:0] P_X_WIDE_READ[0:PQ_NUM_WORDS-1];
    reg [WORD_EXT_W-1:0] P_Y_WIDE_READ[0:PQ_NUM_WORDS-1];
    
    reg [WORD_EXT_W-1:0] P_X_NARROW_READ[0:PQ_NUM_WORDS-1];
    reg [WORD_EXT_W-1:0] P_Y_NARROW_READ[0:PQ_NUM_WORDS-1];
    
    integer xy_offset;
    always @(posedge clk) begin
        //
        if (rcmb_wide_xy_valid)
            //
            case (rcmb_wide_xy_bank)
                //
                BANK_WIDE_L: begin
                    //
                    xy_offset = rcmb_wide_xy_addr;
                    //
                    if (xy_offset >= PQ_NUM_WORDS) begin
                        $display("ERROR: Encountered illegal offset (%d) writing to wide bank L!", xy_offset);
                        $finish;
                    end
                    //
                    P_X_AB_READ[xy_offset] <= rcmb_wide_x_dout;
                    P_Y_AB_READ[xy_offset] <= rcmb_wide_y_dout;
                    //
                end
                //
                BANK_WIDE_H: begin
                    //
                    xy_offset = PQ_NUM_WORDS + rcmb_wide_xy_addr;
                    //
                    if (xy_offset >= 2*PQ_NUM_WORDS) begin
                        $display("ERROR: Encountered illegal offset (%d) writing to wide bank H!", xy_offset);
                        $finish;
                    end
                    //
                    P_X_AB_READ[xy_offset] <= rcmb_wide_x_dout;
                    P_Y_AB_READ[xy_offset] <= rcmb_wide_y_dout;
                    //
                end
                //
                default: begin
                    $display("ERROR: Encountered illegal wide bank (%d) while writing!", rcmb_wide_xy_bank);
                    $finish;
                end
                //
            endcase
        //
        if (rcmb_narrow_xy_valid)
            //
            case (rcmb_narrow_xy_bank)
                //
                BANK_NARROW_Q: begin
                    //
                    xy_offset = rcmb_narrow_xy_addr;
                    //
                    if (xy_offset >= PQ_NUM_WORDS) begin
                        $display("ERROR: Encountered illegal offset (%d) writing to narrow bank Q!", xy_offset);
                        $finish;
                    end
                    //
                    P_X_Q_READ[xy_offset] <= rcmb_narrow_x_dout;
                    P_Y_Q_READ[xy_offset] <= rcmb_narrow_y_dout;
                    //
                end
                //
                BANK_NARROW_EXT: begin
                    //
                    xy_offset = PQ_NUM_WORDS + rcmb_narrow_xy_addr - 1;
                    //
                    if (xy_offset != PQ_NUM_WORDS) begin
                        $display("ERROR: Encountered illegal offset (%d) writing to narrow bank EXT!", xy_offset);
                        $finish;
                    end
                    //
                    P_X_Q_READ[xy_offset] <= rcmb_narrow_x_dout;
                    P_Y_Q_READ[xy_offset] <= rcmb_narrow_y_dout;
                    //
                end
                //
                default: begin
                    $display("ERROR: Encountered illegal narrow bank (%d) while writing!", rcmb_narrow_xy_bank);
                    $finish;
                end
                //
            endcase
        //
        if (rcmb_final_xy_valid)
            //
            case (rcmb_final_xy_bank)
                //
                BANK_RCMB_ML: begin
                    //
                    xy_offset = rcmb_final_xy_addr;
                    //
                    if (xy_offset >= PQ_NUM_WORDS) begin
                        $display("ERROR: Encountered illegal offset (%d) writing to narrow bank ML!", xy_offset);
                        $finish;
                    end
                    //
                    P_X_M_READ[xy_offset] <= rcmb_final_x_dout;
                    P_Y_M_READ[xy_offset] <= rcmb_final_y_dout;
                    //
                end
                //
                BANK_RCMB_MH: begin
                    //
                    xy_offset = PQ_NUM_WORDS + rcmb_final_xy_addr;
                    //
                    if (xy_offset >= 2*PQ_NUM_WORDS) begin
                        $display("ERROR: Encountered illegal offset (%d) writing to narrow bank MH!", xy_offset);
                        $finish;
                    end
                    //
                    P_X_M_READ[xy_offset] <= rcmb_final_x_dout;
                    P_Y_M_READ[xy_offset] <= rcmb_final_y_dout;
                    //
                end
                //
                BANK_RCMB_EXT: begin
                    //
                    xy_offset = 2*PQ_NUM_WORDS + rcmb_final_xy_addr;
                    //
                    if (xy_offset != 2*PQ_NUM_WORDS) begin
                        $display("ERROR: Encountered illegal offset (%d) writing to narrow bank EXT!", xy_offset);
                        $finish;
                    end
                    //
                    P_X_M_READ[xy_offset] <= rcmb_final_x_dout;
                    P_Y_M_READ[xy_offset] <= rcmb_final_y_dout;
                    //
                end
                //
                default: begin
                    $display("ERROR: Encountered illegal narrow bank (%d) while writing!", rcmb_final_xy_bank);
                    $finish;
                end
                //
            endcase
        //
        if (rdct_narrow_xy_valid) begin
            //
            xy_offset = rdct_narrow_xy_addr;
            //
            if (xy_offset >= PQ_NUM_WORDS) begin
                $display("ERROR: Encountered illegal offset (%d) writing to narrow bank T1/T2!", xy_offset);
                $finish;
            end
            //
            P_X_NARROW_READ[xy_offset] <= rdct_narrow_x_dout;
            P_Y_NARROW_READ[xy_offset] <= rdct_narrow_y_dout;
            //
        end
        //
        if (rdct_wide_xy_valid) begin
            //
            xy_offset = rdct_wide_xy_addr;
            //
            if (xy_offset >= PQ_NUM_WORDS) begin
                $display("ERROR: Encountered illegal offset (%d) writing to wide bank T1/T2!", xy_offset);
                $finish;
            end
            //
            P_X_WIDE_READ[xy_offset] <= rdct_wide_x_dout;
            P_Y_WIDE_READ[xy_offset] <= rdct_wide_y_dout;
            //
        end        
        //        
    end

    task p_verify_ab;
        //
        reg verify_x_ab_ok;
        reg verify_y_ab_ok;
        //
        begin
            //
            verify_x_ab_ok = 1;
            verify_y_ab_ok = 1;
            //
            for (i=0; i<2*PQ_NUM_WORDS; i=i+1) begin
                if (P_X_AB_READ[i] !== P_X_AB[i]) verify_x_ab_ok = 0;
                if (P_Y_AB_READ[i] !== P_Y_AB[i]) verify_y_ab_ok = 0;
            end
            //    
            if (!verify_x_ab_ok)
                for (i=0; i<2*PQ_NUM_WORDS; i=i+1)
                    if (P_X_AB_READ[i] === P_X_AB[i]) $display("P_X_AB / P_X_AB_READ [%02d] = 0x%05x / 0x%05x",       i, P_X_AB[i], P_X_AB_READ[i]);
                    else                              $display("P_X_AB / P_X_AB_READ [%02d] = 0x%05x / 0x%05x <???>", i, P_X_AB[i], P_X_AB_READ[i]);
            //
            if (!verify_y_ab_ok)
                for (i=0; i<2*PQ_NUM_WORDS; i=i+1)
                    if (P_Y_AB_READ[i] === P_Y_AB[i]) $display("P_Y_AB / P_Y_AB_READ [%02d] = 0x%05x / 0x%05x",       i, P_Y_AB[i], P_Y_AB_READ[i]);
                    else                              $display("P_Y_AB / P_Y_AB_READ [%02d] = 0x%05x / 0x%05x <???>", i, P_Y_AB[i], P_Y_AB_READ[i]);
            //
            if (verify_x_ab_ok) $display("P_X_AB is OK.");
            else                $display("P_X_AB is WRONG!");
            //
            if (verify_y_ab_ok) $display("P_Y_AB is OK.");
            else                $display("P_Y_AB is WRONG!");
            //
        end
        //
    endtask
    
    task p_verify_q;
        //
        reg verify_x_q_ok;
        reg verify_y_q_ok;
        //
        begin
            //
            verify_x_q_ok = 1;
            verify_y_q_ok = 1;
            //
            for (i=0; i<(PQ_NUM_WORDS+1); i=i+1) begin
                if (P_X_Q_READ[i] !== P_X_Q[i]) verify_x_q_ok = 0;
                if (P_Y_Q_READ[i] !== P_Y_Q[i]) verify_y_q_ok = 0;
            end
            //    
            if (!verify_x_q_ok)
                for (i=0; i<(PQ_NUM_WORDS+1); i=i+1)
                    if (P_X_Q_READ[i] === P_X_Q[i]) $display("P_X_Q / P_X_Q_READ [%02d] = 0x%05x / 0x%05x",       i, P_X_Q[i], P_X_Q_READ[i]);
                    else                            $display("P_X_Q / P_X_Q_READ [%02d] = 0x%05x / 0x%05x <???>", i, P_X_Q[i], P_X_Q_READ[i]);
            //
            if (!verify_y_q_ok)
                for (i=0; i<(PQ_NUM_WORDS+1); i=i+1)
                    if (P_Y_Q_READ[i] === P_Y_Q[i]) $display("P_Y_Q / P_Y_Q_READ [%02d] = 0x%05x / 0x%05x",       i, P_Y_Q[i], P_Y_Q_READ[i]);
                    else                            $display("P_Y_Q / P_Y_Q_READ [%02d] = 0x%05x / 0x%05x <???>", i, P_Y_Q[i], P_Y_Q_READ[i]);
            //
            if (verify_x_q_ok) $display("P_X_Q is OK.");
            else               $display("P_X_Q is WRONG!");
            //
            if (verify_y_q_ok) $display("P_Y_Q is OK.");
            else               $display("P_Y_Q is WRONG!");
            //
        end
        //
    endtask

    task p_verify_m;
        //
        reg verify_x_m_ok;
        reg verify_y_m_ok;
        //
        begin
            //
            verify_x_m_ok = 1;
            verify_y_m_ok = 1;
            //
            for (i=0; i<(2*PQ_NUM_WORDS+1); i=i+1) begin
                if (P_X_M_READ[i] !== P_X_M[i]) verify_x_m_ok = 0;
                if (P_Y_M_READ[i] !== P_Y_M[i]) verify_y_m_ok = 0;
            end
            //    
            if (!verify_x_m_ok)
                for (i=0; i<(2*PQ_NUM_WORDS+1); i=i+1)
                    if (P_X_M_READ[i] === P_X_M[i]) $display("P_X_M / P_X_M_READ [%02d] = 0x%05x / 0x%05x",       i, P_X_M[i], P_X_M_READ[i]);
                    else                            $display("P_X_M / P_X_M_READ [%02d] = 0x%05x / 0x%05x <???>", i, P_X_M[i], P_X_M_READ[i]);
            //
            if (!verify_y_m_ok)
                for (i=0; i<(2*PQ_NUM_WORDS+1); i=i+1)
                    if (P_Y_M_READ[i] === P_Y_M[i]) $display("P_Y_M / P_Y_M_READ [%02d] = 0x%05x / 0x%05x",       i, P_Y_M[i], P_Y_M_READ[i]);
                    else                            $display("P_Y_M / P_Y_M_READ [%02d] = 0x%05x / 0x%05x <???>", i, P_Y_M[i], P_Y_M_READ[i]);
            //
            if (verify_x_m_ok) $display("P_X_M is OK.");
            else               $display("P_X_M is WRONG!");
            //
            if (verify_y_m_ok) $display("P_Y_M is OK.");
            else               $display("P_Y_M is WRONG!");
            //
        end
        //
    endtask
    
  task p_verify_p;
        //
        reg verify_x_wide_ok;
        reg verify_y_wide_ok;
        reg verify_x_narrow_ok;
        reg verify_y_narrow_ok;
        //
        begin
            //
            verify_x_wide_ok = 1;
            verify_y_wide_ok = 1;
            verify_x_narrow_ok = 1;
            verify_y_narrow_ok = 1;
            //
            for (i=0; i<PQ_NUM_WORDS; i=i+1) begin
                if (P_X_WIDE_READ[i] !== P_X[i]) verify_x_wide_ok = 0;
                if (P_Y_WIDE_READ[i] !== P_Y[i]) verify_y_wide_ok = 0;
                if (P_X_NARROW_READ[i] !== P_X[i]) verify_x_narrow_ok = 0;
                if (P_Y_NARROW_READ[i] !== P_Y[i]) verify_y_narrow_ok = 0;
            end
            //
            if (!verify_x_wide_ok || !verify_x_narrow_ok)
                for (i=0; i<PQ_NUM_WORDS; i=i+1)
                    if ((P_X_WIDE_READ[i] === P_X[i]) && (P_X_NARROW_READ[i] === P_X[i])) $display("P_X / P_X_WIDE / P_X_NARROW [%02d] = 0x%05x / 0x%05x / 0x%05x",       i, P_X[i], P_X_WIDE_READ[i], P_X_NARROW_READ[i]);
                    else                                                                  $display("P_X / P_X_WIDE / P_X_NARROW [%02d] = 0x%05x / 0x%05x / 0x%05x <???>", i, P_X[i], P_X_WIDE_READ[i], P_X_NARROW_READ[i]);
            //
            if (!verify_y_wide_ok || !verify_y_narrow_ok)
                for (i=0; i<PQ_NUM_WORDS; i=i+1)
                    if ((P_Y_WIDE_READ[i] === P_Y[i]) && (P_Y_NARROW_READ[i] === P_Y[i])) $display("P_Y / P_Y_WIDE / P_Y_NARROW [%02d] = 0x%05x / 0x%05x / 0x%05x",       i, P_Y[i], P_Y_WIDE_READ[i], P_Y_NARROW_READ[i]);
                    else                                                                  $display("P_Y / P_Y_WIDE / P_Y_NARROW [%02d] = 0x%05x / 0x%05x / 0x%05x <???>", i, P_Y[i], P_Y_WIDE_READ[i], P_Y_NARROW_READ[i]);
            //
            if (verify_x_wide_ok && verify_x_narrow_ok) $display("P_X is OK.");
            else                                        $display("P_X is WRONG!");
            //
            if (verify_y_wide_ok && verify_y_narrow_ok) $display("P_Y is OK.");
            else                                        $display("P_Y is WRONG!");
            //
        end
        //
    endtask
    
endmodule