damaris-backends/drivers/SpinCore-PulseBlaster24Bit/SpinCore-PulseBlaster24Bit.cpp
2014-06-26 11:10:51 +00:00

275 lines
10 KiB
C++

/* **************************************************************************
Author: Achim Gaedke
Created: March 2005
****************************************************************************/
#include "core/core.h"
#include "SpinCore-PulseBlaster24Bit.h"
#include <cmath>
#include <typeinfo>
#include <iterator>
#ifndef SIZETPRINTFLETTER
# ifndef __LP64__
# define SIZETPRINTFLETTER "u"
# else
# define SIZETPRINTFLETTER "lu"
# endif
#endif
/*********************************************************************
PulseBlaster24BitCommand
*********************************************************************/
PulseBlaster24BitCommand::PulseBlaster24BitCommand(): PulseBlasterCommand() {
}
PulseBlaster24BitCommand::PulseBlaster24BitCommand(const PulseBlaster24BitCommand& orig): PulseBlasterCommand(orig) {}
PulseBlaster24BitCommand::PulseBlaster24BitCommand(PulseBlaster24BitProgram& p): PulseBlasterCommand(p) {}
PulseBlaster24BitCommand::PulseBlaster24BitCommand(PulseBlaster24BitProgram& p,
int _ttls, double _length)
:PulseBlasterCommand(p, _ttls, _length)
{}
int PulseBlaster24BitCommand::write_to_file(FILE* out, size_t indent) const {
if (program==NULL) throw pulse_exception("PulseBlaster24Bit: Command not associated with Program");
fprintf(out,"%s<instruction ttls=\"0x%06x\" ",
std::string(indent,' ').c_str(),ttls);
switch(instruction) {
case SpinCorePulseBlaster::LOOP:
fprintf(out,"inst=\"LOOP\" loops=\"%d\"",loop_count);
break;
case SpinCorePulseBlaster::LONG_DELAY:
fprintf(out,"inst=\"LONG_DELAY\" loops=\"%d\"",loop_count);
break;
case SpinCorePulseBlaster::BRANCH:
fprintf(out,"inst=\"BRANCH\" address=\"%" SIZETPRINTFLETTER "\"",std::distance(program->begin(),jump));
break;
case SpinCorePulseBlaster::END_LOOP:
fprintf(out,"inst=\"END_LOOP\" address=\"%" SIZETPRINTFLETTER "\"",std::distance(program->begin(),jump));
break;
case SpinCorePulseBlaster::JSR:
fprintf(out,"inst=\"JSR\" address=\"%" SIZETPRINTFLETTER "\"",std::distance(program->begin(),jump));
break;
case SpinCorePulseBlaster::CONTINUE:
fprintf(out,"inst=\"CONTINUE\"");
break;
case SpinCorePulseBlaster::STOP:
fprintf(out,"inst=\"STOP\"");
break;
case SpinCorePulseBlaster::RTS:
fprintf(out,"inst=\"RTS\"");
break;
case SpinCorePulseBlaster::WAIT:
fprintf(out,"inst=\"WAIT\"");
break;
default:
fprintf(out,"inst=\"%d\" instdata=\"UNKNOWN\"",instruction);
}
fprintf(out," length=\"%g\"/>\n",(1.0*length)/program->internal_clock_freq);
return 1;
}
/*********************************************************************
PulseBlaster24BitProgram
*********************************************************************/
PulseBlaster24BitProgram::PulseBlaster24BitProgram(): PulseBlasterProgram() {
internal_clock_freq=100.0e6;
minimum_interval=9;
ttl_device_id=0;
}
PulseBlaster24BitProgram::PulseBlaster24BitProgram(const SpinCorePulseBlaster24Bit& pb24) {
internal_clock_freq=pb24.clock;
minimum_interval=pb24.shortest_pulse;
ttl_device_id=pb24.ttl_device_id;
}
PulseBlaster24BitProgram::PulseBlaster24BitProgram(const PulseBlaster24BitProgram& orig): PulseBlasterProgram() {
ttl_device_id=orig.ttl_device_id;
// be sure, there are no old list items left!
clear();
const_iterator orig_i;
for (orig_i=orig.begin(); orig_i!=orig.end(); ++orig_i) {
const PulseBlaster24BitCommand* the_command=dynamic_cast<const PulseBlaster24BitCommand*>(*orig_i);
if (the_command==NULL) {
throw SpinCorePulseBlaster_error("wrong command class or NULL pointer found in program");
}
PulseBlaster24BitCommand* new_one=new PulseBlaster24BitCommand(*the_command);
new_one->program=this;
push_back(new_one);
}
// set correct references...
orig_i=orig.begin();
for(iterator i=begin(); i!=end(); ++i) {
(**i).program=this;
if ((**i).instruction==SpinCorePulseBlaster::END_LOOP || (**i).instruction==SpinCorePulseBlaster::BRANCH || (**i).instruction==SpinCorePulseBlaster::JSR) {
(**i).jump=i;
advance((**i).jump,distance(orig.begin(),(**orig_i).jump)-distance(orig.begin(),orig_i));
}
++orig_i;
}
}
PulseBlasterCommand* PulseBlaster24BitProgram::create_command(const state& the_state) {
if (typeid(the_state)==typeid(state_sequent)||typeid(the_state)==typeid(state_parallel))
throw pulse_exception("PulseBlasterCommands can only be created from states");
long unsigned int interval = ceil(the_state.length*internal_clock_freq);
if ( interval < minimum_interval) {
fprintf(stderr,"PulseBlaster state too short (%lu < %lu ticks): %e\n", interval, \
minimum_interval, \
the_state.length);
throw pulse_exception("PulseBlaster state too short");
}
// all states or-ed together
int the_ttls=0;
for (state::const_iterator i=the_state.begin(); i!=the_state.end(); ++i) {
const ttlout* to=dynamic_cast<const ttlout*>(*i);
if (to!=NULL && to->id==ttl_device_id) {
the_ttls|=to->ttls.to_ulong();
}
}
return new PulseBlaster24BitCommand(*this, the_ttls, the_state.length);
}
PulseBlasterCommand* PulseBlaster24BitProgram::create_command(const PulseBlasterCommand* orig) {
PulseBlaster24BitCommand* new_command=NULL;
if (orig==NULL) {
new_command=new PulseBlaster24BitCommand();
new_command->program=this;
new_command->length=minimum_interval;
}
else {
const PulseBlaster24BitCommand* command24Bit=dynamic_cast<const PulseBlaster24BitCommand*>(orig);
if (command24Bit==NULL) throw pulse_exception("wrong PulseBlasterCommand class");
new_command=new PulseBlaster24BitCommand(*command24Bit);
}
return new_command;
}
int PulseBlaster24BitProgram::write_to_file(FILE* out, size_t indent) const {
std::string indent_string(indent,' ');
fprintf(out,"%s<PulseBlaster24BitProgram>\n",indent_string.c_str());
for(const_iterator i=begin(); i!=end(); ++i) {
if (*i==NULL) throw SpinCorePulseBlaster_error("NULL pointer found in command list");
(**i).write_to_file(out, indent+2);
}
fprintf(out,"%s</PulseBlaster24BitProgram>\n",indent_string.c_str());
return 1;
}
/*********************************************************************
SpinCorePulseBlaster24Bit
*********************************************************************/
void SpinCorePulseBlaster24Bit::write_command(unsigned char* data, int flags, opcode inst, unsigned int inst_data, size_t delay) {
if (inst>8)
throw SpinCorePulseBlaster_error("instruction code not known");
// Output, Control Word 1st Byte
data[0]=(flags&0xff0000)>>16;
// Output, Control Word 2nd Byte
data[1]=(flags&0xff00)>>8;
// Output, Control Word 3rd Byte
data[2]=flags&0xff;
// Data Field 1st Byte
data[3]=(inst_data&0x0ff000)>>12;
// Data Field 2nd Byte
data[4]=(inst_data&0xff0)>>4;
// Data Field 3rd Byte and opcode
data[5]=(inst_data&0xf)<<4|(inst&0xf);
// Delay Count 1st Byte
data[6]=(delay&0xff000000)>>24;
// Delay Count 2nd Byte
data[7]=(delay&0xff0000)>>16;
// Delay Count 3rd Byte
data[8]=(delay&0xff00)>>8;
// Delay Count 4th Byte
data[9]=(delay&0xff);
/* *** BUG-FIX (ToDo: clean solution) ***
there is a nasty error in pulseblaster, affecting all states with 4th byte
equal 0xff and delay >255. In this case reduce state for 10ns.
*/
if (0 && data[9]==0xff && delay>0xff)
data[9]=0xfe;
}
void SpinCorePulseBlaster24Bit::write_command(unsigned char* data, const PulseBlasterCommand& command) {
const PulseBlaster24BitCommand* command24Bit=dynamic_cast<const PulseBlaster24BitCommand*>(&command);
if (command24Bit==NULL)
throw SpinCorePulseBlaster_error("found wrong command class in PulseBlasterProgram");
if (command24Bit->program==NULL) throw SpinCorePulseBlaster_error("Command not associated with Program");
unsigned int inst_data=0;
switch(command24Bit->instruction) {
case SpinCorePulseBlaster::CONTINUE:
case SpinCorePulseBlaster::STOP:
case SpinCorePulseBlaster::WAIT:
case SpinCorePulseBlaster::RTS:
// no parameter
break;
case SpinCorePulseBlaster::LOOP:
inst_data=command24Bit->loop_count-1;
break;
case SpinCorePulseBlaster::LONG_DELAY:
inst_data=command24Bit->loop_count-2;
break;
case SpinCorePulseBlaster::BRANCH:
case SpinCorePulseBlaster::END_LOOP:
case SpinCorePulseBlaster::JSR:
inst_data=std::distance(command24Bit->program->begin(),command24Bit->jump);
break;
default:
throw SpinCorePulseBlaster_error("instruction code not known");
}
if (command24Bit->length<3)
throw SpinCorePulseBlaster_error("delay length too small!");
unsigned int delay=(unsigned int)command24Bit->length-3;
write_command(data,command24Bit->ttls,command24Bit->instruction,inst_data,delay);
}
void SpinCorePulseBlaster24Bit::write_to_device(const PulseBlaster24BitProgram& p) {
std::string program;
//Begin pulse program
for (PulseBlaster24BitProgram::const_iterator c=p.begin(); c!=p.end(); ++c) {
char command[10];
write_command((unsigned char*)command,**c);
program.append(command, (size_t)10);
}
set_program(program);
// End of programming registers and pulse program
set_initialized();
}
PulseBlasterProgram* SpinCorePulseBlaster24Bit::create_program(state& exp) {
PulseBlaster24BitProgram* prog=new PulseBlaster24BitProgram();
// the user's code
prog->append_sequence(exp);
return prog;
}
void SpinCorePulseBlaster24Bit::run_pulse_program(const PulseBlasterProgram& p) {
const PulseBlaster24BitProgram* prog=dynamic_cast<const PulseBlaster24BitProgram*>(&p);
if (prog==NULL)
throw SpinCorePulseBlaster_error("found wrong program class in SpinCorePulseBlaster24Bit method");
write_to_device(*prog);
start();
}