<commit_before>#include "TMC2130Stepper.h"
#include "TMC2130Stepper_MACROS.h"

#ifdef ARDUINO_SAM_ARCHIM
	#include "SW_SPI.h"
	SW_SPI TMC_SPI = SW_SPI(); // Default: MOSI=28, MISO=26, SCK=27
#else
	#include <SPI.h>
	#define TMC_SPI SPI
#endif

TMC2130Stepper::TMC2130Stepper(uint8_t pinEN, uint8_t pinDIR, uint8_t pinStep, uint8_t pinCS) {
	_started = false;

	this->_pinEN = pinEN;
	this->_pinDIR = pinDIR;
	this->_pinSTEP = pinStep;
	this->_pinCS = pinCS;

	begin();
}

void TMC2130Stepper::begin() {
#ifdef TMC2130DEBUG
	Serial.println("TMC2130 Stepper driver library");
	Serial.print("Enable pin: ");
	Serial.println(_pinEN);
	Serial.print("Direction pin: ");
	Serial.println(_pinDIR);
	Serial.print("Step pin: ");
	Serial.println(_pinSTEP);
	Serial.print("Chip select pin: ");
	Serial.println(_pinCS);
#endif
	//set pins
	pinMode(_pinEN, OUTPUT);
	pinMode(_pinDIR, OUTPUT);
	pinMode(_pinSTEP, OUTPUT);
	pinMode(_pinCS, OUTPUT);
	digitalWrite(_pinEN, HIGH); //deactivate driver (LOW active)
	digitalWrite(_pinDIR, LOW); //LOW or HIGH
	digitalWrite(_pinSTEP, LOW);
	digitalWrite(_pinCS, HIGH);
/*
	pinMode(MOSI, OUTPUT);
	pinMode(MISO, INPUT);
	pinMode(SCK, OUTPUT);
	digitalWrite(MOSI, LOW);
	digitalWrite(MISO, HIGH);
	digitalWrite(SCK, LOW);

	SPI.begin();
*/
	GCONF(GCONF_sr);
	CHOPCONF(CHOPCONF_sr);
	COOLCONF(COOLCONF_sr);
	PWMCONF(PWMCONF_sr);
	IHOLD_IRUN(IHOLD_IRUN_sr);

	toff(8); //off_time(8);
	tbl(1); //blank_time(24);

	_started = true;
}

//uint32_t TMC2130Stepper::send2130(uint8_t addressByte, uint32_t *config, uint32_t value, uint32_t mask) {
void TMC2130Stepper::send2130(uint8_t addressByte, uint32_t *config) {
	//uint8_t s;
	TMC_SPI.begin();
	#ifndef ARDUINO_SAM_ARCHIM
		TMC_SPI.beginTransaction(SPISettings(16000000/8, MSBFIRST, SPI_MODE3));
	#endif
	digitalWrite(_pinCS, LOW);

	status_response = TMC_SPI.transfer(addressByte & 0xFF); // s =
	#ifdef TMC2130DEBUG
		Serial.println("## Received parameters:");
		Serial.print("## Address byte: ");
		Serial.println(addressByte, HEX);
		Serial.print("## Config: ");
		Serial.println(*config, BIN);
		Serial.print("## status_response: ");
		Serial.println(status_response, BIN);
	#endif

	if (addressByte >> 7) { // Check if WRITE command
		//*config &= ~mask; // Clear bits being set
		//*config |= (value & mask); // Set new values
		TMC_SPI.transfer((*config >> 24) & 0xFF);
		TMC_SPI.transfer((*config >> 16) & 0xFF);
		TMC_SPI.transfer((*config >>  8) & 0xFF);
		TMC_SPI.transfer(*config & 0xFF);
		#ifdef TMC2130DEBUG
			Serial.println("## WRITE cmd");
			Serial.println("##########################");
		#endif
	} else { // READ command
		TMC_SPI.transfer16(0x0000); // Clear SPI
		TMC_SPI.transfer16(0x0000);
		digitalWrite(_pinCS, HIGH);
		digitalWrite(_pinCS, LOW);

		TMC_SPI.transfer(addressByte & 0xFF); // Send the address byte again
		*config  = TMC_SPI.transfer(0x00);
		*config <<= 8;
		*config |= TMC_SPI.transfer(0x00);
		*config <<= 8;
		*config |= TMC_SPI.transfer(0x00);
		*config <<= 8;
		*config |= TMC_SPI.transfer(0x00);
		#ifdef TMC2130DEBUG
			Serial.println("## READ cmd");
			Serial.print("## Received config: ");
			Serial.println(*config, BIN);
			Serial.println("##########################");
		#endif
	}

	digitalWrite(_pinCS, HIGH);
	TMC_SPI.endTransaction();

	//return s;
}

bool TMC2130Stepper::checkOT() {
	uint32_t response = DRV_STATUS();
	if (response & OTPW_bm) {
		flag_otpw = 1;
		return true; // bit 26 for overtemperature warning flag
	}
	return false;
}

bool TMC2130Stepper::getOTPW() { return flag_otpw; }

void TMC2130Stepper::clear_otpw() {	flag_otpw = 0; }

bool TMC2130Stepper::isEnabled() { return !digitalRead(_pinEN) && toff(); }

///////////////////////////////////////////////////////////////////////////////////////
// R+C: GSTAT
void 	TMC2130Stepper::GSTAT(uint8_t input){
	GSTAT_sr = input;
	WRITE_REG(GSTAT);
}
uint8_t TMC2130Stepper::GSTAT()			 	{ READ_REG_R(GSTAT); 		}
bool 	TMC2130Stepper::reset()				{ GET_BYTE(GSTAT, RESET);	}
bool 	TMC2130Stepper::drv_err()			{ GET_BYTE(GSTAT, DRV_ERR);	}
bool 	TMC2130Stepper::uv_cp()				{ GET_BYTE(GSTAT, UV_CP);	}
///////////////////////////////////////////////////////////////////////////////////////
// R: IOIN
uint32_t 	TMC2130Stepper::IOIN() 			{ READ_REG_R(IOIN); 				}
bool 		TMC2130Stepper::step()			{ GET_BYTE_R(IOIN, STEP);			}
bool 		TMC2130Stepper::dir()			{ GET_BYTE_R(IOIN, DIR);			}
bool 		TMC2130Stepper::dcen_cfg4()		{ GET_BYTE_R(IOIN, DCEN_CFG4);		}
bool 		TMC2130Stepper::dcin_cfg5()		{ GET_BYTE_R(IOIN, DCIN_CFG5);		}
bool 		TMC2130Stepper::drv_enn_cfg6()	{ GET_BYTE_R(IOIN, DRV_ENN_CFG6);	}
bool 		TMC2130Stepper::dco()			{ GET_BYTE_R(IOIN, DCO);			}
uint8_t 	TMC2130Stepper::version() 		{ GET_BYTE_R(IOIN, VERSION);		}
///////////////////////////////////////////////////////////////////////////////////////
// W: TPOWERDOWN
uint32_t TMC2130Stepper::TPOWERDOWN() { return TPOWERDOWN_sr; }
void TMC2130Stepper::TPOWERDOWN(uint32_t input) {
	TPOWERDOWN_sr = input;
	WRITE_REG(TPOWERDOWN);
}
///////////////////////////////////////////////////////////////////////////////////////
// R: TSTEP
uint32_t TMC2130Stepper::TSTEP() { READ_REG_R(TSTEP); }
///////////////////////////////////////////////////////////////////////////////////////
// W: TPWMTHRS
uint32_t TMC2130Stepper::TPWMTHRS() { return TPWMTHRS_sr; }
void TMC2130Stepper::TPWMTHRS(uint32_t input) {
	TPWMTHRS_sr = input;
	WRITE_REG(TPWMTHRS);
}
///////////////////////////////////////////////////////////////////////////////////////
// W: TCOOLTHRS
uint32_t TMC2130Stepper::TCOOLTHRS() { return TCOOLTHRS_sr; }
void TMC2130Stepper::TCOOLTHRS(uint32_t input) {
	TCOOLTHRS_sr = input;
	WRITE_REG(TCOOLTHRS);
}
///////////////////////////////////////////////////////////////////////////////////////
// W: THIGH
uint32_t TMC2130Stepper::THIGH() { return THIGH_sr; }
void TMC2130Stepper::THIGH(uint32_t input) {
	THIGH_sr = input;
	WRITE_REG(THIGH);
}
///////////////////////////////////////////////////////////////////////////////////////
// RW: XDIRECT
uint32_t TMC2130Stepper::XDIRECT() { READ_REG(XDIRECT); }
void TMC2130Stepper::XDIRECT(uint32_t input) {
	XDIRECT_sr = input;
	WRITE_REG(XDIRECT);
}
void TMC2130Stepper::coil_A(int16_t B) 	{ MOD_REG(XDIRECT, COIL_A); 	}
void TMC2130Stepper::coil_B(int16_t B) 	{ MOD_REG(XDIRECT, COIL_B); 	}
int16_t TMC2130Stepper::coil_A() 		{ GET_BYTE_R(XDIRECT, COIL_A); 	}
int16_t TMC2130Stepper::coil_B() 		{ GET_BYTE_R(XDIRECT, COIL_A); 	}
///////////////////////////////////////////////////////////////////////////////////////
// W: VDCMIN
uint32_t TMC2130Stepper::VDCMIN() { return VDCMIN_sr; }
void TMC2130Stepper::VDCMIN(uint32_t input) {
	VDCMIN_sr = input;
	WRITE_REG(VDCMIN);
}
///////////////////////////////////////////////////////////////////////////////////////
// R: PWM_SCALE
uint8_t TMC2130Stepper::PWM_SCALE() { READ_REG_R(PWM_SCALE); }
///////////////////////////////////////////////////////////////////////////////////////
// W: ENCM_CTRL
uint8_t TMC2130Stepper::ENCM_CTRL() { return ENCM_CTRL_sr; }
void TMC2130Stepper::ENCM_CTRL(uint8_t input) {
	ENCM_CTRL_sr = input;
	WRITE_REG(ENCM_CTRL);
}
void TMC2130Stepper::inv(bool B)		{ MOD_REG(ENCM_CTRL, INV);		}
void TMC2130Stepper::maxspeed(bool B)	{ MOD_REG(ENCM_CTRL, MAXSPEED); }
bool TMC2130Stepper::inv() 				{ GET_BYTE(ENCM_CTRL, INV); 	}
bool TMC2130Stepper::maxspeed() 		{ GET_BYTE(ENCM_CTRL, MAXSPEED);}
///////////////////////////////////////////////////////////////////////////////////////
// R: LOST_STEPS
uint32_t TMC2130Stepper::LOST_STEPS() { READ_REG_R(LOST_STEPS); }

/**
 *	Helper functions
 */

/*
	Requested current = mA = I_rms/1000
	Equation for current:
	I_rms = (CS+1)/32 * V_fs/(R_sense+0.02ohm) * 1/sqrt(2)
	Solve for CS ->
	CS = 32*sqrt(2)*I_rms*(R_sense+0.02)/V_fs - 1

	Example:
	vsense = 0b0 -> V_fs = 0.325V
	mA = 1640mA = I_rms/1000 = 1.64A
	R_sense = 0.10 Ohm
	->
	CS = 32*sqrt(2)*1.64*(0.10+0.02)/0.325 - 1 = 26.4
	CS = 26
*/
void TMC2130Stepper::rms_current(uint16_t mA, float multiplier, float RS) {
	Rsense = RS;
	uint8_t CS = 32.0*1.41421*mA/1000.0*(Rsense+0.02)/0.325 - 1;
	// If Current Scale is too low, turn on high sensitivity R_sense and calculate again
	if (CS < 16) {
		vsense(true);
		CS = 32.0*1.41421*mA/1000.0*(Rsense+0.02)/0.180 - 1;
	} else if(vsense()) { // If CS >= 16, turn off high_sense_r if it's currently ON
		vsense(false);
	}
	irun(CS);
	ihold(CS*multiplier);
	val_mA = mA;
}

uint16_t TMC2130Stepper::rms_current() {
	return (float)(irun()+1)/32.0 * (vsense()?0.180:0.325)/(Rsense+0.02) / 1.41421 * 1000;
}

void TMC2130Stepper::setCurrent(uint16_t mA, float R, float multiplier) { rms_current(mA, multiplier, R); }
uint16_t TMC2130Stepper::getCurrent() {	return val_mA; }

void TMC2130Stepper::SilentStepStick2130(uint16_t current) { rms_current(current); }

void TMC2130Stepper::microsteps(uint16_t ms) {
	switch(ms) {
		case 256: mres(0); break;
		case 128: mres(1); break;
		case  64: mres(2); break;
		case  32: mres(3); break;
		case  16: mres(4); break;
		case   8: mres(5); break;
		case   4: mres(6); break;
		case   2: mres(7); break;
		case   0: mres(8); break;
		default: break;
	}
}

uint16_t TMC2130Stepper::microsteps() {
	switch(mres()) {
		case 0: return 256;
		case 1: return 128;
		case 2: return  64;
		case 3: return  32;
		case 4: return  16;
		case 5: return   8;
		case 6: return   4;
		case 7: return   2;
		case 8: return   0;
	}
	return 0;
}

void TMC2130Stepper::sg_current_decrease(uint8_t value) {
	switch(value) {
		case 32: sedn(0b00); break;
		case  8: sedn(0b01); break;
		case  2: sedn(0b10); break;
		case  1: sedn(0b11); break;
	}
}
uint8_t TMC2130Stepper::sg_current_decrease() {
	switch(sedn()) {
		case 0b00: return 32;
		case 0b01: return  8;
		case 0b10: return  2;
		case 0b11: return  1;
	}
	return 0;
}
<commit_msg>Fix constructor for DUE<commit_after>#include "TMC2130Stepper.h"
#include "TMC2130Stepper_MACROS.h"

#ifdef ARDUINO_SAM_ARCHIM
	#include "SW_SPI.h"
	SW_SPI TMC_SPI = SW_SPI(); // Default: MOSI=28, MISO=26, SCK=27
#else
	#include <SPI.h>
	#define TMC_SPI SPI
#endif

TMC2130Stepper::TMC2130Stepper(uint8_t pinEN, uint8_t pinDIR, uint8_t pinStep, uint8_t pinCS) {
	_started = false;

	this->_pinEN = pinEN;
	this->_pinDIR = pinDIR;
	this->_pinSTEP = pinStep;
	this->_pinCS = pinCS;
}

void TMC2130Stepper::begin() {
#ifdef TMC2130DEBUG
	Serial.println("TMC2130 Stepper driver library");
	Serial.print("Enable pin: ");
	Serial.println(_pinEN);
	Serial.print("Direction pin: ");
	Serial.println(_pinDIR);
	Serial.print("Step pin: ");
	Serial.println(_pinSTEP);
	Serial.print("Chip select pin: ");
	Serial.println(_pinCS);
#endif
	//set pins
	pinMode(_pinEN, OUTPUT);
	pinMode(_pinDIR, OUTPUT);
	pinMode(_pinSTEP, OUTPUT);
	pinMode(_pinCS, OUTPUT);
	digitalWrite(_pinEN, HIGH); //deactivate driver (LOW active)
	digitalWrite(_pinDIR, LOW); //LOW or HIGH
	digitalWrite(_pinSTEP, LOW);
	digitalWrite(_pinCS, HIGH);
/*
	pinMode(MOSI, OUTPUT);
	pinMode(MISO, INPUT);
	pinMode(SCK, OUTPUT);
	digitalWrite(MOSI, LOW);
	digitalWrite(MISO, HIGH);
	digitalWrite(SCK, LOW);

	SPI.begin();
*/
	GCONF(GCONF_sr);
	CHOPCONF(CHOPCONF_sr);
	COOLCONF(COOLCONF_sr);
	PWMCONF(PWMCONF_sr);
	IHOLD_IRUN(IHOLD_IRUN_sr);

	toff(8); //off_time(8);
	tbl(1); //blank_time(24);

	_started = true;
}

//uint32_t TMC2130Stepper::send2130(uint8_t addressByte, uint32_t *config, uint32_t value, uint32_t mask) {
void TMC2130Stepper::send2130(uint8_t addressByte, uint32_t *config) {
	//uint8_t s;
	TMC_SPI.begin();
	#ifndef ARDUINO_SAM_ARCHIM
		TMC_SPI.beginTransaction(SPISettings(16000000/8, MSBFIRST, SPI_MODE3));
	#endif
	digitalWrite(_pinCS, LOW);

	status_response = TMC_SPI.transfer(addressByte & 0xFF); // s =
	#ifdef TMC2130DEBUG
		Serial.println("## Received parameters:");
		Serial.print("## Address byte: ");
		Serial.println(addressByte, HEX);
		Serial.print("## Config: ");
		Serial.println(*config, BIN);
		Serial.print("## status_response: ");
		Serial.println(status_response, BIN);
	#endif

	if (addressByte >> 7) { // Check if WRITE command
		//*config &= ~mask; // Clear bits being set
		//*config |= (value & mask); // Set new values
		TMC_SPI.transfer((*config >> 24) & 0xFF);
		TMC_SPI.transfer((*config >> 16) & 0xFF);
		TMC_SPI.transfer((*config >>  8) & 0xFF);
		TMC_SPI.transfer(*config & 0xFF);
		#ifdef TMC2130DEBUG
			Serial.println("## WRITE cmd");
			Serial.println("##########################");
		#endif
	} else { // READ command
		TMC_SPI.transfer16(0x0000); // Clear SPI
		TMC_SPI.transfer16(0x0000);
		digitalWrite(_pinCS, HIGH);
		digitalWrite(_pinCS, LOW);

		TMC_SPI.transfer(addressByte & 0xFF); // Send the address byte again
		*config  = TMC_SPI.transfer(0x00);
		*config <<= 8;
		*config |= TMC_SPI.transfer(0x00);
		*config <<= 8;
		*config |= TMC_SPI.transfer(0x00);
		*config <<= 8;
		*config |= TMC_SPI.transfer(0x00);
		#ifdef TMC2130DEBUG
			Serial.println("## READ cmd");
			Serial.print("## Received config: ");
			Serial.println(*config, BIN);
			Serial.println("##########################");
		#endif
	}

	digitalWrite(_pinCS, HIGH);
	TMC_SPI.endTransaction();

	//return s;
}

bool TMC2130Stepper::checkOT() {
	uint32_t response = DRV_STATUS();
	if (response & OTPW_bm) {
		flag_otpw = 1;
		return true; // bit 26 for overtemperature warning flag
	}
	return false;
}

bool TMC2130Stepper::getOTPW() { return flag_otpw; }

void TMC2130Stepper::clear_otpw() {	flag_otpw = 0; }

bool TMC2130Stepper::isEnabled() { return !digitalRead(_pinEN) && toff(); }

///////////////////////////////////////////////////////////////////////////////////////
// R+C: GSTAT
void 	TMC2130Stepper::GSTAT(uint8_t input){
	GSTAT_sr = input;
	WRITE_REG(GSTAT);
}
uint8_t TMC2130Stepper::GSTAT()			 	{ READ_REG_R(GSTAT); 		}
bool 	TMC2130Stepper::reset()				{ GET_BYTE(GSTAT, RESET);	}
bool 	TMC2130Stepper::drv_err()			{ GET_BYTE(GSTAT, DRV_ERR);	}
bool 	TMC2130Stepper::uv_cp()				{ GET_BYTE(GSTAT, UV_CP);	}
///////////////////////////////////////////////////////////////////////////////////////
// R: IOIN
uint32_t 	TMC2130Stepper::IOIN() 			{ READ_REG_R(IOIN); 				}
bool 		TMC2130Stepper::step()			{ GET_BYTE_R(IOIN, STEP);			}
bool 		TMC2130Stepper::dir()			{ GET_BYTE_R(IOIN, DIR);			}
bool 		TMC2130Stepper::dcen_cfg4()		{ GET_BYTE_R(IOIN, DCEN_CFG4);		}
bool 		TMC2130Stepper::dcin_cfg5()		{ GET_BYTE_R(IOIN, DCIN_CFG5);		}
bool 		TMC2130Stepper::drv_enn_cfg6()	{ GET_BYTE_R(IOIN, DRV_ENN_CFG6);	}
bool 		TMC2130Stepper::dco()			{ GET_BYTE_R(IOIN, DCO);			}
uint8_t 	TMC2130Stepper::version() 		{ GET_BYTE_R(IOIN, VERSION);		}
///////////////////////////////////////////////////////////////////////////////////////
// W: TPOWERDOWN
uint32_t TMC2130Stepper::TPOWERDOWN() { return TPOWERDOWN_sr; }
void TMC2130Stepper::TPOWERDOWN(uint32_t input) {
	TPOWERDOWN_sr = input;
	WRITE_REG(TPOWERDOWN);
}
///////////////////////////////////////////////////////////////////////////////////////
// R: TSTEP
uint32_t TMC2130Stepper::TSTEP() { READ_REG_R(TSTEP); }
///////////////////////////////////////////////////////////////////////////////////////
// W: TPWMTHRS
uint32_t TMC2130Stepper::TPWMTHRS() { return TPWMTHRS_sr; }
void TMC2130Stepper::TPWMTHRS(uint32_t input) {
	TPWMTHRS_sr = input;
	WRITE_REG(TPWMTHRS);
}
///////////////////////////////////////////////////////////////////////////////////////
// W: TCOOLTHRS
uint32_t TMC2130Stepper::TCOOLTHRS() { return TCOOLTHRS_sr; }
void TMC2130Stepper::TCOOLTHRS(uint32_t input) {
	TCOOLTHRS_sr = input;
	WRITE_REG(TCOOLTHRS);
}
///////////////////////////////////////////////////////////////////////////////////////
// W: THIGH
uint32_t TMC2130Stepper::THIGH() { return THIGH_sr; }
void TMC2130Stepper::THIGH(uint32_t input) {
	THIGH_sr = input;
	WRITE_REG(THIGH);
}
///////////////////////////////////////////////////////////////////////////////////////
// RW: XDIRECT
uint32_t TMC2130Stepper::XDIRECT() { READ_REG(XDIRECT); }
void TMC2130Stepper::XDIRECT(uint32_t input) {
	XDIRECT_sr = input;
	WRITE_REG(XDIRECT);
}
void TMC2130Stepper::coil_A(int16_t B) 	{ MOD_REG(XDIRECT, COIL_A); 	}
void TMC2130Stepper::coil_B(int16_t B) 	{ MOD_REG(XDIRECT, COIL_B); 	}
int16_t TMC2130Stepper::coil_A() 		{ GET_BYTE_R(XDIRECT, COIL_A); 	}
int16_t TMC2130Stepper::coil_B() 		{ GET_BYTE_R(XDIRECT, COIL_A); 	}
///////////////////////////////////////////////////////////////////////////////////////
// W: VDCMIN
uint32_t TMC2130Stepper::VDCMIN() { return VDCMIN_sr; }
void TMC2130Stepper::VDCMIN(uint32_t input) {
	VDCMIN_sr = input;
	WRITE_REG(VDCMIN);
}
///////////////////////////////////////////////////////////////////////////////////////
// R: PWM_SCALE
uint8_t TMC2130Stepper::PWM_SCALE() { READ_REG_R(PWM_SCALE); }
///////////////////////////////////////////////////////////////////////////////////////
// W: ENCM_CTRL
uint8_t TMC2130Stepper::ENCM_CTRL() { return ENCM_CTRL_sr; }
void TMC2130Stepper::ENCM_CTRL(uint8_t input) {
	ENCM_CTRL_sr = input;
	WRITE_REG(ENCM_CTRL);
}
void TMC2130Stepper::inv(bool B)		{ MOD_REG(ENCM_CTRL, INV);		}
void TMC2130Stepper::maxspeed(bool B)	{ MOD_REG(ENCM_CTRL, MAXSPEED); }
bool TMC2130Stepper::inv() 				{ GET_BYTE(ENCM_CTRL, INV); 	}
bool TMC2130Stepper::maxspeed() 		{ GET_BYTE(ENCM_CTRL, MAXSPEED);}
///////////////////////////////////////////////////////////////////////////////////////
// R: LOST_STEPS
uint32_t TMC2130Stepper::LOST_STEPS() { READ_REG_R(LOST_STEPS); }

/**
 *	Helper functions
 */

/*
	Requested current = mA = I_rms/1000
	Equation for current:
	I_rms = (CS+1)/32 * V_fs/(R_sense+0.02ohm) * 1/sqrt(2)
	Solve for CS ->
	CS = 32*sqrt(2)*I_rms*(R_sense+0.02)/V_fs - 1

	Example:
	vsense = 0b0 -> V_fs = 0.325V
	mA = 1640mA = I_rms/1000 = 1.64A
	R_sense = 0.10 Ohm
	->
	CS = 32*sqrt(2)*1.64*(0.10+0.02)/0.325 - 1 = 26.4
	CS = 26
*/
void TMC2130Stepper::rms_current(uint16_t mA, float multiplier, float RS) {
	Rsense = RS;
	uint8_t CS = 32.0*1.41421*mA/1000.0*(Rsense+0.02)/0.325 - 1;
	// If Current Scale is too low, turn on high sensitivity R_sense and calculate again
	if (CS < 16) {
		vsense(true);
		CS = 32.0*1.41421*mA/1000.0*(Rsense+0.02)/0.180 - 1;
	} else if(vsense()) { // If CS >= 16, turn off high_sense_r if it's currently ON
		vsense(false);
	}
	irun(CS);
	ihold(CS*multiplier);
	val_mA = mA;
}

uint16_t TMC2130Stepper::rms_current() {
	return (float)(irun()+1)/32.0 * (vsense()?0.180:0.325)/(Rsense+0.02) / 1.41421 * 1000;
}

void TMC2130Stepper::setCurrent(uint16_t mA, float R, float multiplier) { rms_current(mA, multiplier, R); }
uint16_t TMC2130Stepper::getCurrent() {	return val_mA; }

void TMC2130Stepper::SilentStepStick2130(uint16_t current) { rms_current(current); }

void TMC2130Stepper::microsteps(uint16_t ms) {
	switch(ms) {
		case 256: mres(0); break;
		case 128: mres(1); break;
		case  64: mres(2); break;
		case  32: mres(3); break;
		case  16: mres(4); break;
		case   8: mres(5); break;
		case   4: mres(6); break;
		case   2: mres(7); break;
		case   0: mres(8); break;
		default: break;
	}
}

uint16_t TMC2130Stepper::microsteps() {
	switch(mres()) {
		case 0: return 256;
		case 1: return 128;
		case 2: return  64;
		case 3: return  32;
		case 4: return  16;
		case 5: return   8;
		case 6: return   4;
		case 7: return   2;
		case 8: return   0;
	}
	return 0;
}

void TMC2130Stepper::sg_current_decrease(uint8_t value) {
	switch(value) {
		case 32: sedn(0b00); break;
		case  8: sedn(0b01); break;
		case  2: sedn(0b10); break;
		case  1: sedn(0b11); break;
	}
}
uint8_t TMC2130Stepper::sg_current_decrease() {
	switch(sedn()) {
		case 0b00: return 32;
		case 0b01: return  8;
		case 0b10: return  2;
		case 0b11: return  1;
	}
	return 0;
}
<|endoftext|>


<commit_before>#include <QTest>
#include <QDebug>
#include "tglobal.h"

static QByteArray dummydata;
static const QByteArray testdata2("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
static const QByteArray testdata3("a;lkdfj;lkjfad;lakjsdla;kj;lkajd;lakj;lkj;lkj;sl;kjs;lkj;llkj;lslkj;lslkj;slkjsl;kj;lkj;lkjkj;lkk");
static const QByteArray testdata4("109283091823019823019283019823019823019283019831092830192830192831");
static const QByteArray testdata5("poiterpoiterpoiterpoiterpoierteeprotipoeritepoirtperopoitepotierpoeritperoitpeorit");

class LZ4Compress : public QObject
{
    Q_OBJECT
private slots:
    void initTestCase();
    void qcompress_data();
    void qcompress();
    void lz4_l1_data();
    void lz4_l1();
    void lz4_l2_data();
    void lz4_l2();
    void lz4_l5_data();
    void lz4_l5();
    void bench_lz4_l1_512();
    void bench_lz4_l2_512();
    void bench_lz4_l5_512();
    void bench_qcompress_512();
    void bench_base64_512();
    void bench_lz4_l1_128k();
    void bench_lz4_l2_128k();
    void bench_lz4_l5_128k();
    void bench_qcompress_128k();
    void bench_base64_128k();
    void bench_lz4_l1_10m();
    void bench_lz4_l2_10m();
    void bench_lz4_l5_10m();
    void bench_qcompress_10m();
    void bench_base64_10m();
};

void LZ4Compress::initTestCase()
{
    dummydata.resize(10 * 1024 * 1024);
    for (int i = 0; i < dummydata.size() - 8; i += 8) {
        dummydata.replace(i, 4, QByteArray::number((uint)Tf::random(0xFFFF), 16));
    }
}

void LZ4Compress::qcompress_data()
{
    QTest::addColumn<QByteArray>("data");

    QTest::newRow("1") << QByteArray("");
    QTest::newRow("2") << testdata2;
    QTest::newRow("3") << testdata3;
    QTest::newRow("4") << testdata4;
    QTest::newRow("5") << testdata5;
    QTest::newRow("6") << dummydata.mid(1025);
    QTest::newRow("7") << dummydata.mid(1024 * 1021);
    QTest::newRow("8") << dummydata;
}

void LZ4Compress::qcompress()
{
    QFETCH(QByteArray, data);

    QByteArray comp = qCompress(data);
    qDebug() << "orignal length:" << data.length() <<  " compression:" << (float)comp.length() / qMax(data.length(), 1);
    QByteArray uncomp = qUncompress(comp);
    QCOMPARE(data, uncomp);
}

void LZ4Compress::lz4_l1_data()
{
    QTest::addColumn<QByteArray>("data");

    QTest::newRow("1") << QByteArray("");
    QTest::newRow("2") << testdata2;
    QTest::newRow("3") << testdata3;
    QTest::newRow("4") << testdata4;
    QTest::newRow("5") << testdata5;
    QTest::newRow("6") << dummydata.mid(1025);
    QTest::newRow("7") << dummydata.mid(1024 * 1021);
    QTest::newRow("8") << dummydata;
}

void LZ4Compress::lz4_l1()
{
    QFETCH(QByteArray, data);

    QByteArray comp = Tf::lz4Compress(data, 1);
    qDebug() << "orignal length:" << data.length() <<  " compression:" << (float)comp.length() / qMax(data.length(), 1);
    QByteArray uncomp = Tf::lz4Uncompress(comp);
    QCOMPARE(data, uncomp);
}

void LZ4Compress::lz4_l2_data()
{
    QTest::addColumn<QByteArray>("data");

    QTest::newRow("1") << QByteArray("");
    QTest::newRow("2") << testdata2;
    QTest::newRow("3") << testdata3;
    QTest::newRow("4") << testdata4;
    QTest::newRow("5") << testdata5;
    QTest::newRow("6") << dummydata.mid(1025);
    QTest::newRow("7") << dummydata.mid(1024 * 1021);
    QTest::newRow("8") << dummydata;
}

void LZ4Compress::lz4_l2()
{
    QFETCH(QByteArray, data);

    QByteArray comp = Tf::lz4Compress(data, 2);
    qDebug() << "orignal length:" << data.length() <<  " compression:" << (float)comp.length() / qMax(data.length(), 1);
    QByteArray uncomp = Tf::lz4Uncompress(comp);
    QCOMPARE(data, uncomp);
}

void LZ4Compress::lz4_l5_data()
{
    QTest::addColumn<QByteArray>("data");

    QTest::newRow("1") << QByteArray("");
    QTest::newRow("2") << testdata2;
    QTest::newRow("3") << testdata3;
    QTest::newRow("4") << testdata4;
    QTest::newRow("5") << testdata5;
    QTest::newRow("6") << dummydata.mid(1025);
    QTest::newRow("7") << dummydata.mid(1024 * 1021);
    QTest::newRow("8") << dummydata;
}

void LZ4Compress::lz4_l5()
{
    QFETCH(QByteArray, data);

    QByteArray comp = Tf::lz4Compress(data, 5);
    qDebug() << "orignal length:" << data.length() <<  " compression:" << (float)comp.length() / qMax(data.length(), 1);
    QByteArray uncomp = Tf::lz4Uncompress(comp);
    QCOMPARE(data, uncomp);
}

void LZ4Compress::bench_lz4_l1_512()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata.mid(512)), 1 );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l2_512()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata.mid(512)), 2 );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l5_512()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata.mid(512)), 5 );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_qcompress_512()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata.mid(512)) );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_base64_512()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata.mid(512)) );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l1_128k()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata.mid(128 * 1024)), 1 );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l2_128k()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata.mid(128 * 1024)), 2 );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l5_128k()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata.mid(128 * 1024)), 5 );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_qcompress_128k()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata.mid(128 * 1024)) );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_base64_128k()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata.mid(128 * 1024)) );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l1_10m()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata), 1 );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l2_10m()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata), 2 );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l5_10m()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata), 5 );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_qcompress_10m()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata) );
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_base64_10m()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress( Tf::lz4Compress(dummydata) );
        Q_UNUSED(cmp);
    }
}

QTEST_APPLESS_MAIN(LZ4Compress)
#include "main.moc"
<commit_msg>bugfixes.<commit_after>#include <QTest>
#include <QDebug>
#include "tglobal.h"

static QByteArray dummydata;
static const QByteArray testdata2("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
static const QByteArray testdata3("a;lkdfj;lkjfad;lakjsdla;kj;lkajd;lakj;lkj;lkj;sl;kjs;lkj;llkj;lslkj;lslkj;slkjsl;kj;lkj;lkjkj;lkk");
static const QByteArray testdata4("109283091823019823019283019823019823019283019831092830192830192831");
static const QByteArray testdata5("poiterpoiterpoiterpoiterpoierteeprotipoeritepoirtperopoitepotierpoeritperoitpeorit");

class LZ4Compress : public QObject
{
    Q_OBJECT
private slots:
    void initTestCase();
    void qcompress_data();
    void qcompress();
    void lz4_l1_data();
    void lz4_l1();
    void lz4_l2_data();
    void lz4_l2();
    void lz4_l5_data();
    void lz4_l5();
    void bench_lz4_l1_512();
    void bench_lz4_l2_512();
    void bench_lz4_l5_512();
    void bench_qcompress_512();
    void bench_base64_512();
    void bench_lz4_l1_128k();
    void bench_lz4_l2_128k();
    void bench_lz4_l5_128k();
    void bench_qcompress_128k();
    void bench_base64_128k();
    void bench_lz4_l1_10m();
    void bench_lz4_l2_10m();
    void bench_lz4_l5_10m();
    void bench_qcompress_10m();
    void bench_base64_10m();
};

void LZ4Compress::initTestCase()
{
    dummydata.resize(10 * 1024 * 1024);
    for (int i = 0; i < dummydata.size() - 8; i += 8) {
        dummydata.replace(i, 4, QByteArray::number((uint)Tf::random(0xFFFF), 16));
    }
}

void LZ4Compress::qcompress_data()
{
    QTest::addColumn<QByteArray>("data");

    QTest::newRow("1") << QByteArray("");
    QTest::newRow("2") << testdata2;
    QTest::newRow("3") << testdata3;
    QTest::newRow("4") << testdata4;
    QTest::newRow("5") << testdata5;
    QTest::newRow("6") << dummydata.mid(0, 1025);
    QTest::newRow("7") << dummydata.mid(0, 1024 * 1021);
    QTest::newRow("8") << dummydata;
}

void LZ4Compress::qcompress()
{
    QFETCH(QByteArray, data);

    QByteArray comp = qCompress(data);
    qDebug() << "orignal length:" << data.length() <<  " compression:" << (float)comp.length() / qMax(data.length(), 1);
    QByteArray uncomp = qUncompress(comp);
    QCOMPARE(data, uncomp);
}

void LZ4Compress::lz4_l1_data()
{
    QTest::addColumn<QByteArray>("data");

    QTest::newRow("1") << QByteArray("");
    QTest::newRow("2") << testdata2;
    QTest::newRow("3") << testdata3;
    QTest::newRow("4") << testdata4;
    QTest::newRow("5") << testdata5;
    QTest::newRow("6") << dummydata.mid(0, 1025);
    QTest::newRow("7") << dummydata.mid(0, 1024 * 1021);
    QTest::newRow("8") << dummydata;
}

void LZ4Compress::lz4_l1()
{
    QFETCH(QByteArray, data);

    QByteArray comp = Tf::lz4Compress(data, 1);
    qDebug() << "orignal length:" << data.length() <<  " compression:" << (float)comp.length() / qMax(data.length(), 1);
    QByteArray uncomp = Tf::lz4Uncompress(comp);
    QCOMPARE(data, uncomp);
}

void LZ4Compress::lz4_l2_data()
{
    QTest::addColumn<QByteArray>("data");

    QTest::newRow("1") << QByteArray("");
    QTest::newRow("2") << testdata2;
    QTest::newRow("3") << testdata3;
    QTest::newRow("4") << testdata4;
    QTest::newRow("5") << testdata5;
    QTest::newRow("6") << dummydata.mid(0, 1025);
    QTest::newRow("7") << dummydata.mid(0, 1024 * 1021);
    QTest::newRow("8") << dummydata;
}

void LZ4Compress::lz4_l2()
{
    QFETCH(QByteArray, data);

    QByteArray comp = Tf::lz4Compress(data, 2);
    qDebug() << "orignal length:" << data.length() <<  " compression:" << (float)comp.length() / qMax(data.length(), 1);
    QByteArray uncomp = Tf::lz4Uncompress(comp);
    QCOMPARE(data, uncomp);
}

void LZ4Compress::lz4_l5_data()
{
    QTest::addColumn<QByteArray>("data");

    QTest::newRow("1") << QByteArray("");
    QTest::newRow("2") << testdata2;
    QTest::newRow("3") << testdata3;
    QTest::newRow("4") << testdata4;
    QTest::newRow("5") << testdata5;
    QTest::newRow("6") << dummydata.mid(0, 1025);
    QTest::newRow("7") << dummydata.mid(0, 1024 * 1021);
    QTest::newRow("8") << dummydata;
}

void LZ4Compress::lz4_l5()
{
    QFETCH(QByteArray, data);

    QByteArray comp = Tf::lz4Compress(data, 5);
    qDebug() << "orignal length:" << data.length() <<  " compression:" << (float)comp.length() / qMax(data.length(), 1);
    QByteArray uncomp = Tf::lz4Uncompress(comp);
    QCOMPARE(data, uncomp);
}

void LZ4Compress::bench_lz4_l1_512()
{
    auto d = dummydata.mid(0, 512);
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress(Tf::lz4Compress(d, 1));
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l2_512()
{
    auto d = dummydata.mid(0, 512);
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress(Tf::lz4Compress(d, 2));
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l5_512()
{
    auto d = dummydata.mid(0, 512);
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress(Tf::lz4Compress(d, 5));
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_qcompress_512()
{
    auto d = dummydata.mid(0, 512);
    QBENCHMARK {
        auto cmp = qUncompress(qCompress(d));
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_base64_512()
{
    auto d = dummydata.mid(0, 512);
    QBENCHMARK {
        auto cmp = QByteArray::fromBase64(d.toBase64());
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l1_128k()
{
    auto d = dummydata.mid(0, 128 * 1024);
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress(Tf::lz4Compress(d, 1));
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l2_128k()
{
    auto d = dummydata.mid(0, 128 * 1024);
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress(Tf::lz4Compress(d, 2));
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l5_128k()
{
    auto d = dummydata.mid(0, 128 * 1024);
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress(Tf::lz4Compress(d, 5));
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_qcompress_128k()
{
    auto d = dummydata.mid(0, 128 * 1024);
    QBENCHMARK {
        auto cmp = qUncompress(qCompress(d));
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_base64_128k()
{
    auto d = dummydata.mid(0, 128 * 1024);
    QBENCHMARK {
        auto cmp = QByteArray::fromBase64(d.toBase64());
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l1_10m()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress(Tf::lz4Compress(dummydata, 1));
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l2_10m()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress(Tf::lz4Compress(dummydata, 2));
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_lz4_l5_10m()
{
    QBENCHMARK {
        auto cmp = Tf::lz4Uncompress(Tf::lz4Compress(dummydata, 5));
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_qcompress_10m()
{
    QBENCHMARK {
        auto cmp = qUncompress(qCompress(dummydata));
        Q_UNUSED(cmp);
    }
}

void LZ4Compress::bench_base64_10m()
{
    QBENCHMARK {
        auto cmp = QByteArray::fromBase64(dummydata.toBase64());
        Q_UNUSED(cmp);
    }
}

QTEST_APPLESS_MAIN(LZ4Compress)
#include "main.moc"
<|endoftext|>


<commit_before>// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <addrdb.h>
#include <addrman.h>
#include <blockencodings.h>
#include <blockfilter.h>
#include <chain.h>
#include <coins.h>
#include <compressor.h>
#include <consensus/merkle.h>
#include <key.h>
#include <merkleblock.h>
#include <net.h>
#include <primitives/block.h>
#include <protocol.h>
#include <psbt.h>
#include <pubkey.h>
#include <script/keyorigin.h>
#include <streams.h>
#include <undo.h>
#include <version.h>

#include <stdexcept>
#include <stdint.h>
#include <unistd.h>

#include <vector>

#include <test/fuzz/fuzz.h>

void initialize()
{
    // Fuzzers using pubkey must hold an ECCVerifyHandle.
    static const auto verify_handle = MakeUnique<ECCVerifyHandle>();
}

void test_one_input(const std::vector<uint8_t>& buffer)
{
    CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
    try {
        int nVersion;
        ds >> nVersion;
        ds.SetVersion(nVersion);
    } catch (const std::ios_base::failure&) {
        return;
    }

#if BLOCK_FILTER_DESERIALIZE
    try {
        BlockFilter block_filter;
        ds >> block_filter;
    } catch (const std::ios_base::failure&) {
    }
#elif ADDR_INFO_DESERIALIZE
    try {
        CAddrInfo addr_info;
        ds >> addr_info;
    } catch (const std::ios_base::failure&) {
    }
#elif BLOCK_FILE_INFO_DESERIALIZE
    try {
        CBlockFileInfo block_file_info;
        ds >> block_file_info;
    } catch (const std::ios_base::failure&) {
    }
#elif BLOCK_HEADER_AND_SHORT_TXIDS_DESERIALIZE
    try {
        CBlockHeaderAndShortTxIDs block_header_and_short_txids;
        ds >> block_header_and_short_txids;
    } catch (const std::ios_base::failure&) {
    }
#elif FEE_RATE_DESERIALIZE
    try {
        CFeeRate fee_rate;
        ds >> fee_rate;
    } catch (const std::ios_base::failure&) {
    }
#elif MERKLE_BLOCK_DESERIALIZE
    try {
        CMerkleBlock merkle_block;
        ds >> merkle_block;
    } catch (const std::ios_base::failure&) {
    }
#elif OUT_POINT_DESERIALIZE
    try {
        COutPoint out_point;
        ds >> out_point;
    } catch (const std::ios_base::failure&) {
    }
#elif PARTIAL_MERKLE_TREE_DESERIALIZE
    try {
        CPartialMerkleTree partial_merkle_tree;
        ds >> partial_merkle_tree;
    } catch (const std::ios_base::failure&) {
    }
#elif PUB_KEY_DESERIALIZE
    try {
        CPubKey pub_key;
        ds >> pub_key;
    } catch (const std::ios_base::failure&) {
    }
#elif SCRIPT_DESERIALIZE
    try {
        CScript script;
        ds >> script;
    } catch (const std::ios_base::failure&) {
    }
#elif SUB_NET_DESERIALIZE
    try {
        CSubNet sub_net;
        ds >> sub_net;
    } catch (const std::ios_base::failure&) {
    }
#elif TX_IN_DESERIALIZE
    try {
        CTxIn tx_in;
        ds >> tx_in;
    } catch (const std::ios_base::failure&) {
    }
#elif FLAT_FILE_POS_DESERIALIZE
    try {
        FlatFilePos flat_file_pos;
        ds >> flat_file_pos;
    } catch (const std::ios_base::failure&) {
    }
#elif KEY_ORIGIN_INFO_DESERIALIZE
    try {
        KeyOriginInfo key_origin_info;
        ds >> key_origin_info;
    } catch (const std::ios_base::failure&) {
    }
#elif PARTIALLY_SIGNED_TRANSACTION_DESERIALIZE
    try {
        PartiallySignedTransaction partially_signed_transaction;
        ds >> partially_signed_transaction;
    } catch (const std::ios_base::failure&) {
    }
#elif PREFILLED_TRANSACTION_DESERIALIZE
    try {
        PrefilledTransaction prefilled_transaction;
        ds >> prefilled_transaction;
    } catch (const std::ios_base::failure&) {
    }
#elif PSBT_INPUT_DESERIALIZE
    try {
        PSBTInput psbt_input;
        ds >> psbt_input;
    } catch (const std::ios_base::failure&) {
    }
#elif PSBT_OUTPUT_DESERIALIZE
    try {
        PSBTOutput psbt_output;
        ds >> psbt_output;
    } catch (const std::ios_base::failure&) {
    }
#elif BLOCK_DESERIALIZE
    try {
        CBlock block;
        ds >> block;
    } catch (const std::ios_base::failure&) {
    }
#elif BLOCKLOCATOR_DESERIALIZE
    try {
        CBlockLocator bl;
        ds >> bl;
    } catch (const std::ios_base::failure&) {
    }
#elif BLOCKMERKLEROOT
    try {
        CBlock block;
        ds >> block;
        bool mutated;
        BlockMerkleRoot(block, &mutated);
    } catch (const std::ios_base::failure&) {
    }
#elif ADDRMAN_DESERIALIZE
    try {
        CAddrMan am;
        ds >> am;
    } catch (const std::ios_base::failure&) {
    }
#elif BLOCKHEADER_DESERIALIZE
    try {
        CBlockHeader bh;
        ds >> bh;
    } catch (const std::ios_base::failure&) {
    }
#elif BANENTRY_DESERIALIZE
    try {
        CBanEntry be;
        ds >> be;
    } catch (const std::ios_base::failure&) {
    }
#elif TXUNDO_DESERIALIZE
    try {
        CTxUndo tu;
        ds >> tu;
    } catch (const std::ios_base::failure&) {
    }
#elif BLOCKUNDO_DESERIALIZE
    try {
        CBlockUndo bu;
        ds >> bu;
    } catch (const std::ios_base::failure&) {
    }
#elif COINS_DESERIALIZE
    try {
        Coin coin;
        ds >> coin;
    } catch (const std::ios_base::failure&) {
    }
#elif NETADDR_DESERIALIZE
    try {
        CNetAddr na;
        ds >> na;
    } catch (const std::ios_base::failure&) {
    }
#elif SERVICE_DESERIALIZE
    try {
        CService s;
        ds >> s;
    } catch (const std::ios_base::failure&) {
    }
#elif MESSAGEHEADER_DESERIALIZE
    CMessageHeader::MessageStartChars pchMessageStart = {0x00, 0x00, 0x00, 0x00};
    try {
        CMessageHeader mh(pchMessageStart);
        ds >> mh;
        (void)mh.IsValid(pchMessageStart);
    } catch (const std::ios_base::failure&) {
    }
#elif ADDRESS_DESERIALIZE
    try {
        CAddress a;
        ds >> a;
    } catch (const std::ios_base::failure&) {
    }
#elif INV_DESERIALIZE
    try {
        CInv i;
        ds >> i;
    } catch (const std::ios_base::failure&) {
    }
#elif BLOOMFILTER_DESERIALIZE
    try {
        CBloomFilter bf;
        ds >> bf;
    } catch (const std::ios_base::failure&) {
    }
#elif DISKBLOCKINDEX_DESERIALIZE
    try {
        CDiskBlockIndex dbi;
        ds >> dbi;
    } catch (const std::ios_base::failure&) {
    }
#elif TXOUTCOMPRESSOR_DESERIALIZE
    CTxOut to;
    CTxOutCompressor toc(to);
    try {
        ds >> toc;
    } catch (const std::ios_base::failure&) {
    }
#elif BLOCKTRANSACTIONS_DESERIALIZE
    try {
        BlockTransactions bt;
        ds >> bt;
    } catch (const std::ios_base::failure&) {
    }
#elif BLOCKTRANSACTIONSREQUEST_DESERIALIZE
    try {
        BlockTransactionsRequest btr;
        ds >> btr;
    } catch (const std::ios_base::failure&) {
    }
#else
#error Need at least one fuzz target to compile
#endif
}
<commit_msg>tests: Test serialisation as part of deserialisation fuzzing. Test round-trip equality where possible. Avoid code repetition.<commit_after>// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <addrdb.h>
#include <addrman.h>
#include <blockencodings.h>
#include <blockfilter.h>
#include <chain.h>
#include <coins.h>
#include <compressor.h>
#include <consensus/merkle.h>
#include <key.h>
#include <merkleblock.h>
#include <net.h>
#include <primitives/block.h>
#include <protocol.h>
#include <psbt.h>
#include <pubkey.h>
#include <script/keyorigin.h>
#include <streams.h>
#include <undo.h>
#include <version.h>

#include <exception>
#include <stdexcept>
#include <stdint.h>
#include <unistd.h>

#include <vector>

#include <test/fuzz/fuzz.h>

void initialize()
{
    // Fuzzers using pubkey must hold an ECCVerifyHandle.
    static const auto verify_handle = MakeUnique<ECCVerifyHandle>();
}

namespace {

struct invalid_fuzzing_input_exception : public std::exception {
};

template <typename T>
CDataStream Serialize(const T& obj)
{
    CDataStream ds(SER_NETWORK, INIT_PROTO_VERSION);
    ds << obj;
    return ds;
}

template <typename T>
T Deserialize(CDataStream ds)
{
    T obj;
    ds >> obj;
    return obj;
}

template <typename T>
void DeserializeFromFuzzingInput(const std::vector<uint8_t>& buffer, T& obj)
{
    CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
    try {
        int version;
        ds >> version;
        ds.SetVersion(version);
    } catch (const std::ios_base::failure&) {
        throw invalid_fuzzing_input_exception();
    }
    try {
        ds >> obj;
    } catch (const std::ios_base::failure&) {
        throw invalid_fuzzing_input_exception();
    }
    assert(buffer.empty() || !Serialize(obj).empty());
}

template <typename T>
void AssertEqualAfterSerializeDeserialize(const T& obj)
{
    assert(Deserialize<T>(Serialize(obj)) == obj);
}

} // namespace

void test_one_input(const std::vector<uint8_t>& buffer)
{
    try {
#if BLOCK_FILTER_DESERIALIZE
        BlockFilter block_filter;
        DeserializeFromFuzzingInput(buffer, block_filter);
#elif ADDR_INFO_DESERIALIZE
        CAddrInfo addr_info;
        DeserializeFromFuzzingInput(buffer, addr_info);
#elif BLOCK_FILE_INFO_DESERIALIZE
        CBlockFileInfo block_file_info;
        DeserializeFromFuzzingInput(buffer, block_file_info);
#elif BLOCK_HEADER_AND_SHORT_TXIDS_DESERIALIZE
        CBlockHeaderAndShortTxIDs block_header_and_short_txids;
        DeserializeFromFuzzingInput(buffer, block_header_and_short_txids);
#elif FEE_RATE_DESERIALIZE
        CFeeRate fee_rate;
        DeserializeFromFuzzingInput(buffer, fee_rate);
        AssertEqualAfterSerializeDeserialize(fee_rate);
#elif MERKLE_BLOCK_DESERIALIZE
        CMerkleBlock merkle_block;
        DeserializeFromFuzzingInput(buffer, merkle_block);
#elif OUT_POINT_DESERIALIZE
        COutPoint out_point;
        DeserializeFromFuzzingInput(buffer, out_point);
        AssertEqualAfterSerializeDeserialize(out_point);
#elif PARTIAL_MERKLE_TREE_DESERIALIZE
        CPartialMerkleTree partial_merkle_tree;
        DeserializeFromFuzzingInput(buffer, partial_merkle_tree);
#elif PUB_KEY_DESERIALIZE
        CPubKey pub_key;
        DeserializeFromFuzzingInput(buffer, pub_key);
        // TODO: The following equivalence should hold for CPubKey? Fix.
        // AssertEqualAfterSerializeDeserialize(pub_key);
#elif SCRIPT_DESERIALIZE
        CScript script;
        DeserializeFromFuzzingInput(buffer, script);
#elif SUB_NET_DESERIALIZE
        CSubNet sub_net;
        DeserializeFromFuzzingInput(buffer, sub_net);
        AssertEqualAfterSerializeDeserialize(sub_net);
#elif TX_IN_DESERIALIZE
        CTxIn tx_in;
        DeserializeFromFuzzingInput(buffer, tx_in);
        AssertEqualAfterSerializeDeserialize(tx_in);
#elif FLAT_FILE_POS_DESERIALIZE
        FlatFilePos flat_file_pos;
        DeserializeFromFuzzingInput(buffer, flat_file_pos);
        AssertEqualAfterSerializeDeserialize(flat_file_pos);
#elif KEY_ORIGIN_INFO_DESERIALIZE
        KeyOriginInfo key_origin_info;
        DeserializeFromFuzzingInput(buffer, key_origin_info);
        AssertEqualAfterSerializeDeserialize(key_origin_info);
#elif PARTIALLY_SIGNED_TRANSACTION_DESERIALIZE
        PartiallySignedTransaction partially_signed_transaction;
        DeserializeFromFuzzingInput(buffer, partially_signed_transaction);
#elif PREFILLED_TRANSACTION_DESERIALIZE
        PrefilledTransaction prefilled_transaction;
        DeserializeFromFuzzingInput(buffer, prefilled_transaction);
#elif PSBT_INPUT_DESERIALIZE
        PSBTInput psbt_input;
        DeserializeFromFuzzingInput(buffer, psbt_input);
#elif PSBT_OUTPUT_DESERIALIZE
        PSBTOutput psbt_output;
        DeserializeFromFuzzingInput(buffer, psbt_output);
#elif BLOCK_DESERIALIZE
        CBlock block;
        DeserializeFromFuzzingInput(buffer, block);
#elif BLOCKLOCATOR_DESERIALIZE
        CBlockLocator bl;
        DeserializeFromFuzzingInput(buffer, bl);
#elif BLOCKMERKLEROOT
        CBlock block;
        DeserializeFromFuzzingInput(buffer, block);
        bool mutated;
        BlockMerkleRoot(block, &mutated);
#elif ADDRMAN_DESERIALIZE
        CAddrMan am;
        DeserializeFromFuzzingInput(buffer, am);
#elif BLOCKHEADER_DESERIALIZE
        CBlockHeader bh;
        DeserializeFromFuzzingInput(buffer, bh);
#elif BANENTRY_DESERIALIZE
        CBanEntry be;
        DeserializeFromFuzzingInput(buffer, be);
#elif TXUNDO_DESERIALIZE
        CTxUndo tu;
        DeserializeFromFuzzingInput(buffer, tu);
#elif BLOCKUNDO_DESERIALIZE
        CBlockUndo bu;
        DeserializeFromFuzzingInput(buffer, bu);
#elif COINS_DESERIALIZE
        Coin coin;
        DeserializeFromFuzzingInput(buffer, coin);
#elif NETADDR_DESERIALIZE
        CNetAddr na;
        DeserializeFromFuzzingInput(buffer, na);
        AssertEqualAfterSerializeDeserialize(na);
#elif SERVICE_DESERIALIZE
        CService s;
        DeserializeFromFuzzingInput(buffer, s);
        AssertEqualAfterSerializeDeserialize(s);
#elif MESSAGEHEADER_DESERIALIZE
        const CMessageHeader::MessageStartChars pchMessageStart = {0x00, 0x00, 0x00, 0x00};
        CMessageHeader mh(pchMessageStart);
        DeserializeFromFuzzingInput(buffer, mh);
        (void)mh.IsValid(pchMessageStart);
#elif ADDRESS_DESERIALIZE
        CAddress a;
        DeserializeFromFuzzingInput(buffer, a);
#elif INV_DESERIALIZE
        CInv i;
        DeserializeFromFuzzingInput(buffer, i);
#elif BLOOMFILTER_DESERIALIZE
        CBloomFilter bf;
        DeserializeFromFuzzingInput(buffer, bf);
#elif DISKBLOCKINDEX_DESERIALIZE
        CDiskBlockIndex dbi;
        DeserializeFromFuzzingInput(buffer, dbi);
#elif TXOUTCOMPRESSOR_DESERIALIZE
        CTxOut to;
        CTxOutCompressor toc(to);
        DeserializeFromFuzzingInput(buffer, toc);
#elif BLOCKTRANSACTIONS_DESERIALIZE
        BlockTransactions bt;
        DeserializeFromFuzzingInput(buffer, bt);
#elif BLOCKTRANSACTIONSREQUEST_DESERIALIZE
        BlockTransactionsRequest btr;
        DeserializeFromFuzzingInput(buffer, btr);
#else
#error Need at least one fuzz target to compile
#endif
    } catch (const invalid_fuzzing_input_exception&) {
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <addrdb.h>
#include <addrman.h>
#include <blockencodings.h>
#include <blockfilter.h>
#include <chain.h>
#include <coins.h>
#include <compressor.h>
#include <consensus/merkle.h>
#include <key.h>
#include <merkleblock.h>
#include <net.h>
#include <netbase.h>
#include <node/utxo_snapshot.h>
#include <optional.h>
#include <primitives/block.h>
#include <protocol.h>
#include <psbt.h>
#include <pubkey.h>
#include <script/keyorigin.h>
#include <streams.h>
#include <undo.h>
#include <version.h>

#include <exception>
#include <stdexcept>
#include <stdint.h>
#include <unistd.h>

#include <vector>

#include <test/fuzz/fuzz.h>

void initialize()
{
    // Fuzzers using pubkey must hold an ECCVerifyHandle.
    static const ECCVerifyHandle verify_handle;
}

namespace {

struct invalid_fuzzing_input_exception : public std::exception {
};

template <typename T>
CDataStream Serialize(const T& obj, const int version = INIT_PROTO_VERSION)
{
    CDataStream ds(SER_NETWORK, version);
    ds << obj;
    return ds;
}

template <typename T>
T Deserialize(CDataStream ds)
{
    T obj;
    ds >> obj;
    return obj;
}

template <typename T>
void DeserializeFromFuzzingInput(const std::vector<uint8_t>& buffer, T& obj, const Optional<int> protocol_version = nullopt)
{
    CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
    if (protocol_version) {
        ds.SetVersion(*protocol_version);
    } else {
        try {
            int version;
            ds >> version;
            ds.SetVersion(version);
        } catch (const std::ios_base::failure&) {
            throw invalid_fuzzing_input_exception();
        }
    }
    try {
        ds >> obj;
    } catch (const std::ios_base::failure&) {
        throw invalid_fuzzing_input_exception();
    }
    assert(buffer.empty() || !Serialize(obj).empty());
}

template <typename T>
void AssertEqualAfterSerializeDeserialize(const T& obj, const int version = INIT_PROTO_VERSION)
{
    assert(Deserialize<T>(Serialize(obj, version)) == obj);
}

} // namespace

void test_one_input(const std::vector<uint8_t>& buffer)
{
    try {
#if BLOCK_FILTER_DESERIALIZE
        BlockFilter block_filter;
        DeserializeFromFuzzingInput(buffer, block_filter);
#elif ADDR_INFO_DESERIALIZE
        CAddrInfo addr_info;
        DeserializeFromFuzzingInput(buffer, addr_info);
#elif BLOCK_FILE_INFO_DESERIALIZE
        CBlockFileInfo block_file_info;
        DeserializeFromFuzzingInput(buffer, block_file_info);
#elif BLOCK_HEADER_AND_SHORT_TXIDS_DESERIALIZE
        CBlockHeaderAndShortTxIDs block_header_and_short_txids;
        DeserializeFromFuzzingInput(buffer, block_header_and_short_txids);
#elif FEE_RATE_DESERIALIZE
        CFeeRate fee_rate;
        DeserializeFromFuzzingInput(buffer, fee_rate);
        AssertEqualAfterSerializeDeserialize(fee_rate);
#elif MERKLE_BLOCK_DESERIALIZE
        CMerkleBlock merkle_block;
        DeserializeFromFuzzingInput(buffer, merkle_block);
#elif OUT_POINT_DESERIALIZE
        COutPoint out_point;
        DeserializeFromFuzzingInput(buffer, out_point);
        AssertEqualAfterSerializeDeserialize(out_point);
#elif PARTIAL_MERKLE_TREE_DESERIALIZE
        CPartialMerkleTree partial_merkle_tree;
        DeserializeFromFuzzingInput(buffer, partial_merkle_tree);
#elif PUB_KEY_DESERIALIZE
        CPubKey pub_key;
        DeserializeFromFuzzingInput(buffer, pub_key);
        // TODO: The following equivalence should hold for CPubKey? Fix.
        // AssertEqualAfterSerializeDeserialize(pub_key);
#elif SCRIPT_DESERIALIZE
        CScript script;
        DeserializeFromFuzzingInput(buffer, script);
#elif SUB_NET_DESERIALIZE
        CSubNet sub_net_1;
        DeserializeFromFuzzingInput(buffer, sub_net_1, INIT_PROTO_VERSION);
        AssertEqualAfterSerializeDeserialize(sub_net_1, INIT_PROTO_VERSION);
        CSubNet sub_net_2;
        DeserializeFromFuzzingInput(buffer, sub_net_2, INIT_PROTO_VERSION | ADDRV2_FORMAT);
        AssertEqualAfterSerializeDeserialize(sub_net_2, INIT_PROTO_VERSION | ADDRV2_FORMAT);
        CSubNet sub_net_3;
        DeserializeFromFuzzingInput(buffer, sub_net_3);
        AssertEqualAfterSerializeDeserialize(sub_net_3, INIT_PROTO_VERSION | ADDRV2_FORMAT);
#elif TX_IN_DESERIALIZE
        CTxIn tx_in;
        DeserializeFromFuzzingInput(buffer, tx_in);
        AssertEqualAfterSerializeDeserialize(tx_in);
#elif FLAT_FILE_POS_DESERIALIZE
        FlatFilePos flat_file_pos;
        DeserializeFromFuzzingInput(buffer, flat_file_pos);
        AssertEqualAfterSerializeDeserialize(flat_file_pos);
#elif KEY_ORIGIN_INFO_DESERIALIZE
        KeyOriginInfo key_origin_info;
        DeserializeFromFuzzingInput(buffer, key_origin_info);
        AssertEqualAfterSerializeDeserialize(key_origin_info);
#elif PARTIALLY_SIGNED_TRANSACTION_DESERIALIZE
        PartiallySignedTransaction partially_signed_transaction;
        DeserializeFromFuzzingInput(buffer, partially_signed_transaction);
#elif PREFILLED_TRANSACTION_DESERIALIZE
        PrefilledTransaction prefilled_transaction;
        DeserializeFromFuzzingInput(buffer, prefilled_transaction);
#elif PSBT_INPUT_DESERIALIZE
        PSBTInput psbt_input;
        DeserializeFromFuzzingInput(buffer, psbt_input);
#elif PSBT_OUTPUT_DESERIALIZE
        PSBTOutput psbt_output;
        DeserializeFromFuzzingInput(buffer, psbt_output);
#elif BLOCK_DESERIALIZE
        CBlock block;
        DeserializeFromFuzzingInput(buffer, block);
#elif BLOCKLOCATOR_DESERIALIZE
        CBlockLocator bl;
        DeserializeFromFuzzingInput(buffer, bl);
#elif BLOCKMERKLEROOT
        CBlock block;
        DeserializeFromFuzzingInput(buffer, block);
        bool mutated;
        BlockMerkleRoot(block, &mutated);
#elif ADDRMAN_DESERIALIZE
        CAddrMan am;
        DeserializeFromFuzzingInput(buffer, am);
#elif BLOCKHEADER_DESERIALIZE
        CBlockHeader bh;
        DeserializeFromFuzzingInput(buffer, bh);
#elif BANENTRY_DESERIALIZE
        CBanEntry be;
        DeserializeFromFuzzingInput(buffer, be);
#elif TXUNDO_DESERIALIZE
        CTxUndo tu;
        DeserializeFromFuzzingInput(buffer, tu);
#elif BLOCKUNDO_DESERIALIZE
        CBlockUndo bu;
        DeserializeFromFuzzingInput(buffer, bu);
#elif COINS_DESERIALIZE
        Coin coin;
        DeserializeFromFuzzingInput(buffer, coin);
#elif NETADDR_DESERIALIZE
        CNetAddr na;
        DeserializeFromFuzzingInput(buffer, na);
        if (na.IsAddrV1Compatible()) {
            AssertEqualAfterSerializeDeserialize(na);
        }
        AssertEqualAfterSerializeDeserialize(na, INIT_PROTO_VERSION | ADDRV2_FORMAT);
#elif SERVICE_DESERIALIZE
        CService s;
        DeserializeFromFuzzingInput(buffer, s);
        if (s.IsAddrV1Compatible()) {
            AssertEqualAfterSerializeDeserialize(s);
        }
        AssertEqualAfterSerializeDeserialize(s, INIT_PROTO_VERSION | ADDRV2_FORMAT);
#elif MESSAGEHEADER_DESERIALIZE
        CMessageHeader mh;
        DeserializeFromFuzzingInput(buffer, mh);
        (void)mh.IsCommandValid();
#elif ADDRESS_DESERIALIZE
        CAddress a;
        DeserializeFromFuzzingInput(buffer, a);
#elif INV_DESERIALIZE
        CInv i;
        DeserializeFromFuzzingInput(buffer, i);
#elif BLOOMFILTER_DESERIALIZE
        CBloomFilter bf;
        DeserializeFromFuzzingInput(buffer, bf);
#elif DISKBLOCKINDEX_DESERIALIZE
        CDiskBlockIndex dbi;
        DeserializeFromFuzzingInput(buffer, dbi);
#elif TXOUTCOMPRESSOR_DESERIALIZE
        CTxOut to;
        auto toc = Using<TxOutCompression>(to);
        DeserializeFromFuzzingInput(buffer, toc);
#elif BLOCKTRANSACTIONS_DESERIALIZE
        BlockTransactions bt;
        DeserializeFromFuzzingInput(buffer, bt);
#elif BLOCKTRANSACTIONSREQUEST_DESERIALIZE
        BlockTransactionsRequest btr;
        DeserializeFromFuzzingInput(buffer, btr);
#elif SNAPSHOTMETADATA_DESERIALIZE
        SnapshotMetadata snapshot_metadata;
        DeserializeFromFuzzingInput(buffer, snapshot_metadata);
#elif UINT160_DESERIALIZE
        uint160 u160;
        DeserializeFromFuzzingInput(buffer, u160);
        AssertEqualAfterSerializeDeserialize(u160);
#elif UINT256_DESERIALIZE
        uint256 u256;
        DeserializeFromFuzzingInput(buffer, u256);
        AssertEqualAfterSerializeDeserialize(u256);
#else
#error Need at least one fuzz target to compile
#endif
        // Classes intentionally not covered in this file since their deserialization code is
        // fuzzed elsewhere:
        // * Deserialization of CTxOut is fuzzed in test/fuzz/tx_out.cpp
        // * Deserialization of CMutableTransaction is fuzzed in src/test/fuzz/transaction.cpp
    } catch (const invalid_fuzzing_input_exception&) {
    }
}
<commit_msg>fuzz: Assert roundtrip equality for both addrv1 and addrv2 versions of CService<commit_after>// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <addrdb.h>
#include <addrman.h>
#include <blockencodings.h>
#include <blockfilter.h>
#include <chain.h>
#include <coins.h>
#include <compressor.h>
#include <consensus/merkle.h>
#include <key.h>
#include <merkleblock.h>
#include <net.h>
#include <netbase.h>
#include <node/utxo_snapshot.h>
#include <optional.h>
#include <primitives/block.h>
#include <protocol.h>
#include <psbt.h>
#include <pubkey.h>
#include <script/keyorigin.h>
#include <streams.h>
#include <undo.h>
#include <version.h>

#include <exception>
#include <stdexcept>
#include <stdint.h>
#include <unistd.h>

#include <vector>

#include <test/fuzz/fuzz.h>

void initialize()
{
    // Fuzzers using pubkey must hold an ECCVerifyHandle.
    static const ECCVerifyHandle verify_handle;
}

namespace {

struct invalid_fuzzing_input_exception : public std::exception {
};

template <typename T>
CDataStream Serialize(const T& obj, const int version = INIT_PROTO_VERSION)
{
    CDataStream ds(SER_NETWORK, version);
    ds << obj;
    return ds;
}

template <typename T>
T Deserialize(CDataStream ds)
{
    T obj;
    ds >> obj;
    return obj;
}

template <typename T>
void DeserializeFromFuzzingInput(const std::vector<uint8_t>& buffer, T& obj, const Optional<int> protocol_version = nullopt)
{
    CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
    if (protocol_version) {
        ds.SetVersion(*protocol_version);
    } else {
        try {
            int version;
            ds >> version;
            ds.SetVersion(version);
        } catch (const std::ios_base::failure&) {
            throw invalid_fuzzing_input_exception();
        }
    }
    try {
        ds >> obj;
    } catch (const std::ios_base::failure&) {
        throw invalid_fuzzing_input_exception();
    }
    assert(buffer.empty() || !Serialize(obj).empty());
}

template <typename T>
void AssertEqualAfterSerializeDeserialize(const T& obj, const int version = INIT_PROTO_VERSION)
{
    assert(Deserialize<T>(Serialize(obj, version)) == obj);
}

} // namespace

void test_one_input(const std::vector<uint8_t>& buffer)
{
    try {
#if BLOCK_FILTER_DESERIALIZE
        BlockFilter block_filter;
        DeserializeFromFuzzingInput(buffer, block_filter);
#elif ADDR_INFO_DESERIALIZE
        CAddrInfo addr_info;
        DeserializeFromFuzzingInput(buffer, addr_info);
#elif BLOCK_FILE_INFO_DESERIALIZE
        CBlockFileInfo block_file_info;
        DeserializeFromFuzzingInput(buffer, block_file_info);
#elif BLOCK_HEADER_AND_SHORT_TXIDS_DESERIALIZE
        CBlockHeaderAndShortTxIDs block_header_and_short_txids;
        DeserializeFromFuzzingInput(buffer, block_header_and_short_txids);
#elif FEE_RATE_DESERIALIZE
        CFeeRate fee_rate;
        DeserializeFromFuzzingInput(buffer, fee_rate);
        AssertEqualAfterSerializeDeserialize(fee_rate);
#elif MERKLE_BLOCK_DESERIALIZE
        CMerkleBlock merkle_block;
        DeserializeFromFuzzingInput(buffer, merkle_block);
#elif OUT_POINT_DESERIALIZE
        COutPoint out_point;
        DeserializeFromFuzzingInput(buffer, out_point);
        AssertEqualAfterSerializeDeserialize(out_point);
#elif PARTIAL_MERKLE_TREE_DESERIALIZE
        CPartialMerkleTree partial_merkle_tree;
        DeserializeFromFuzzingInput(buffer, partial_merkle_tree);
#elif PUB_KEY_DESERIALIZE
        CPubKey pub_key;
        DeserializeFromFuzzingInput(buffer, pub_key);
        // TODO: The following equivalence should hold for CPubKey? Fix.
        // AssertEqualAfterSerializeDeserialize(pub_key);
#elif SCRIPT_DESERIALIZE
        CScript script;
        DeserializeFromFuzzingInput(buffer, script);
#elif SUB_NET_DESERIALIZE
        CSubNet sub_net_1;
        DeserializeFromFuzzingInput(buffer, sub_net_1, INIT_PROTO_VERSION);
        AssertEqualAfterSerializeDeserialize(sub_net_1, INIT_PROTO_VERSION);
        CSubNet sub_net_2;
        DeserializeFromFuzzingInput(buffer, sub_net_2, INIT_PROTO_VERSION | ADDRV2_FORMAT);
        AssertEqualAfterSerializeDeserialize(sub_net_2, INIT_PROTO_VERSION | ADDRV2_FORMAT);
        CSubNet sub_net_3;
        DeserializeFromFuzzingInput(buffer, sub_net_3);
        AssertEqualAfterSerializeDeserialize(sub_net_3, INIT_PROTO_VERSION | ADDRV2_FORMAT);
#elif TX_IN_DESERIALIZE
        CTxIn tx_in;
        DeserializeFromFuzzingInput(buffer, tx_in);
        AssertEqualAfterSerializeDeserialize(tx_in);
#elif FLAT_FILE_POS_DESERIALIZE
        FlatFilePos flat_file_pos;
        DeserializeFromFuzzingInput(buffer, flat_file_pos);
        AssertEqualAfterSerializeDeserialize(flat_file_pos);
#elif KEY_ORIGIN_INFO_DESERIALIZE
        KeyOriginInfo key_origin_info;
        DeserializeFromFuzzingInput(buffer, key_origin_info);
        AssertEqualAfterSerializeDeserialize(key_origin_info);
#elif PARTIALLY_SIGNED_TRANSACTION_DESERIALIZE
        PartiallySignedTransaction partially_signed_transaction;
        DeserializeFromFuzzingInput(buffer, partially_signed_transaction);
#elif PREFILLED_TRANSACTION_DESERIALIZE
        PrefilledTransaction prefilled_transaction;
        DeserializeFromFuzzingInput(buffer, prefilled_transaction);
#elif PSBT_INPUT_DESERIALIZE
        PSBTInput psbt_input;
        DeserializeFromFuzzingInput(buffer, psbt_input);
#elif PSBT_OUTPUT_DESERIALIZE
        PSBTOutput psbt_output;
        DeserializeFromFuzzingInput(buffer, psbt_output);
#elif BLOCK_DESERIALIZE
        CBlock block;
        DeserializeFromFuzzingInput(buffer, block);
#elif BLOCKLOCATOR_DESERIALIZE
        CBlockLocator bl;
        DeserializeFromFuzzingInput(buffer, bl);
#elif BLOCKMERKLEROOT
        CBlock block;
        DeserializeFromFuzzingInput(buffer, block);
        bool mutated;
        BlockMerkleRoot(block, &mutated);
#elif ADDRMAN_DESERIALIZE
        CAddrMan am;
        DeserializeFromFuzzingInput(buffer, am);
#elif BLOCKHEADER_DESERIALIZE
        CBlockHeader bh;
        DeserializeFromFuzzingInput(buffer, bh);
#elif BANENTRY_DESERIALIZE
        CBanEntry be;
        DeserializeFromFuzzingInput(buffer, be);
#elif TXUNDO_DESERIALIZE
        CTxUndo tu;
        DeserializeFromFuzzingInput(buffer, tu);
#elif BLOCKUNDO_DESERIALIZE
        CBlockUndo bu;
        DeserializeFromFuzzingInput(buffer, bu);
#elif COINS_DESERIALIZE
        Coin coin;
        DeserializeFromFuzzingInput(buffer, coin);
#elif NETADDR_DESERIALIZE
        CNetAddr na;
        DeserializeFromFuzzingInput(buffer, na);
        if (na.IsAddrV1Compatible()) {
            AssertEqualAfterSerializeDeserialize(na);
        }
        AssertEqualAfterSerializeDeserialize(na, INIT_PROTO_VERSION | ADDRV2_FORMAT);
#elif SERVICE_DESERIALIZE
        CService s;
        DeserializeFromFuzzingInput(buffer, s);
        if (s.IsAddrV1Compatible()) {
            AssertEqualAfterSerializeDeserialize(s);
        }
        AssertEqualAfterSerializeDeserialize(s, INIT_PROTO_VERSION | ADDRV2_FORMAT);
        CService s1;
        DeserializeFromFuzzingInput(buffer, s1, INIT_PROTO_VERSION);
        AssertEqualAfterSerializeDeserialize(s1, INIT_PROTO_VERSION);
        assert(s1.IsAddrV1Compatible());
        CService s2;
        DeserializeFromFuzzingInput(buffer, s2, INIT_PROTO_VERSION | ADDRV2_FORMAT);
        AssertEqualAfterSerializeDeserialize(s2, INIT_PROTO_VERSION | ADDRV2_FORMAT);
#elif MESSAGEHEADER_DESERIALIZE
        CMessageHeader mh;
        DeserializeFromFuzzingInput(buffer, mh);
        (void)mh.IsCommandValid();
#elif ADDRESS_DESERIALIZE
        CAddress a;
        DeserializeFromFuzzingInput(buffer, a);
#elif INV_DESERIALIZE
        CInv i;
        DeserializeFromFuzzingInput(buffer, i);
#elif BLOOMFILTER_DESERIALIZE
        CBloomFilter bf;
        DeserializeFromFuzzingInput(buffer, bf);
#elif DISKBLOCKINDEX_DESERIALIZE
        CDiskBlockIndex dbi;
        DeserializeFromFuzzingInput(buffer, dbi);
#elif TXOUTCOMPRESSOR_DESERIALIZE
        CTxOut to;
        auto toc = Using<TxOutCompression>(to);
        DeserializeFromFuzzingInput(buffer, toc);
#elif BLOCKTRANSACTIONS_DESERIALIZE
        BlockTransactions bt;
        DeserializeFromFuzzingInput(buffer, bt);
#elif BLOCKTRANSACTIONSREQUEST_DESERIALIZE
        BlockTransactionsRequest btr;
        DeserializeFromFuzzingInput(buffer, btr);
#elif SNAPSHOTMETADATA_DESERIALIZE
        SnapshotMetadata snapshot_metadata;
        DeserializeFromFuzzingInput(buffer, snapshot_metadata);
#elif UINT160_DESERIALIZE
        uint160 u160;
        DeserializeFromFuzzingInput(buffer, u160);
        AssertEqualAfterSerializeDeserialize(u160);
#elif UINT256_DESERIALIZE
        uint256 u256;
        DeserializeFromFuzzingInput(buffer, u256);
        AssertEqualAfterSerializeDeserialize(u256);
#else
#error Need at least one fuzz target to compile
#endif
        // Classes intentionally not covered in this file since their deserialization code is
        // fuzzed elsewhere:
        // * Deserialization of CTxOut is fuzzed in test/fuzz/tx_out.cpp
        // * Deserialization of CMutableTransaction is fuzzed in src/test/fuzz/transaction.cpp
    } catch (const invalid_fuzzing_input_exception&) {
    }
}
<|endoftext|>


<commit_before>#include <taichi/testing.h>
#include "../tlang.h"

TLANG_NAMESPACE_BEGIN

TC_TEST("snode") {
  Program prog(Arch::x86_64);

  auto i = Index(0);
  Global(u, i32);

  int n = 128;

  // All data structure originates from a "root", which is a forked node.
  prog.layout([&] { root.fixed(i, n).place(u); });

  for (int i = 0; i < n; i++) {
    u.val<int32>(i) = i + 1;
  }

  for (int i = 0; i < n; i++) {
    TC_CHECK_EQUAL(u.val<int32>(i), i + 1, 0);
  }
}

TC_TEST("snode_loop") {
  Program prog(Arch::x86_64);
  CoreState::set_trigger_gdb_when_crash(true);
  prog.config.print_ir = true;

  auto i = Index(0);
  Global(u, i32);

  int n = 128;

  // All data structure originates from a "root", which is a forked node.
  prog.layout([&] { root.fixed(i, n).place(u); });

  auto set = kernel([&] {
    Declare(i);
    For(i, u, [&] { u[i] = i * 2; });
  });

  set();

  for (int i = 0; i < n; i++) {
    TC_CHECK_EQUAL(u.val<int32>(i), i * 2, 0);
  }
}

TC_TEST("2d_blocked_array") {
  int n = 32, block_size = 16;

  for (auto forked : {true, false}) {
    Program prog(Arch::x86_64);

    Global(a, i32);
    Global(b, i32);

    layout([&] {
      auto i = Index(0);
      auto j = Index(1);
      if (!forked) {
        TC_ASSERT(n % block_size == 0);
        root.fixed({i, j}, {n / block_size, n * 2 / block_size})
            .fixed({i, j}, {block_size, block_size})
            .place(a, b);
      } else {
        root.fixed({i, j}, {n, n * 2}).place(a);
        root.fixed({i, j}, {n, n * 2}).place(b);
      }
    });

    auto inc = kernel([&]() {
      Declare(i);
      Declare(j);
      For({i, j}, a, [&] { b[i, j] = a[i, j] + i; });
    });

    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n * 2; j++) {
        a.val<int32>(i, j) = i + j * 3;
      }
    }

    inc();

    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n * 2; j++) {
        TC_CHECK(a.val<int32>(i, j) == i + j * 3);
        TC_CHECK(b.val<int32>(i, j) == i * 2 + j * 3);
      }
    }
  }
}

#if (0)

TC_TEST("spmv") {
  initialize_benchmark();
  int n = 8192;
  int band = 256;
  int k = 128;
  TC_ASSERT(k <= band);
  int m = n * k;

  Eigen::SparseMatrix<float32, Eigen::RowMajor> M(n, n);
  Eigen::VectorXf V(n), Vret(n);

  Program prog;
  prog.config.simd_width = 4;
  prog.config.external_optimization_level = 4;

  auto result = var<float32>();
  auto mat_col = var<int32>();
  auto mat_row = var<int32>();
  auto mat_val = var<float32>();
  auto vec_val = var<float32>();
  auto compressed_col = var<int32>();
  auto compressed_val = var<float32>();

  auto i = ind(), j = ind(), p = ind();

  std::vector<Eigen::Triplet<float32>> entries;

  layout([&] {
    // indirect puts an int32
    root.fixed(p, m).place(mat_row);
    root.fixed(p, m).place(mat_col);
    root.fixed(p, m).place(mat_val);
    auto &mat = root.fixed(i, n).multi_threaded();
    mat.dynamic(j, k).place(compressed_col);
    mat.dynamic(j, k).place(compressed_val);
    root.fixed(i, n).place(vec_val);
    root.fixed(i, n).place(result);
  });

  auto populate = kernel(mat_row, [&]() {
    touch(compressed_col, mat_row[p], mat_col[p]);
    touch(compressed_val, mat_row[p], mat_val[p]);
  });

  auto matvecmul = kernel(compressed_col, [&]() {
    auto entry = compressed_val[i, j] * vec_val[compressed_col[i, j]];
    reduce(result[i], entry);
  });

  for (int i = 0; i < n; i++) {
    std::set<int> cols;
    for (int j = 0; j < k; j++) {
      int col;
      while (true) {
        col = std::rand() % (2 * band) - band + i;
        if (col < 0 || col >= n)
          continue;
        if (cols.find(col) == cols.end()) {
          break;
        }
      }
      cols.insert(col);
      auto val = rand();
      entries.push_back({i, col, val});
      mat_row.val<int32>(i * k + j) = i;
      mat_col.val<int32>(i * k + j) = col;
      mat_val.val<float32>(i * k + j) = val;
    }
    auto val = rand();
    V(i) = val;
    vec_val.val<float32>(i) = val;
  }

  TC_TIME(M.setFromTriplets(entries.begin(), entries.end()));

  TC_TIME(populate());

  int T = 1;
  for (int i = 0; i < T; i++) {
    TC_TIME(matvecmul());
  }

  TC_P(n = Eigen::nbThreads());
  for (int i = 0; i < T; i++) {
    TC_TIME(Vret = M * V);
  }

  for (int i = 0; i < n; i++) {
    TC_CHECK_EQUAL(Vret(i), result.val<float32>(i) / T, 1e-3_f);
  }
}

TC_TEST("spmv_dynamic") {
  initialize_benchmark();
  int n = 8192;
  int band = 256;
  int k = 128;
  TC_ASSERT(k <= band);
  int m = n * k;

  Eigen::SparseMatrix<float32, Eigen::RowMajor> M(n, n);
  Eigen::VectorXf V(n), Vret(n);

  Program prog;
  prog.config.external_optimization_level = 4;

  auto result = var<float32>();
  auto mat_col = var<int32>();
  auto mat_row = var<int32>();
  auto mat_val = var<float32>();
  auto vec_val = var<float32>();
  auto compressed_col = var<int32>();
  auto compressed_val = var<float32>();

  auto i = ind(), j = ind(), p = ind();

  std::vector<Eigen::Triplet<float32>> entries;

  layout([&] {
    // indirect puts an int32
    root.dynamic(p, m).place(mat_row);
    root.dynamic(p, m).place(mat_col);
    root.dynamic(p, m).place(mat_val);
    auto &mat = root.fixed(i, n).multi_threaded();
    mat.dynamic(j, k).place(compressed_col);
    mat.dynamic(j, k).place(compressed_val);
    root.fixed(i, n).place(vec_val);
    root.fixed(i, n).place(result);
  });

  auto populate = kernel(mat_row, [&]() {
    touch(compressed_col, mat_row[p], mat_col[p]);
    touch(compressed_val, mat_row[p], mat_val[p]);
  });

  auto matvecmul = kernel(compressed_col, [&]() {
    auto entry = compressed_val[i, j] * vec_val[compressed_col[i, j]];
    reduce(result[i], entry);
  });

  int num_entries = 0;
  for (int i = 0; i < n; i++) {
    std::set<int> cols;
    int sub = rand_int() % 32;
    for (int j = 0; j < k - sub; j++) {
      int col;
      while (true) {
        col = std::rand() % (2 * band) - band + i;
        if (col < 0 || col >= n)
          continue;
        if (cols.find(col) == cols.end()) {
          break;
        }
      }
      cols.insert(col);
      auto val = rand();
      entries.push_back({i, col, val});
      mat_row.val<int32>(num_entries) = i;
      mat_col.val<int32>(num_entries) = col;
      mat_val.val<float32>(num_entries) = val;
      num_entries++;
    }
    auto val = rand();
    V(i) = val;
    vec_val.val<float32>(i) = val;
  }

  TC_TIME(M.setFromTriplets(entries.begin(), entries.end()));

  TC_TIME(populate());

  int T = 30;
  for (int i = 0; i < T; i++) {
    TC_TIME(matvecmul());
  }

  TC_P(n = Eigen::nbThreads());
  for (int i = 0; i < T; i++) {
    TC_TIME(Vret = M * V);
  }

  for (int i = 0; i < n; i++) {
    TC_CHECK_EQUAL(Vret(i), result.val<float32>(i) / T, 1e-3_f);
  }
}

// array of linked list
TC_TEST("indirect") {
  Program prog;

  int n = 4;
  int k = 8;
  int m = n * k;

  Global(a, i32);
  Global(sum, i32);

  SNode *snode;

  layout([&] {
    auto i = Index(0), j = Index(1);
    // indirect puts an int32
    snode = &root.fixed(i, n).indirect(j, k * 2);
    root.fixed(j, m).place(a);
    root.fixed(i, n).place(sum);
  });

  auto populate = kernel([&]() {
    Declare(j);

    // the second
    touch(snode, load(a[j]) / imm(k), j);  // put main index into snode sparsity
  });

  auto inc = kernel(a, [&]() { a[j] = a[j] + imm(1); });

  auto red = kernel(snode, [&]() { reduce(sum[i], a[j]); });

  for (int i = 0; i < m; i++) {
    a.val<int32>(i) = i;
  }

  populate();
  inc();
  red();

  for (int i = 0; i < n; i++) {
    auto reduced = sum.val<int32>(i);
    TC_CHECK(reduced == (i * k + (i + 1) * k + 1) * k / 2);
  }
}
#endif

TC_TEST("leaf_context") {
  Program prog;

  int n = 64;
  int k = 32;
  int m = n * k;

  Global(a, i32);
  Global(sum, i32);

  layout([&] {
    auto i = Index(0);
    root.fixed(i, n).fixed(i, k).place(a);
    root.place(sum);
  });

  int sum_gt = 0;
  for (int i = 0; i < m; i++) {
    if (i / k % 3 == 1) {
      a.val<int32>(i) = i;
      sum_gt += i;
    }
  }

  kernel([&]() {
    Declare(i);
    For(i, a, [&] {sum[Expr(0)] += a[i]; });
  })();

  TC_CHECK(sum.val<int32>() == sum_gt);
}

TC_TEST("pointer") {
  Program prog;

  int n = 32;
  int k = 64;
  int m = n * k;

  Global(a, i32);
  Global(sum, i32);

  layout([&] {
    auto i = Index(0);
    root.fixed(i, n).pointer().fixed(i, k).place(a);
    root.place(sum);
  });

  auto red = kernel([&]() {
    Declare(i);
    For(i, a, [&] { sum[Expr(0)] += a[i]; });
  });

  int sum_gt = 0;
  for (int i = 0; i < m; i++) {
    if (i / k % 3 == 1) {
      a.val<int32>(i) = i;
      sum_gt += i;
    }
  }

  red();

  auto reduced = sum.val<int32>();
  TC_CHECK(reduced == sum_gt);
}

TC_TEST("hashed") {
  Program prog;

  int n = 64;
  int k = 128;
  int m = n * k;

  Global(a, i32);
  Global(sum, i32);

  layout([&] {
    auto i = Index(0);
    root.hashed(i, n).fixed(i, k).place(a);
    root.place(sum);
  });

  auto red = kernel([&]() {
    Declare(i);
    For(i, a, [&] { sum[Expr(0)] += a[i]; });
  });
  sum.val<int32>() = 0;

  int sum_gt = 0;
  for (int i = 0; i < m; i++) {
    if (i / k % 3 == 1) {
      a.val<int32>(i) = 1;
      sum_gt += 1;
    }
  }

  red();

  auto reduced = sum.val<int32>();
  TC_CHECK(reduced == sum_gt);
}

TC_TEST("box_filter") {
  return;
  Program prog;

  int n = 64;
  int k = 128;
  int m = n * k;

  Global(x, i32);
  Global(y, i32);

  layout([&] {
    auto i = Index(0);
    root.hashed(i, n).fixed(i, k).place(x, y);
  });

  auto red = kernel([&]() {
    Declare(i);
    For(i, x, [&] { y[i] = x[i - 1] + x[i] + x[i + 1]; });
  });

  red();

  // auto reduced = sum.val<int32>();
  // TC_CHECK(reduced == sum_gt);
}

TLANG_NAMESPACE_END
<commit_msg>test separete i, j indices<commit_after>#include <taichi/testing.h>
#include "../tlang.h"

TLANG_NAMESPACE_BEGIN

TC_TEST("snode") {
  Program prog(Arch::x86_64);

  auto i = Index(0);
  Global(u, i32);

  int n = 128;

  // All data structure originates from a "root", which is a forked node.
  prog.layout([&] { root.fixed(i, n).place(u); });

  for (int i = 0; i < n; i++) {
    u.val<int32>(i) = i + 1;
  }

  for (int i = 0; i < n; i++) {
    TC_CHECK_EQUAL(u.val<int32>(i), i + 1, 0);
  }
}

TC_TEST("snode_loop") {
  Program prog(Arch::x86_64);
  CoreState::set_trigger_gdb_when_crash(true);
  prog.config.print_ir = true;

  auto i = Index(0);
  Global(u, i32);

  int n = 128;

  // All data structure originates from a "root", which is a forked node.
  prog.layout([&] { root.fixed(i, n).place(u); });

  auto set = kernel([&] {
    Declare(i);
    For(i, u, [&] { u[i] = i * 2; });
  });

  set();

  for (int i = 0; i < n; i++) {
    TC_CHECK_EQUAL(u.val<int32>(i), i * 2, 0);
  }
}

TC_TEST("snode_loop2") {
  Program prog(Arch::x86_64);
  CoreState::set_trigger_gdb_when_crash(true);
  prog.config.print_ir = true;

  auto i = Index(0), j = Index(1);
  Global(u, i32);
  Global(v, i32);

  int n = 128;

  // All data structure originates from a "root", which is a forked node.
  prog.layout([&] { root.fixed(i, n).place(u); root.fixed(j, n).place(v); });

  auto set1 = kernel([&] {
    Declare(i);
    For(i, u, [&] { u[i] = i * 2; });
  });

  auto set2 = kernel([&] {
    Declare(j);
    For(j, v, [&] { v[j] = j * 3; });
  });

  set1();
  set2();

  for (int i = 0; i < n; i++) {
    TC_CHECK_EQUAL(u.val<int32>(i), i * 2, 0);
    TC_CHECK_EQUAL(v.val<int32>(i), i * 3, 0);
  }
}

TC_TEST("2d_blocked_array") {
  int n = 32, block_size = 16;

  for (auto forked : {true, false}) {
    Program prog(Arch::x86_64);

    Global(a, i32);
    Global(b, i32);

    layout([&] {
      auto i = Index(0);
      auto j = Index(1);
      if (!forked) {
        TC_ASSERT(n % block_size == 0);
        root.fixed({i, j}, {n / block_size, n * 2 / block_size})
            .fixed({i, j}, {block_size, block_size})
            .place(a, b);
      } else {
        root.fixed({i, j}, {n, n * 2}).place(a);
        root.fixed({i, j}, {n, n * 2}).place(b);
      }
    });

    auto inc = kernel([&]() {
      Declare(i);
      Declare(j);
      For({i, j}, a, [&] { b[i, j] = a[i, j] + i; });
    });

    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n * 2; j++) {
        a.val<int32>(i, j) = i + j * 3;
      }
    }

    inc();

    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n * 2; j++) {
        TC_CHECK(a.val<int32>(i, j) == i + j * 3);
        TC_CHECK(b.val<int32>(i, j) == i * 2 + j * 3);
      }
    }
  }
}

#if (0)

TC_TEST("spmv") {
  initialize_benchmark();
  int n = 8192;
  int band = 256;
  int k = 128;
  TC_ASSERT(k <= band);
  int m = n * k;

  Eigen::SparseMatrix<float32, Eigen::RowMajor> M(n, n);
  Eigen::VectorXf V(n), Vret(n);

  Program prog;
  prog.config.simd_width = 4;
  prog.config.external_optimization_level = 4;

  auto result = var<float32>();
  auto mat_col = var<int32>();
  auto mat_row = var<int32>();
  auto mat_val = var<float32>();
  auto vec_val = var<float32>();
  auto compressed_col = var<int32>();
  auto compressed_val = var<float32>();

  auto i = ind(), j = ind(), p = ind();

  std::vector<Eigen::Triplet<float32>> entries;

  layout([&] {
    // indirect puts an int32
    root.fixed(p, m).place(mat_row);
    root.fixed(p, m).place(mat_col);
    root.fixed(p, m).place(mat_val);
    auto &mat = root.fixed(i, n).multi_threaded();
    mat.dynamic(j, k).place(compressed_col);
    mat.dynamic(j, k).place(compressed_val);
    root.fixed(i, n).place(vec_val);
    root.fixed(i, n).place(result);
  });

  auto populate = kernel(mat_row, [&]() {
    touch(compressed_col, mat_row[p], mat_col[p]);
    touch(compressed_val, mat_row[p], mat_val[p]);
  });

  auto matvecmul = kernel(compressed_col, [&]() {
    auto entry = compressed_val[i, j] * vec_val[compressed_col[i, j]];
    reduce(result[i], entry);
  });

  for (int i = 0; i < n; i++) {
    std::set<int> cols;
    for (int j = 0; j < k; j++) {
      int col;
      while (true) {
        col = std::rand() % (2 * band) - band + i;
        if (col < 0 || col >= n)
          continue;
        if (cols.find(col) == cols.end()) {
          break;
        }
      }
      cols.insert(col);
      auto val = rand();
      entries.push_back({i, col, val});
      mat_row.val<int32>(i * k + j) = i;
      mat_col.val<int32>(i * k + j) = col;
      mat_val.val<float32>(i * k + j) = val;
    }
    auto val = rand();
    V(i) = val;
    vec_val.val<float32>(i) = val;
  }

  TC_TIME(M.setFromTriplets(entries.begin(), entries.end()));

  TC_TIME(populate());

  int T = 1;
  for (int i = 0; i < T; i++) {
    TC_TIME(matvecmul());
  }

  TC_P(n = Eigen::nbThreads());
  for (int i = 0; i < T; i++) {
    TC_TIME(Vret = M * V);
  }

  for (int i = 0; i < n; i++) {
    TC_CHECK_EQUAL(Vret(i), result.val<float32>(i) / T, 1e-3_f);
  }
}

TC_TEST("spmv_dynamic") {
  initialize_benchmark();
  int n = 8192;
  int band = 256;
  int k = 128;
  TC_ASSERT(k <= band);
  int m = n * k;

  Eigen::SparseMatrix<float32, Eigen::RowMajor> M(n, n);
  Eigen::VectorXf V(n), Vret(n);

  Program prog;
  prog.config.external_optimization_level = 4;

  auto result = var<float32>();
  auto mat_col = var<int32>();
  auto mat_row = var<int32>();
  auto mat_val = var<float32>();
  auto vec_val = var<float32>();
  auto compressed_col = var<int32>();
  auto compressed_val = var<float32>();

  auto i = ind(), j = ind(), p = ind();

  std::vector<Eigen::Triplet<float32>> entries;

  layout([&] {
    // indirect puts an int32
    root.dynamic(p, m).place(mat_row);
    root.dynamic(p, m).place(mat_col);
    root.dynamic(p, m).place(mat_val);
    auto &mat = root.fixed(i, n).multi_threaded();
    mat.dynamic(j, k).place(compressed_col);
    mat.dynamic(j, k).place(compressed_val);
    root.fixed(i, n).place(vec_val);
    root.fixed(i, n).place(result);
  });

  auto populate = kernel(mat_row, [&]() {
    touch(compressed_col, mat_row[p], mat_col[p]);
    touch(compressed_val, mat_row[p], mat_val[p]);
  });

  auto matvecmul = kernel(compressed_col, [&]() {
    auto entry = compressed_val[i, j] * vec_val[compressed_col[i, j]];
    reduce(result[i], entry);
  });

  int num_entries = 0;
  for (int i = 0; i < n; i++) {
    std::set<int> cols;
    int sub = rand_int() % 32;
    for (int j = 0; j < k - sub; j++) {
      int col;
      while (true) {
        col = std::rand() % (2 * band) - band + i;
        if (col < 0 || col >= n)
          continue;
        if (cols.find(col) == cols.end()) {
          break;
        }
      }
      cols.insert(col);
      auto val = rand();
      entries.push_back({i, col, val});
      mat_row.val<int32>(num_entries) = i;
      mat_col.val<int32>(num_entries) = col;
      mat_val.val<float32>(num_entries) = val;
      num_entries++;
    }
    auto val = rand();
    V(i) = val;
    vec_val.val<float32>(i) = val;
  }

  TC_TIME(M.setFromTriplets(entries.begin(), entries.end()));

  TC_TIME(populate());

  int T = 30;
  for (int i = 0; i < T; i++) {
    TC_TIME(matvecmul());
  }

  TC_P(n = Eigen::nbThreads());
  for (int i = 0; i < T; i++) {
    TC_TIME(Vret = M * V);
  }

  for (int i = 0; i < n; i++) {
    TC_CHECK_EQUAL(Vret(i), result.val<float32>(i) / T, 1e-3_f);
  }
}

// array of linked list
TC_TEST("indirect") {
  Program prog;

  int n = 4;
  int k = 8;
  int m = n * k;

  Global(a, i32);
  Global(sum, i32);

  SNode *snode;

  layout([&] {
    auto i = Index(0), j = Index(1);
    // indirect puts an int32
    snode = &root.fixed(i, n).indirect(j, k * 2);
    root.fixed(j, m).place(a);
    root.fixed(i, n).place(sum);
  });

  auto populate = kernel([&]() {
    Declare(j);

    // the second
    touch(snode, load(a[j]) / imm(k), j);  // put main index into snode sparsity
  });

  auto inc = kernel(a, [&]() { a[j] = a[j] + imm(1); });

  auto red = kernel(snode, [&]() { reduce(sum[i], a[j]); });

  for (int i = 0; i < m; i++) {
    a.val<int32>(i) = i;
  }

  populate();
  inc();
  red();

  for (int i = 0; i < n; i++) {
    auto reduced = sum.val<int32>(i);
    TC_CHECK(reduced == (i * k + (i + 1) * k + 1) * k / 2);
  }
}
#endif

TC_TEST("leaf_context") {
  Program prog;

  int n = 64;
  int k = 32;
  int m = n * k;

  Global(a, i32);
  Global(sum, i32);

  layout([&] {
    auto i = Index(0);
    root.fixed(i, n).fixed(i, k).place(a);
    root.place(sum);
  });

  int sum_gt = 0;
  for (int i = 0; i < m; i++) {
    if (i / k % 3 == 1) {
      a.val<int32>(i) = i;
      sum_gt += i;
    }
  }

  kernel([&]() {
    Declare(i);
    For(i, a, [&] {sum[Expr(0)] += a[i]; });
  })();

  TC_CHECK(sum.val<int32>() == sum_gt);
}

TC_TEST("pointer") {
  Program prog;

  int n = 32;
  int k = 64;
  int m = n * k;

  Global(a, i32);
  Global(sum, i32);

  layout([&] {
    auto i = Index(0);
    root.fixed(i, n).pointer().fixed(i, k).place(a);
    root.place(sum);
  });

  auto red = kernel([&]() {
    Declare(i);
    For(i, a, [&] { sum[Expr(0)] += a[i]; });
  });

  int sum_gt = 0;
  for (int i = 0; i < m; i++) {
    if (i / k % 3 == 1) {
      a.val<int32>(i) = i;
      sum_gt += i;
    }
  }

  red();

  auto reduced = sum.val<int32>();
  TC_CHECK(reduced == sum_gt);
}

TC_TEST("hashed") {
  Program prog;

  int n = 64;
  int k = 128;
  int m = n * k;

  Global(a, i32);
  Global(sum, i32);

  layout([&] {
    auto i = Index(0);
    root.hashed(i, n).fixed(i, k).place(a);
    root.place(sum);
  });

  auto red = kernel([&]() {
    Declare(i);
    For(i, a, [&] { sum[Expr(0)] += a[i]; });
  });
  sum.val<int32>() = 0;

  int sum_gt = 0;
  for (int i = 0; i < m; i++) {
    if (i / k % 3 == 1) {
      a.val<int32>(i) = 1;
      sum_gt += 1;
    }
  }

  red();

  auto reduced = sum.val<int32>();
  TC_CHECK(reduced == sum_gt);
}

TC_TEST("box_filter") {
  return;
  Program prog;

  int n = 64;
  int k = 128;
  int m = n * k;

  Global(x, i32);
  Global(y, i32);

  layout([&] {
    auto i = Index(0);
    root.hashed(i, n).fixed(i, k).place(x, y);
  });

  auto red = kernel([&]() {
    Declare(i);
    For(i, x, [&] { y[i] = x[i - 1] + x[i] + x[i + 1]; });
  });

  red();

  // auto reduced = sum.val<int32>();
  // TC_CHECK(reduced == sum_gt);
}

TLANG_NAMESPACE_END
<|endoftext|>