1use std::fmt::Write;
2
3#[derive(Debug)]
4pub enum CsdMultiplierError {
5 InvalidCharacter,
6 LengthMismatch,
7}
8
9pub struct CsdMultiplier {
10 csd: String,
11 n: usize,
12 m: usize,
13}
14
15impl CsdMultiplier {
16 pub fn new(csd: &str, n: usize, m: usize) -> Result<Self, CsdMultiplierError> {
17 if !csd.chars().all(|c| matches!(c, '+' | '-' | '0')) {
19 return Err(CsdMultiplierError::InvalidCharacter);
20 }
21
22 if csd.len() != m + 1 {
24 return Err(CsdMultiplierError::LengthMismatch);
25 }
26
27 Ok(Self {
28 csd: csd.to_string(),
29 n,
30 m,
31 })
32 }
33
34 fn decimal_value(&self) -> i32 {
36 self.csd.chars().fold(0, |acc, c| {
37 let acc = acc << 1;
38 match c {
39 '+' => acc + 1,
40 '-' => acc - 1,
41 '0' => acc,
42 _ => unreachable!(),
43 }
44 })
45 }
46
47 pub fn generate_verilog(&self) -> String {
49 let mut output = String::new();
50 self.generate_header(&mut output);
51 self.generate_wires(&mut output);
52 self.generate_result(&mut output);
53 writeln!(output, "endmodule").unwrap();
54 output
55 }
56
57 fn generate_header(&self, output: &mut String) {
58 writeln!(
59 output,
60 "// CSD Multiplier for pattern: {} (value: {})",
61 self.csd,
62 self.decimal_value()
63 )
64 .unwrap();
65
66 writeln!(
67 output,
68 "module csd_multiplier (
69 input signed [{}:0] x, // Input value (signed)
70 output signed [{}:0] result // Result (signed)
71);",
72 self.n - 1,
73 self.n + self.m - 1
74 )
75 .unwrap();
76 }
77
78 fn get_terms(&self) -> Vec<(usize, char)> {
79 self.csd
80 .chars()
81 .enumerate()
82 .filter_map(|(i, c)| {
83 let power = self.m - i;
84 match c {
85 '+' => Some((power, '+')),
86 '-' => Some((power, '-')),
87 '0' => None,
88 _ => unreachable!(),
89 }
90 })
91 .collect()
92 }
93
94 fn generate_wires(&self, output: &mut String) {
95 let terms = self.get_terms();
96 if terms.is_empty() {
97 return;
98 }
99
100 let shift_powers: Vec<_> = {
101 let mut powers: Vec<_> = terms.iter().map(|(p, _)| *p).collect();
102 powers.sort_by(|a, b| b.cmp(a)); powers.dedup();
104 powers
105 };
106
107 writeln!(
108 output,
109 "\n // Signed shifted versions (Verilog handles sign extension)"
110 )
111 .unwrap();
112
113 for &power in &shift_powers {
114 let padding = self.m - power;
115 writeln!(
116 output,
117 " wire signed [{}:0] x_shift{} = $signed({{ {{{}{{x[{}]}}}}, x}}) << {};",
118 self.n + self.m - 1,
119 power,
120 padding,
121 self.n - 1,
122 power
123 )
124 .unwrap();
125 }
126 }
127
128 fn generate_result(&self, output: &mut String) {
129 writeln!(output, "\n // CSD implementation with signed arithmetic").unwrap();
130 let terms = self.get_terms();
131
132 if terms.is_empty() {
133 writeln!(output, " assign result = 0;").unwrap();
134 } else {
135 let (first_power, first_op) = terms[0];
136 let mut expr = format!("{}x_shift{}", first_op, first_power);
137
138 for (power, op) in &terms[1..] {
139 expr.push_str(&format!(" {} x_shift{}", op, power));
140 }
141
142 writeln!(output, " assign result = {};", expr.replace("+", "")).unwrap();
143 }
144 }
145}
146
147#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn test_valid_csd() {
163 let csd = "+00-00+0+";
164 let multiplier = CsdMultiplier::new(csd, 8, 8).unwrap();
165 assert_eq!(multiplier.decimal_value(), 229);
166 }
167
168 #[test]
169 fn test_invalid_csd_chars() {
170 let csd = "+01-00+0+";
171 let result = CsdMultiplier::new(csd, 8, 6);
172 assert!(matches!(result, Err(CsdMultiplierError::InvalidCharacter)));
173 }
174
175 #[test]
176 fn test_length_mismatch() {
177 let csd = "+00-00+0+";
178 let result = CsdMultiplier::new(csd, 8, 5);
179 assert!(matches!(result, Err(CsdMultiplierError::LengthMismatch)));
180 }
181
182 #[test]
183 fn test_verilog_generation() {
184 let csd = "+0-";
185 let n = 8;
186 let m = 2;
187 let multiplier = CsdMultiplier::new(csd, n, m).unwrap();
188 let expected_verilog = r###"// CSD Multiplier for pattern: +0- (value: 3)
189module csd_multiplier (
190 input signed [7:0] x, // Input value (signed)
191 output signed [9:0] result // Result (signed)
192);
193
194 // Signed shifted versions (Verilog handles sign extension)
195 wire signed [9:0] x_shift2 = $signed({ {0{x[7]}}, x}) << 2;
196 wire signed [9:0] x_shift0 = $signed({ {2{x[7]}}, x}) << 0;
197
198 // CSD implementation with signed arithmetic
199 assign result = x_shift2 - x_shift0;
200endmodule
201"###;
202 assert_eq!(multiplier.generate_verilog(), expected_verilog);
203 }
204}