1`include "mrfm.vh"
2
3module mrfm_iir (input clock, input reset, input strobe_in,
4		 input serial_strobe, input [6:0] serial_addr, input [31:0] serial_data,
5		 input wire [15:0] sample_in, output reg [15:0] sample_out);
6
7   wire [5:0] 	       coeff_addr, coeff_wr_addr;
8   wire [4:0] 	       data_addr, data_wr_addr;
9   reg [4:0] 	       cur_offset, data_addr_int, data_wr_addr_int;
10
11   wire [15:0] 	       coeff, coeff_wr_data, data, data_wr_data;
12   wire 	       coeff_wr;
13   reg 		       data_wr;
14
15   wire [30:0] 	       product;
16   wire [33:0] 	       accum;
17   wire [15:0] 	       scaled_accum;
18
19   wire [7:0] 	       shift;
20   reg [5:0] 	       phase;
21   wire 	       enable_mult, enable_acc, latch_out, select_input;
22   reg 		       done, clear_acc;
23
24   setting_reg #(`FR_MRFM_IIR_COEFF) sr_coeff(.clock(clock),.reset(reset),
25					      .strobe(serial_strobe),.addr(serial_addr),.in(serial_data),
26					      .out({coeff_wr_addr,coeff_wr_data}),.changed(coeff_wr));
27
28   setting_reg #(`FR_MRFM_IIR_SHIFT) sr_shift(.clock(clock),.reset(reset),
29					      .strobe(serial_strobe),.addr(serial_addr),.in(serial_data),
30					      .out(shift),.changed());
31
32   ram64 coeff_ram(.clock(clock),.write(coeff_wr),.wr_addr(coeff_wr_addr),.wr_data(coeff_wr_data),
33		   .rd_addr(coeff_addr),.rd_data(coeff));
34
35   ram32 data_ram(.clock(clock),.write(data_wr),.wr_addr(data_wr_addr),.wr_data(data_wr_data),
36		  .rd_addr(data_addr),.rd_data(data));
37
38   mult mult (.clock(clock),.x(data),.y(coeff),.product(product),.enable_in(enable_mult),.enable_out() );
39
40   acc acc (.clock(clock),.reset(reset),.clear(clear_acc),.enable_in(enable_acc),.enable_out(),
41	    .addend(product),.sum(accum) );
42
43   shifter shifter (.in(accum),.out(scaled_accum),.shift(shift));
44
45   assign 	       data_wr_data = select_input ? sample_in : scaled_accum;
46   assign 	       enable_mult = 1'b1;
47
48   always @(posedge clock)
49     if(reset)
50       cur_offset <= #1 5'd0;
51     else if(latch_out)
52       cur_offset <= #1 cur_offset + 5'd1;
53
54   assign 	       data_addr = data_addr_int + cur_offset;
55   assign 	       data_wr_addr = data_wr_addr_int + cur_offset;
56
57   always @(posedge clock)
58     if(reset)
59       done <= #1 1'b0;
60     else if(latch_out)
61       done <= #1 1'b1;
62     else if(strobe_in)
63       done <= #1 1'b0;
64
65   always @(posedge clock)
66     if(reset)
67       phase <= #1 6'd0;
68     else if(strobe_in)
69       phase <= #1 6'd0;
70     else if(!done)
71       phase <= #1 phase + 6'd1;
72
73   always @(phase)
74     case(phase)
75       6'd0 : data_addr_int = 5'd0;
76       default : data_addr_int = 5'd0;
77     endcase // case(phase)
78
79   assign 	       coeff_addr = phase;
80
81   always @(phase)
82     case(phase)
83       6'd01 : data_addr_int = 5'd00; 6'd02 : data_addr_int = 5'd01; 6'd03 : data_addr_int = 5'd02;
84       6'd04 : data_addr_int = 5'd03; 6'd05 : data_addr_int = 5'd04;
85
86       6'd07 : data_addr_int = 5'd03; 6'd08 : data_addr_int = 5'd04; 6'd09 : data_addr_int = 5'd05;
87       6'd10 : data_addr_int = 5'd06; 6'd11 : data_addr_int = 5'd07;
88
89       6'd13 : data_addr_int = 5'd06; 6'd14 : data_addr_int = 5'd07; 6'd15 : data_addr_int = 5'd08;
90       6'd16 : data_addr_int = 5'd09; 6'd17 : data_addr_int = 5'd10;
91
92       6'd19 : data_addr_int = 5'd09; 6'd20 : data_addr_int = 5'd10; 6'd21 : data_addr_int = 5'd11;
93       6'd22 : data_addr_int = 5'd12; 6'd23 : data_addr_int = 5'd13;
94
95       6'd25 : data_addr_int = 5'd12; 6'd26 : data_addr_int = 5'd13; 6'd27 : data_addr_int = 5'd14;
96       6'd28 : data_addr_int = 5'd15; 6'd29 : data_addr_int = 5'd16;
97
98       6'd31 : data_addr_int = 5'd15; 6'd32 : data_addr_int = 5'd16; 6'd33 : data_addr_int = 5'd17;
99       6'd34 : data_addr_int = 5'd18; 6'd35 : data_addr_int = 5'd19;
100
101       default : data_addr_int = 5'd00;
102     endcase // case(phase)
103
104   always @(phase)
105     case(phase)
106       6'd0 : data_wr_addr_int = 5'd2;
107       6'd8 : data_wr_addr_int = 5'd5;
108       6'd14 : data_wr_addr_int = 5'd8;
109       6'd20 : data_wr_addr_int = 5'd11;
110       6'd26 : data_wr_addr_int = 5'd14;
111       6'd32 : data_wr_addr_int = 5'd17;
112       6'd38 : data_wr_addr_int = 5'd20;
113       default : data_wr_addr_int = 5'd0;
114     endcase // case(phase)
115
116   always @(phase)
117     case(phase)
118       6'd0, 6'd8, 6'd14, 6'd20, 6'd26, 6'd32, 6'd38: data_wr = 1'b1;
119       default : data_wr = 1'b0;
120     endcase // case(phase)
121
122   always @(phase)
123     case(phase)
124       6'd0, 6'd1, 6'd2, 6'd3, 6'd9, 6'd15, 6'd21, 6'd27, 6'd33 : clear_acc = 1'd1;
125       default : clear_acc = 1'b0;
126     endcase // case(phase)
127
128   assign 	       enable_acc = ~clear_acc;
129   assign 	       latch_out = (phase == 6'd38);
130
131   always @(posedge clock)
132     if(reset)
133       sample_out <= #1 16'd0;
134     else if(latch_out)
135       sample_out <= #1 scaled_accum;
136
137endmodule // mrfm_iir
138