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

323 lines
9.6 KiB
C++

#include "SpinCore-PulseBlaster.h"
#include "PulseBlasterProgram.h"
#include "core/xml_states.h"
#include <typeinfo>
/* ***************************************************************************************
PulseBlasterCommand
**************************************************************************************** */
PulseBlasterCommand::PulseBlasterCommand() {
ttls=0;
instruction=SpinCorePulseBlaster::CONTINUE;
length=0;
loop_count=0;
program=NULL;
}
PulseBlasterCommand::PulseBlasterCommand(const PulseBlasterCommand& orig) {
instruction=orig.instruction;
length=orig.length;
ttls=orig.ttls;
program=orig.program;
switch(instruction) {
case SpinCorePulseBlaster::LOOP:
case SpinCorePulseBlaster::LONG_DELAY:
loop_count=orig.loop_count;
jump=program->end();
break;
case SpinCorePulseBlaster::BRANCH:
case SpinCorePulseBlaster::END_LOOP:
case SpinCorePulseBlaster::JSR:
jump=orig.jump;
loop_count=0;
break;
default:
loop_count=0;
jump=program->end();
}
}
PulseBlasterCommand::PulseBlasterCommand(PulseBlasterProgram& p) {
ttls=0;
instruction=SpinCorePulseBlaster::CONTINUE;
length=p.minimum_interval;
program=&p;
loop_count=0;
jump=p.end();
}
PulseBlasterCommand::PulseBlasterCommand(PulseBlasterProgram& p, int _ttls, double _length) {
ttls=_ttls;
loop_count=0;
instruction=SpinCorePulseBlaster::CONTINUE;
program=&p;
jump=p.end();
length=(size_t)floor(_length*p.internal_clock_freq+0.5); // graceful rounding
}
/* ***************************************************************************************
PulseBlasterProgram
**************************************************************************************** */
PulseBlasterProgram::PulseBlasterProgram(const PulseBlasterProgram& orig): std::list<PulseBlasterCommand*>() {
// do not copy the list. This must be done by the derived class...
internal_clock_freq=orig.internal_clock_freq;
minimum_interval=orig.minimum_interval;
}
int PulseBlasterProgram::insert_ref(PulseBlasterProgram::iterator target_pos,
PulseBlasterProgram::const_iterator start_copy,
PulseBlasterProgram::const_iterator end_copy) {
insert(target_pos,start_copy,end_copy);
iterator i=target_pos;
for(const_iterator orig_i=end_copy;orig_i!=start_copy;--orig_i) {
if ((**i).instruction==SpinCorePulseBlaster::END_LOOP || (**i).instruction==SpinCorePulseBlaster::BRANCH || (**i).instruction==SpinCorePulseBlaster::JSR) {
(**i).jump=i;
advance(i,distance(start_copy,(**orig_i).jump)-distance(start_copy,orig_i));
}
--i;
}
return 0;
}
PulseBlasterProgram::~PulseBlasterProgram() {
while (!empty()) {
if (back()!=NULL) delete back();
pop_back();
}
}
void PulseBlasterProgram::append_sequence(const state& the_states) {
std::list<stackentry> the_stack;
// recieve a work copy with partially enrolled loops and flat structures
state* flat=the_states.copy_flat(0);
push_back(create_command());
iterator dummy_pos=--end();
state_atom* this_tag=flat;
while (1) {
// operate on a sequence
if (typeid(*this_tag)==typeid(state_sequent)) {
//fprintf(stderr,"found sequence\n");
state_sequent* sequence=dynamic_cast<state_sequent*>(this_tag);
// throw away all elements, which were non-states
for(state_sequent::iterator i=sequence->begin(); sequence->end()!=i;) {
if (dynamic_cast<state*>(*i)==0) {
// states are expected, nothing else!
fprintf(stderr, "only states are allowed inside a sequent section!\n");
delete *i;
i=sequence->erase(i);
}
else
// fine
++i;
}
// skip if empty
if (!sequence->empty() && sequence->repeat>0) {
if (sequence->repeat>1<<20) {
// nested loops as workaround
size_t new_count1=1<<20;
size_t new_count2=sequence->repeat/new_count1;
size_t new_count3=sequence->repeat-new_count1*new_count2;
// if (new_count2==1) {}
// if (new_count3==0) {}
state_sequent* new_sequence1=new state_sequent();
new_sequence1->repeat=new_count1;
state_sequent* new_sequence2=new state_sequent(*sequence);
new_sequence2->repeat=new_count2;
new_sequence1->push_back(new_sequence2);
state_sequent* new_sequence3=new state_sequent(*sequence);
new_sequence3->repeat=new_count3;
while (!sequence->empty()) {
delete sequence->front();
sequence->pop_front();
}
sequence->repeat=1;
sequence->push_back(new_sequence1);
sequence->push_back(new_sequence3);
}
// if necessary enroll loop at begin
// prepare sequence
if (sequence->repeat>1) {
while (1) {
state* first_state=NULL;
state_sequent::iterator i=sequence->begin();
while( i!=sequence->end()) {
first_state=dynamic_cast<state*>(*i);
if (NULL!=first_state) break;
++i;
}
if (first_state!=NULL) {
state_sequent* first_sequence=dynamic_cast<state_sequent*>(first_state);
if (first_sequence!=NULL) {
// fprintf(stderr,"enroll begin\n");
size_t repeat=first_sequence->repeat;
if (repeat==0) {
delete *i;
sequence->erase(i);
}
else if (repeat==1) {
sequence->insert(i,first_sequence->begin(),first_sequence->end());
first_sequence->clear();
delete *i;
sequence->erase(i);
}
else {
for (state_sequent::iterator j=first_sequence->begin();j!=first_sequence->end();++j)
sequence->insert(i,(*j)->copy_new());
first_sequence->repeat=repeat-1;
}
// check again...
continue;
}
}
// nothing to be done
break;
}
// if necessary enroll loop at end
while (1) {
state* last_state=NULL;
state_sequent::iterator i=sequence->end();
while(i!=sequence->begin()) {
--i;
last_state=dynamic_cast<state*>(*i);
if (last_state!=NULL) break;
}
if (last_state!=NULL) {
state_sequent* last_sequence=dynamic_cast<state_sequent*>(last_state);
if (last_sequence!=NULL) {
if (last_sequence->repeat==0) {
// forget this sequence
delete *i;
sequence->erase(i);
}
else if (last_sequence->repeat==1) {
// forget the sequence around it
sequence->insert(i,last_sequence->begin(),last_sequence->end());
last_sequence->clear();
delete *i;
sequence->erase(i);
}
else {
// fprintf(stderr,"enroll end\n");
last_sequence->repeat-=1;
i++;
for (state_sequent::iterator j=last_sequence->begin();j!=last_sequence->end();++j)
sequence->insert(i,(*j)->copy_new());
}
// check again
continue;
}
break;
}
}
}
// step down
// push to stack
stackentry new_entry={sequence, sequence->begin(), --end()};
#if 0
if (new_entry.command==the_program->end())
fprintf(stderr,"saved an end iterator\n");
else
fprintf(stderr,"saved pos no %d\n",distance(begin(),new_entry.command));
for (PulseBlasterProgram::iterator i=++begin();i!=end();i++)
i->write_to_file(stderr);
#endif
the_stack.push_back(new_entry);
this_tag=*(the_stack.back().subsequence_position);
continue;
}
}
// operate on a single state
else if (typeid(*this_tag)==typeid(state)) {
//fprintf(stderr,"found state\n");
state* this_state=dynamic_cast<state*>(this_tag);
if (this_state->length*internal_clock_freq>pow(2,32)-1) {
// add a loop to state, to gain longer durations
// numerical stability?
// todo: avaoid unnecessary loop or state
const double loop_state_length=42.949;
size_t number_loops=(size_t)floor(this_state->length/loop_state_length);
double remaining_time=this_state->length-loop_state_length*number_loops;
if (remaining_time*internal_clock_freq<minimum_interval) {
// now, the remaining state might be too short
remaining_time+=loop_state_length;
--number_loops;
}
state_sequent* new_loop=new state_sequent;
new_loop->repeat=number_loops;
this_state->length=loop_state_length;
new_loop->push_back(this_state->copy_new());
this_state->length=remaining_time;
if (the_stack.empty()) {
// in addition to this make a sequence around it
state_sequent* sequence_envelope=new state_sequent;
sequence_envelope->push_back(new_loop);
sequence_envelope->push_back(this_state);
this_state=sequence_envelope;
}
else {
// insert the loop after this state
state_sequent::iterator loop_pos=(state_sequent::iterator)the_stack.back().subsequence_position;
the_stack.back().subsequence->insert(++loop_pos,new_loop);
}
continue;
}
else {
// simply append the state
PulseBlasterCommand* c=create_command(*this_state);
if (c==NULL) throw pulse_exception("failed state creation");
push_back(c);
}
}
else {
fprintf(stderr,"droped something");
// drop it...
}
// find the next state...
while (!the_stack.empty()) {
stackentry& last_entry=the_stack.back();
++last_entry.subsequence_position;
if (last_entry.subsequence_position!=last_entry.subsequence->end()) {
this_tag=*(the_stack.back().subsequence_position);
break;
}
// finish loop...
if (last_entry.subsequence->repeat>1) {
++last_entry.command;
if (last_entry.command==--end()) {
// special case long delay
back()->instruction=SpinCorePulseBlaster::LONG_DELAY;
back()->loop_count=last_entry.subsequence->repeat;
}
else {
// loop with several states
(**(last_entry.command)).instruction=SpinCorePulseBlaster::LOOP;
(**(last_entry.command)).loop_count=last_entry.subsequence->repeat;
back()->instruction=SpinCorePulseBlaster::END_LOOP;
back()->jump=last_entry.command;
}
}
// jump to next level
the_stack.pop_back();
}
if (the_stack.empty()) break;
}
delete flat;
// is that ok in all cases?
delete *dummy_pos;
erase(dummy_pos);
}