323 lines
9.6 KiB
C++
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);
|
|
}
|