// AN9238 virtual ADC model (1 port) module virtual_adc_model #( parameter int unsigned ADC_DATA_WIDTH = 12, // Bipolar input range: +/- VOLTAGE_RANGE parameter real VOLTAGE_RANGE = 1.0, // Analog input correction parameter real VOLTAGE_GAIN = 0.2, parameter real GROUND_BIAS = 0.0, // ADC timing parameters parameter time CONVERSION_DELAY = 250ps )( input logic clk_i, input real voltage_i, output logic otr_o, output logic [ADC_DATA_WIDTH-1:0] data_o ); localparam int unsigned ZERO_CODE = (1 << (ADC_DATA_WIDTH - 1)); localparam real VOLTAGE_STEP = (2 * VOLTAGE_RANGE) / real'((1 << ADC_DATA_WIDTH) - 1); real voltage_corrected; //------------------------------------------------------------ // Convert analog voltage to ADC code //------------------------------------------------------------ function automatic logic [ADC_DATA_WIDTH-1:0] voltage_to_code( input real voltage ); if (voltage <= -VOLTAGE_RANGE) return '0; if (voltage >= VOLTAGE_RANGE) return {ADC_DATA_WIDTH{1'b1}}; return $rtoi(voltage / VOLTAGE_STEP + real'((ZERO_CODE)) + 0.5); endfunction function automatic logic range_check( input real voltage ); real v_abs = (voltage < 0.0) ? -voltage : voltage; return v_abs >= VOLTAGE_RANGE; endfunction //------------------------------------------------------------ // Initial state //------------------------------------------------------------ initial begin data_o = ZERO_CODE; // 0V otr_o = 0; end //------------------------------------------------------------ // Update analog output //------------------------------------------------------------ always @(posedge clk_i) begin voltage_corrected = (voltage_i - GROUND_BIAS) * VOLTAGE_GAIN; data_o <= #(CONVERSION_DELAY) voltage_to_code(voltage_corrected); otr_o <= #(CONVERSION_DELAY) range_check(voltage_corrected); end endmodule