```////////////////////////////////////////////////////////////////////////////////
//
/// LSU EE 4755 Fall 2016 Homework 2 -- SOLUTION
//

/// Assignment  http://www.ece.lsu.edu/koppel/v/2016/hw02.pdf

`default_nettype none

//////////////////////////////////////////////////////////////////////////////
///  Problem 1
//
/// Modify aa_digit_val so that it works for any radix, not just 10.
//
//     [✔] The code must be synthesizable.
//     [✔] Can use behavioral or implicit structural code.

module aa_decimal_digit_val
( output uwire [3:0] val,
output uwire is_dig,
input uwire [7:0] char );

// Do not edit this module.

assign       is_dig = char >= "0" && char <= "9";
assign       val = is_dig ? char - "0" : 0;

endmodule

module aa_digit_val
#( int radix = 10 )
( output uwire [3:0] val,
output uwire is_dig,
input uwire [7:0] char );

/// SOLUTION

// Check whether char is in range 0-9 or a-f, regardless of radix.
//
uwire  is_dig_09 = char >= "0" && char <= "9";
uwire  is_dig_af = char >= "a" && char <= "f";

// Convert char to binary, assuming that it is hexadecimal.
//
uwire [3:0] val_raw = is_dig_09 ? char - "0" : char - "a" + 10;

//
assign     is_dig = ( is_dig_09 || is_dig_af ) && val_raw < radix;

assign     val = is_dig ? val_raw : 0;

endmodule

//////////////////////////////////////////////////////////////////////////////
///  Problem 2
//
//
//     [✔] The code must be synthesizable.
//     [✔] Can use behavioral or implicit structural code.

#( int radix = 10 )
( output uwire [7:0] sum,
output uwire carry_out,
output uwire is_dig_out,
input uwire [7:0] a, b,
input uwire carry_in,
input uwire is_dig_in);

/// SOLUTION

// Instantiate two aa_digit_val modules, connecting one to each
// input digit. These will determine whether each character input
// is a valid digit and if so provide the binary value of the
// digit.
//
uwire [3:0] val_a, val_b;
uwire       is_dig_a, is_dig_b;

// Compute the sum of carry_in and the binary versions of a and
// b. Note that the sum may contain a carry, and so it can not be
// assigned to the module output.
//
uwire [4:0] sum_val = carry_in + val_a + val_b;

// Determine whether there is a carry out.
//
assign     carry_out = sum_val >= radix;

// Determine the sum, in binary, with the carry removed.
//
uwire [3:0] sum_dig_val = carry_out ? sum_val - radix : sum_val;

// Convert the sum to ASCII or to a blank if we don't have a valid digit.
//
assign sum = !is_dig_out ? " " :
sum_dig_val < 10 ? "0" + sum_dig_val : "a" + sum_dig_val - 10;

// If the value of is_dig_out, below, is true then output sum will
// be set to a digit of the sum. Otherwise sum should be set to a
// blank. The value of is_dig_out will be false when we are past
// the last digit of both a and b, and we don't have a carry out
// from the previous digit.
//
assign is_dig_out = is_dig_in && ( carry_in || is_dig_a || is_dig_b );

endmodule

module aa_width2
#( int radix = 10 )
( output uwire [1:0][7:0] sum,
output uwire c_out,
output uwire is_dig_out,
input uwire [1:0][7:0] a, b,
input uwire c_in,
input uwire is_dig_in);

uwire   co0, id_0;

endmodule

int digits = 2,
int width = \$clog2( radix ** digits ) )
( output logic [width-1:0] sum,
output logic carry_out,
input uwire [width-1:0] a, b,
input uwire carry_in );

always_comb { carry_out, sum } = 0 + carry_in + a + b;

endmodule

//////////////////////////////////////////////////////////////////////////////
/// Testbench Code
//
//  The code below instantiates some of the modules above,
//  provides test inputs, and verifies the outputs.
//
//  The testbench may be modified to facilitate your solution. Of
//  course, the removal of tests which your module fails is not a
//  method of fixing a broken module. (One might modify the testbench
//  so that the first tests it performs are thoe which make it easier
//  to determine what the problem is, for example, test inputs that
//  are all 0's or all 1's.)

begin
while ( 1 )
begin
automatic int dig = a % radix;
if ( radtos.len() > 0 && a == 0 ) break;
radtos = { dig < 10 ? "0" + dig : "a" + dig - 10, radtos };
end
end
endfunction

module aa_test;

logic start_done[32];

initial begin

start_done[1] = 1;

end

endmodule

module aa_test_digit_val #( int radix = 10 )
( output logic done, input uwire start );

localparam int err_limit = 10;

logic [7:0] a;
uwire [3:0]  dval;
uwire        is_d;

int digit_vals[256];

int num_errs;

initial begin
num_errs = 0;

wait ( start == 1 );

digit_vals = { 256 { -1 } };
for ( int i=0; i<radix; i++ )
digit_vals[ i < 10 ? "0" + i : "a" + i - 10 ] = i;

for ( int i=0; i<256; i++ )
begin
automatic bit is_d_shadow = digit_vals[i] >= 0 ;
#1;
a = i;
#1;
if ( is_d != is_d_shadow ) begin
\$write
("Error in aa_digit_val for char %c (%0d) radix %0d, is_d %0d != %0d (correct)\n",
num_errs++;
if ( num_errs > err_limit ) \$finish(2);
continue;
end
if ( is_d_shadow && dval != digit_vals[i] ) begin
\$write
("Error in aa_digit_val for char %c (%0d) radix %0d: val %0d != %0d (correct)\n",
num_errs++;
if ( num_errs > err_limit ) \$finish(2);
continue;
end

end

done = 1;

end

endmodule

module aa_test_width2 #( int radix = 10 )
( output logic done, input uwire start );

localparam int err_limit = 10;
localparam int max_digits = 2;
localparam int max_dno = max_digits - 1;
localparam int num_tests = 100;

uwire [max_dno:0][7:0] sum;
uwire        co;
logic       fo, ci, fi;

int unsigned aval, bval, ssum_val;

int num_errs;

initial begin
num_errs = 0;

wait ( start == 1 );

for ( int i=0; i<num_tests; i++ )
begin
automatic int width = max_digits;
aval = {\$random()} >> 1;
bval = {\$random()} >> 1;
ssum_val = aval + bval;
ci = 0;
fi = 1;
#1;

if ( sum !== shadow_sum ) begin

\$write("Error %s + %s != %s (%s correct).\n",
num_errs++;
if ( num_errs > err_limit ) \$finish(2);

end

#1;

end

done = 1;

end

endmodule