/* CONSTDIVMUL.CPP CODE GENERATION FOR CONSTANT DIVISION/MULTIPLICATION IN PIC ASSEMBLY Idea and project guidance by James Newton , Used software tricks shared on PICLIST by Scott Dattalo , Robert A. LaBudde James Newton , Dwayne Reid Implementation by Nikolai Golovchenko Date: Feb 19, 2000 - Mar 16, 2000; Mar 21, 2000; Mar 30, 2000 (banner added); */ //Debug string: //Acc=ACC&Bits=8&Const=7.55&ConstErr=0.1&Temp=TEMP //Acc=ACC&Bits=8&Const=0.9099&ConstErr=0.1&Temp=TEMP //Acc=ACC&Bits=7&Const=0.39&ConstErr=0.001&Temp=TEMP //Acc=ACC&Bits=7&Const=4.9946&ConstErr=0.001&Temp=TEMP //Acc=ACC&Bits=2&Const=2.35&ConstErr=1&Temp=TEMP //Acc=ACC&Bits=2&Const=1.3&ConstErr=1&Temp=TEMP //Acc=ACC&Bits=4&Const=2.03&ConstErr=1&Temp=TEMP //Acc=ACC&Bits=16&Const=0.0095&ConstErr=0.1&Temp=TEMP //Acc=ACC&Bits=8&Const=+0.99218750000000&ConstErr=0.1&Temp=TEMP //Acc=ACC&Bits=8&Const=14&ConstErr=0.1&Temp=TEMP //Acc=ACC&Bits=8&Const=0.984&ConstErr=0.001&Temp=TEMP&endian=big //Acc=ACC&Bits=8&Const=1.01538085&ConstErr=0.01&Temp=TEMP&endian=little //Acc=ACC&Bits=8&Const=0.11&ConstErr=0.01&Temp=TEMP&endian=little //Acc=ACC&Bits=8&Const=0.13&ConstErr=0.01&Temp=TEMP&endian=little #include "constdivmul.h" double Const, //Constant value ConstErr; //Constant error percent char OutBits, //Bits number in output AddBits, //Bits added to input size in result InpBytes, //Bytes number in input OutBytes; //Bytes number in output PIC16 *ALU; //Status register and accumulator object Reg :: Reg() { Leads = 0; BytesUsed = 0; Bits = 0; Name = ""; Sign = false; Zero = true; wasUsed = false; endian = big; } Reg :: Reg(char *N, char b, endianType endi) { Leads = (8 - b % 8) & 0x07; BytesUsed = (b + 7) / 8; Bits = b; Name = N; Zero = false; Sign = false; wasUsed = false; endian = endi; } char *Reg :: ShowUsedRegs() { char i; str[0] = 0; if(wasUsed) { for(i = 0; i < BytesUsed; i++) { sprintf(str + strlen(str),"\t%s%d\n", Name, i); } } return str; } char *Reg :: ShiftLeft(char Shift) { Zero = false; ALU->ClearSnippet(); ALU->TakeCarry(); ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); if(endian == big) { return ShiftLeftBE(Shift); } else { return ShiftLeftLE(Shift); } } char *Reg :: ShiftLeftBE(char Shift) { //NOTE: not tested for signed regs! char i, j; //Counter if(Shift > Leads) { //reg needs extension if((Shift % 8) <= Leads) { //just add trailing zero bytes j = ((Shift - Leads) + 7) / 8; //bytes to add } else { //reserve one leading byte and add trailing zero bytes if needed for(j = GetBytes(), i = j - 1; i >= 0; i--, j--) { ALU->movfw(this, i); ALU->movwf(this, j); } ALU->clrf(this, 0); if(Sign) { ALU->btfsc(this, 1, 7); ALU->comff(this, 0); } Leads += 8; CheckBytesUsed(); //add trailing zero bytes j = ((Shift - Leads) + 7) / 8 - 1; //bytes to add } //clear trailing bytes for(i = GetBytes(); j > 0; j--, i++) { ALU->clrf(this, i); Bits += 8; CheckBytesUsed(); } } //final shift Shift %= 8; //bits to shift switch(Shift) { case 6: { //for 6 do and break //reserve one trailing byte Bits += 8; CheckBytesUsed(); Bits -= 8; i = GetBytesTotal(); ALU->clrf(this, i); Bits += 8; while((Shift++) < 8) { for(j = 0; j <= i; j++) { ALU->rrff(this, j); } Bits--; Leads++; } for(j = 1; j <= i; j++) { ALU->movfw(this, j); ALU->movwf(this, j - 1); } Leads -= 8; } break; case 7: { //for 7 do and break //1) ALU->rrff(this, 0); //2) i = GetBytesTotal() - 1; for(j = 1; j <= i; j++) { ALU->rrfw(this, j); ALU->movwf(this, j - 1); } //3) ALU->clrf(this, i); ALU->rrff(this, i); Bits += 7; Leads -= 7; } break; case 4: case 5: { //for 4 and 5 swap and fall through to shift i = GetBytesTotal() - 1; if(i <= 1) { //swap economical for sizes 1 and 2 bytes for(j = 0; j <= i; j++) { if((Leads < 8) || (j != 0) || (Sign)) { //don't use msb byte if it's clear - they are clear for unsigned ALU->swapfw(this, j); ALU->andlw(-16); ALU->movwf(this, j); } if(j != i) { ALU->swapfw(this, j + 1); ALU->andlw(15); ALU->iorwff(this, j); } } Shift -= 4; Bits += 4; Leads -= 4; } } default: { //for 1, 2, 3, 5 shift and break for(i = Shift; i > 0; i--) { if((i == Shift) || (Sign)) { ALU->clrc(); } for(j = GetBytesTotal() - 1; j >= 0 ; j--) { ALU->rlff(this, j); } Bits++; Leads--; } } break; } return ALU->GetSnippet(); } char *Reg :: ShiftLeftLE(char Shift) { //NOTE: doesn't work for signed regs! char i, j, gb, ShiftB; gb = GetBytesTotal(); ShiftB = Shift / 8; //remember bytes to shift Shift %= 8; //shift bits switch(Shift) { case 6: { //for 6 do and break //shift left 8 times for(j = gb - 1; j >= 0; j--) { ALU->movfw(this, j); ALU->movwf(this, j + 1); } ALU->clrf(this, 0); Bits += 8; CheckBytesUsed(); //shift right two times if(Leads < 6) { //clear carry if the msb will be used after shifts ALU->clrc(); } while((Shift++) < 8) { for(j = gb; j >= 0; j--) { ALU->rrff(this, j); } } Bits -= 2; Leads += 2; Leads %= 8; //discard high byte if not needed } break; case 7: { //for 7 do and break //1) if(Leads < 7) { ALU->clrc(); ALU->rrfw(this, gb - 1); ALU->movwf(this, gb); Leads += 8; CheckBytesUsed(); } else { ALU->rrff(this, gb - 1); } //2) for(j = gb - 2; j >= 0; j--) { ALU->rrfw(this, j); ALU->movwf(this, j + 1); } //3) ALU->clrf(this, 0); ALU->rrff(this, 0); Bits += 7; Leads -= 7; } break; case 4: case 5: { //for 4 and 5 swap and fall through to shift if(gb < 3) { //swap economical for sizes 1 and 2 bytes if(Leads >= 4) { ALU->swapff(this, gb - 1); } else { ALU->swapfw(this, gb - 1); ALU->andlw(15); ALU->movwf(this, gb); ALU->swapfw(this, gb - 1); ALU->andlw(-16); ALU->movwf(this, gb - 1); Leads += 8; CheckBytesUsed(); } for(j = gb - 2; j >= 0; j--) { ALU->swapfw(this, j); ALU->andlw(15); ALU->iorwff(this, j + 1); ALU->swapfw(this, j); ALU->andlw(-16); ALU->movwf(this, j); } Shift -= 4; Bits += 4; Leads -= 4; } } default: { //for 1, 2, 3, 5 shift and break gb = GetBytesTotal(); for(i = Shift; i > 0; i--) { if(i == Shift) { ALU->clrc(); } for(j = 0; j < gb ; j++) { ALU->rlff(this, j); } Bits++; Leads--; if(Leads < 0) { ALU->clrf(this, gb); ALU->rlff(this, gb++); Leads += 8; CheckBytesUsed(); } } } break; } //finally, move bytes gb = GetBytesTotal(); if(ShiftB > 0) { for(i = gb - 1 + ShiftB, j = gb - 1; j >= 0; i--, j--) { ALU->movfw(this, j); ALU->movwf(this, i); } for(i = 0; i < ShiftB; i++) { ALU->clrf(this, i); } Bits += ShiftB * 8; CheckBytesUsed(); } return ALU->GetSnippet(); } char *Reg :: ShiftRight(char Shift) { if(Shift >= GetSize()) { Bits = 0; Leads = 0; Zero = true; return ""; } ALU->ClearSnippet(); Zero = false; if(endian == big) { return ShiftRightBE(Shift); } else { return ShiftRightLE(Shift); } } char *Reg :: ShiftRightBE(char Shift) { char i, j; //Find modulus 8 of Shift and correct bits number after bytes move //Move bytes by substracting from Bits Bits -= Shift; Shift %= 8; Bits += Shift; switch(Shift) { case 6: { //do this if shift=6 and break if((Leads - Sign) < 2) { //reserve one byte for(j = GetBytesTotal() - 1; j >= 0; j--) { ALU->movfw(this, j); ALU->movwf(this, j + 1); } Bits += 8; CheckBytesUsed(); Bits -= 8; //initialize MSByte ALU->clrf(this, 0); if(ALU->cHolder != this) { //free carry if it's busy ALU->TakeCarry(); ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); } if(!ALU->GetNoteCarry(this)) { if(Sign) { ALU->btfsc(this, 1, 7); ALU->comff(this, 0); } } else { if(Sign) { ALU->skpc(); ALU->comff(this, 0); } else { ALU->skpnc(); ALU->bsf(this, 0, 0); } } } else { Leads -= 8; } //left shifts Shift = 8 - Shift; while((Shift--) > 0) { for(j = GetBytesTotal(); j >= 0; j--) { ALU->rlff(this, j); } } Leads += 6; Bits -= 6; } break; case 7: { //do this if shift=7 and break //free carry if it's busy ALU->TakeCarry(); ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); //1) j = GetBytesTotal() - 1; ALU->rlff(this, j); //2) if(Leads == 0) { for(i = j - 1; i >= 0; i--, j--) { ALU->rlfw(this, i); ALU->movwf(this, j); } ALU->clrf(this, 0); if(Sign) { ALU->skpnc(); ALU->comff(this, 0); } else { ALU->rlff(this, 0); } } else { for(j = GetBytesTotal() - 2; j >= 0; j--) { ALU->rlff(this, j); } Leads -= 8; } Leads += 7; Bits -= 7; } break; case 4: case 5: { //do if Bytes=1 else fall through if(GetBytes() == 1) { if(ALU->cHolder != this) { //free carry if it's busy ALU->TakeCarry(); ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); } for(j = GetBytesTotal() - 1; j >= 0 ; j--) { ALU->swapfw(this, j); ALU->andlw(0x0f); ALU->movwf(this, j); if(j != 0) { ALU->swapfw(this, j - 1); ALU->andlw(-16); ALU->iorwff(this, j); } } if(!ALU->GetNoteCarry(this)) { if(Sign) { ALU->movlw(-16); ALU->btfsc(this, 0, 3); ALU->iorwff(this, 0); } } else { if(Sign) { ALU->movlw(-16); ALU->skpc(); ALU->iorwff(this, 0); } else { ALU->skpnc(); ALU->bsf(this, 0, 4); } } Shift -= 4; Leads += 4; Bits -= 4; ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); //make the final shift if shift = 5 } } default: { //do for shift = 0..3, and 4, 5 if Bytes > 1 for(i = Shift; i > 0; i--) { if(ALU->cHolder != this) { //free carry if it's busy ALU->TakeCarry(); ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); } if(!ALU->GetNoteCarry(this)) { if(Sign) { ALU->rlfw(this, 0); } else { if(!ALU->GetValidCarry(this)) { ALU->clrc(); //ALU->SetValidCarry(false, this); } } } else { if(Sign) { ALU->comc(); } } for(j = 0; j < GetBytesTotal(); j++) { ALU->rrff(this, j); } ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); Bits--; Leads++; } } break; } //if leads are more then a byte, remove them if((Leads / 8) > 0) { for(i = Leads / 8, j = 0; i < GetBytesTotal(); i++, j++) { ALU->movfw(this, i); ALU->movwf(this, j); } Leads %= 8; } ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); return ALU->GetSnippet(); } char *Reg :: ShiftRightLE(char Shift) { char i, j, ShiftB, gb; gb = GetBytesTotal(); ShiftB = Shift / 8; Shift %= 8; //move bytes if(ShiftB > 0) { for(j = ShiftB, i = 0; j < gb; j++, i++) { ALU->movfw(this, j); ALU->movwf(this, i); } Bits -= ShiftB * 8; } //shift bits switch(Shift) { case 6: { //do and break //Take care of carry ALU->TakeCarry(); ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); gb = GetBytesTotal(); //shift left 2 times while((Shift++) < 8) { for(j = 0; j < gb; j++) { ALU->rlff(this, j); } Leads--; Bits++; if((Leads - Sign) < 0) { ALU->clrf(this, gb); if(Sign) { ALU->skpnc(); ALU->comff(this, gb); } else { ALU->rlff(this, gb); } Leads += 8; CheckBytesUsed(); gb = GetBytesTotal(); } } //move right 8 times for(i = 0; i < (gb - 1); i++) { ALU->movfw(this, i + 1); ALU->movwf(this, i); } Bits -= 8; } break; case 7: { //do this if shift=7 and break //free carry if it's busy ALU->TakeCarry(); ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); //1) gb = GetBytesTotal(); ALU->rlff(this, 0); //2) for(i = 0; i < (gb - 1); i++) { ALU->rlfw(this, i + 1); ALU->movwf(this, i); } if((Leads - Sign) == 0) { ALU->clrf(this, gb - 1); if(Sign) { ALU->skpnc(); ALU->comff(this, gb - 1); } else { ALU->rlff(this, gb - 1); } } Leads += 7; Bits -= 7; Leads %= 8; //remove unnecessary leads CheckBytesUsed(); } break; case 4: case 5: { //do if Bytes=1 else fall through if(gb == 1) { if(ALU->cHolder != this) { //free carry if it's busy ALU->TakeCarry(); ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); } gb = GetBytesTotal(); for(j = 0; j < (gb - 1) ; j++) { if(j != 0) { ALU->swapfw(this, j); ALU->andlw(-16); ALU->iorwff(this, j - 1); } ALU->swapfw(this, j); ALU->andlw(0x0f); ALU->movwf(this, j); } ALU->swapfw(this, j); ALU->andlw(0x0f); if(!ALU->GetNoteCarry(this)) { if(Sign) { ALU->btfsc(this, 0, 3); ALU->iorlw(-16); } } else { if(Sign) { ALU->skpc(); ALU->iorlw(-16); } else { ALU->skpnc(); ALU->iorlw(16); } } ALU->movwf(this, j); Shift -= 4; Leads += 4; Bits -= 4; ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); //make the final shift if shift = 5 } } default: { //do for shift = 0..3, and 4, 5 if Bytes > 1 for(i = Shift; i > 0; i--) { gb = GetBytesTotal(); if(ALU->cHolder != this) { //free carry if it's busy ALU->TakeCarry(); ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); } if(!ALU->GetNoteCarry(this)) { if(Sign) { ALU->rlfw(this, gb - 1); } else { if(!ALU->GetValidCarry(this)) { ALU->clrc(); //ALU->SetValidCarry(false, this); } } } else { if(Sign) { ALU->comc(); } } for(j = gb - 1; j >= 0; j--) { ALU->rrff(this, j); } ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); Bits--; Leads++; Leads %= 8; //discard unneeded leads } } break; } /* //if leads are more then a byte, remove them if((Leads / 8) > 0) { for(i = Leads / 8, j = 0; i < GetBytesTotal(); i++, j++) { ALU->movfw(this, i); ALU->movwf(this, j); } Leads %= 8; } */ ALU->SetNoteCarry(false, this); ALU->SetValidCarry(false, this); return ALU->GetSnippet(); } void Reg :: Normalize(Reg *R2) { ALU->TakeCarry(); if(endian == big) { NormalizeBE(R2); } else { NormalizeLE(R2); } } void Reg :: NormalizeBE(Reg *R2) { char i, j, d; d = R2->GetBytesTotal() - GetBytesTotal(); if(d > 0) { //reserve leading bytes for(j = GetBytesTotal() + d - 1, i = j - 1; i >= 0; i--, j--) { ALU->movfw(this, i); ALU->movwf(this, j); } for(i = 0; i < d; i++) { ALU->clrf(this, i); if(Sign) { ALU->btfsc(this, d, 7); ALU->comff(this, i); } Leads += 8; } CheckBytesUsed(); } } void Reg :: NormalizeLE(Reg *R2) { char i, d; d = R2->GetBytesTotal() - GetBytesTotal(); if(d > 0) { for(i = GetBytesTotal(); d > 0; i++, d--) { //reserve leading byte ALU->clrf(this, i); if(Sign) { ALU->btfsc(this, i - 1, 7); ALU->comff(this, i); } Leads += 8; } CheckBytesUsed(); } } char *Reg :: Add(Reg *R2) { ALU->ClearSnippet(); Normalize(R2); if(endian == big) { return AddBE(R2); } else { return AddLE(R2); } } char *Reg :: AddBE(Reg *R2) { char i, j; for(i = R2->GetBytesTotal() - 1, j = GetBytesTotal() - 1; i >= 0; i--, j--) { if(i == (R2->GetBytesTotal() - 1)) { // first bytes addition ALU->movfw(R2, i); ALU->addwff(this, j); } else { // other bytes addition with carry propagation ALU->movfw(R2, i); ALU->skpnc(); ALU->incfszw(R2, i); ALU->addwff(this, j); } } if(j >= 0) { //in case right operand had less bytes, replace them with zero literals ALU->movlw(1); while(j >= 0) { ALU->skpnc(); ALU->addwff(this, j); j--; } } i = Leads; if(Leads > R2->Leads) { Leads = R2->Leads; } Leads --; //one bit added after each addition ALU->SetValidCarry(true, this); //after addition carry is always valid ALU->SetNoteCarry(false, this); //Correct leads on overflow to carry if(Leads == -1) { ALU->SetNoteCarry(true, this); Leads = 0; } Bits += i - Leads; return ALU->GetSnippet(); } char *Reg :: AddLE(Reg *R2) { char i, j, r2b, rb; r2b = R2->GetBytesTotal(); rb = GetBytesTotal(); for(i = 0, j = 0; i < r2b; i++, j++) { if(i == 0) { // first bytes addition ALU->movfw(R2, i); ALU->addwff(this, j); } else { // other bytes addition with carry propagation ALU->movfw(R2, i); ALU->skpnc(); ALU->incfszw(R2, i); ALU->addwff(this, j); } } if(j < rb) { //in case right operand had less bytes, replace them with zero literals ALU->movlw(1); while(j < rb) { ALU->skpnc(); ALU->addwff(this, j); j++; } } i = Leads; if(Leads > R2->Leads) { Leads = R2->Leads; } Leads --; //one bit added after each addition ALU->SetValidCarry(true, this); //after addition carry is always valid ALU->SetNoteCarry(false, this); //Correct leads on overflow to carry if(Leads == -1) { ALU->SetNoteCarry(true, this); Leads = 0; } Bits += i - Leads; return ALU->GetSnippet(); } char *Reg :: Sub(Reg *R2) { ALU->ClearSnippet(); Normalize(R2); ALU->SetValidCarry(false, this); if(endian == big) { return SubBE(R2); } else { return SubLE(R2); } } char *Reg :: SubBE(Reg *R2) { char i, j; if(Sign) { //substraction from negative number will //add one more significant bit // if(R2->Leads < 2) { //add a leading byte for(j = GetBytes(), i = j - 1; i >= 0; i--, j--) { ALU->movfw(this, i); ALU->movwf(this, j); } ALU->clrf(this, 0); ALU->btfsc(this, 1, 7); ALU->comff(this, 0); Bits += Leads - R2->Leads; //set size of r2 for this Leads = 8 + R2->Leads; CheckBytesUsed(); } } for(i = R2->GetBytesTotal() - 1, j = GetBytesTotal() - 1; i >= 0; i--, j--) { if(i == (R2->GetBytesTotal() - 1)) { // first bytes substraction ALU->movfw(R2, i); ALU->subwff(this, j); } else { // other bytes substraction with carry propagation ALU->movfw(R2, i); ALU->skpc(); ALU->incfszw(R2, i); ALU->subwff(this, j); } } if(j >= 0) { //in case right operand had less bytes, replace them with zero literals ALU->movlw(1); while(j >= 0) { ALU->skpc(); ALU->subwff(this, j); j--; } } if(GetBytesTotal() == R2->GetBytesTotal()) { i = Leads; //choose least number of leads if(Leads > R2->Leads) { Leads = R2->Leads; } Bits += i - Leads; //correct number of bits } if(Sign) { Leads --; Bits ++; } ALU->SetNoteCarry(false, this); if(Leads == 0) { //substraction using all bits - //carry contains sign ALU->SetNoteCarry(true, this); } return ALU->GetSnippet(); } char *Reg :: SubLE(Reg *R2) { char i, j, gb, gb2; gb = GetBytesTotal(); gb2 = R2->GetBytesTotal(); if(Sign) { //substraction from negative number will //add one more significant bit // if(R2->Leads < 2) { //add a leading byte ALU->clrf(this, gb); ALU->btfsc(this, gb - 1, 7); ALU->comff(this, gb); Bits += Leads - R2->Leads; //set size of r2 for this Leads = 8 + R2->Leads; CheckBytesUsed(); } } for(i = 0, j = 0; i < gb2; i++, j++) { if(i == 0) { // first bytes substraction ALU->movfw(R2, i); ALU->subwff(this, j); } else { // other bytes substraction with carry propagation ALU->movfw(R2, i); ALU->skpc(); ALU->incfszw(R2, i); ALU->subwff(this, j); } } if(j < gb) { //in case right operand had less bytes, replace them with zero literals ALU->movlw(1); while(j , gb) { ALU->skpc(); ALU->subwff(this, j); j++; } } if(GetBytesTotal() == R2->GetBytesTotal()) { i = Leads; //choose least number of leads if(Leads > R2->Leads) { Leads = R2->Leads; } Bits += i - Leads; //correct number of bits } if(Sign) { Leads --; Bits ++; } ALU->SetNoteCarry(false, this); if(Leads == 0) { //substraction using all bits - //carry contains sign ALU->SetNoteCarry(true, this); } return ALU->GetSnippet(); } char *Reg :: Neg() { ALU->ClearSnippet(); if(endian == big) { return NegBE(); } else { return NegLE(); } } char *Reg :: NegBE() { char i, j; if(Leads == 0) { //reserve byte to place sign for(j = GetBytesTotal(), i = j - 1; i >= 0; i--, j--) { ALU->movfw(this, i); ALU->movwf(this, j); } ALU->clrf(this, 0); Leads += 8; CheckBytesUsed(); } for(i = 0; i < GetBytesTotal(); i++) { ALU->comff(this, i); } for(i = GetBytesTotal() - 1, j = i; i >= 0; i--) { if(i != j) { ALU->skpnz(); } ALU->incff(this, i); } //Leads--; //Bits++; return ALU->GetSnippet(); } char *Reg :: NegLE() { char i, rb; if(Leads == 0) { //reserve byte to place sign ALU->clrf(this, GetBytesTotal()); Leads += 8; CheckBytesUsed(); } rb = GetBytesTotal(); for(i = 0; i < rb; i++) { ALU->comff(this, i); } for(i = 0; i < rb; i++) { if(i != 0) { ALU->skpnz(); } ALU->incff(this, i); } return ALU->GetSnippet(); } char *Reg :: Copy(Reg *R2) { char i; ALU->ClearSnippet(); ALU->TakeCarry(); for(i = 0; i < R2->GetBytes(); i++) { ALU->movfw(R2, i); ALU->movwf(this, i); } Bits = R2->Bits; Leads = R2->Leads; CheckBytesUsed(); Sign = R2->Sign; Zero = R2->Zero; return ALU->GetSnippet(); } void Reg :: CheckBytesUsed() { char i; i = GetBytesTotal() - BytesUsed; if(i > 0) { BytesUsed += i; } } void Reg :: SetSize(char b, char l) //set size of reg in bits and leads { Bits = b; Leads = l; CheckBytesUsed(); } //--------------------------------------------------------------- PIC16 :: PIC16(void) { cHolder = NULL; wHolder = NULL; vNoteCarry = false; vValidCarry = false; } void PIC16 :: SetNoteCarry(bool val, Reg *R) //Set vNoteCarry flag { vNoteCarry = val; cHolder = R; } void PIC16 :: SetValidCarry(bool val, Reg *R) //Set vValidCarry flag { vValidCarry = val; cHolder = R; } bool PIC16 :: GetNoteCarry(Reg *R) //Get vNoteCarry flag { if(R == cHolder) { return vNoteCarry; } return false; } bool PIC16 :: GetValidCarry(Reg *R) //Get vValidCarry flag { if(R == cHolder) { return vValidCarry; } return false; } char *PIC16 :: TakeCarry() { char i, j, gbt; if(GetNoteCarry(cHolder)) { if(cHolder->endian == big) { for(j = cHolder->GetBytesTotal(), i = j - 1; i >= 0; i--, j--) { movfw(cHolder, i); movwf(cHolder, j); } clrf(cHolder, 0); if(cHolder->Sign) { skpc(); comff(cHolder, 0); } else { rlff(cHolder, 0); } } else { gbt = cHolder->GetBytesTotal(); clrf(cHolder, gbt); if(cHolder->Sign) { skpc(); comff(cHolder, gbt); } else { rlff(cHolder, gbt); } } SetNoteCarry(false, cHolder); SetValidCarry(false, cHolder); cHolder->SetSize(cHolder->GetSize() - cHolder->Sign + 1, 7 + cHolder->Sign); } return str; } char *PIC16 :: movwf(Reg *File, char Index) { sprintf(str + strlen(str), "\tmovwf\t%s%d\n", File->Name, Index); wHolder = File; wIndex = Index; return str; } char *PIC16 :: movfw(Reg *File, char Index) { if(!wValid(File, Index)) { sprintf(str + strlen(str), "\tmovf\t%s%d, w\n", File->Name, Index); wHolder = File; wIndex = Index; File->wasUsed = true; } return str; } char *PIC16 :: movlw(char literal) { sprintf(str + strlen(str), "\tmovlw\t%d\n", literal); wHolder = NULL; return str; } char *PIC16 :: andlw(char literal) { sprintf(str + strlen(str), "\tandlw\t%d\n", literal); wHolder = NULL; return str; } char *PIC16 :: clrw() { sprintf(str + strlen(str), "\tclrw\n"); wHolder = NULL; return str; } char *PIC16 :: clrf(Reg *File, char Index) { if(wValid(File, Index)) { wHolder = NULL; } sprintf(str + strlen(str), "\tclrf\t%s%d\n", File->Name, Index); return str; } char *PIC16 :: swapfw(Reg *File, char Index) { if(wValid(File, Index)) { wHolder = NULL; } sprintf(str + strlen(str), "\tswapf\t%s%d, w\n", File->Name, Index); return str; } char *PIC16 :: swapff(Reg *File, char Index) { if(wValid(File, Index)) { wHolder = NULL; } sprintf(str + strlen(str), "\tswapf\t%s%d, f\n", File->Name, Index); return str; } char *PIC16 :: btfsc(Reg *File, char Index, char Bit) { sprintf(str + strlen(str), "\tbtfsc\t%s%d, %d\n", File->Name, Index, Bit); File->wasUsed = true; return str; } char *PIC16 :: btfss(Reg *File, char Index, char Bit) { sprintf(str + strlen(str), "\tbtfss\t%s%d, %d\n", File->Name, Index, Bit); File->wasUsed = true; return str; } char *PIC16 :: comff(Reg *File, char Index) { if(wValid(File, Index)) { wHolder = NULL; } sprintf(str + strlen(str), "\tcomf\t%s%d, f\n", File->Name, Index); File->wasUsed = true; return str; } char *PIC16 :: clrc() { sprintf(str + strlen(str), "\tclrc\n"); return str; } char *PIC16 :: comc() { movlw(1); wHolder = NULL; sprintf(str + strlen(str), "\txorwf STATUS, f\n"); return str; } char *PIC16 :: skpc() { sprintf(str + strlen(str), "\tskpc\n"); return str; } char *PIC16 :: skpnc() { sprintf(str + strlen(str), "\tskpnc\n"); return str; } char *PIC16 :: skpnz() { sprintf(str + strlen(str), "\tskpnz\n"); return str; } char *PIC16 :: rlff(Reg *File, char Index) { if(wValid(File, Index)) { wHolder = NULL; } sprintf(str + strlen(str), "\trlf\t%s%d, f\n", File->Name, Index); File->wasUsed = true; return str; } char *PIC16 :: rlfw(Reg *File, char Index) { wHolder = NULL; sprintf(str + strlen(str), "\trlf\t%s%d, w\n", File->Name, Index); File->wasUsed = true; return str; } char *PIC16 :: rrff(Reg *File, char Index) { if(wValid(File, Index)) { wHolder = NULL; } sprintf(str + strlen(str), "\trrf\t%s%d, f\n", File->Name, Index); File->wasUsed = true; return str; } char *PIC16 :: rrfw(Reg *File, char Index) { wHolder = NULL; sprintf(str + strlen(str), "\trrf\t%s%d, w\n", File->Name, Index); File->wasUsed = true; return str; } char *PIC16 :: addwff(Reg *File, char Index) { if(wValid(File, Index)) { wHolder = NULL; } sprintf(str + strlen(str), "\taddwf\t%s%d, f\n", File->Name, Index); File->wasUsed = true; return str; } char *PIC16 :: iorwff(Reg *File, char Index) { if(wValid(File, Index)) { wHolder = NULL; } sprintf(str + strlen(str), "\tiorwf\t%s%d, f\n", File->Name, Index); File->wasUsed = true; return str; } char *PIC16 :: iorlw(char literal) { wHolder = NULL; sprintf(str + strlen(str), "\tiorlw\t%d\n", literal); return str; } char *PIC16 :: bsf(Reg *File, char Index, char Bit) { if(wValid(File, Index)) { wHolder = NULL; } sprintf(str + strlen(str), "\tbsf\t%s%d, %d\n", File->Name, Index, Bit); File->wasUsed = true; return str; } char *PIC16 :: subwff(Reg *File, char Index) { if(wValid(File, Index)) { wHolder = NULL; } sprintf(str + strlen(str), "\tsubwf\t%s%d, f\n", File->Name, Index); File->wasUsed = true; return str; } char *PIC16 :: incfszw(Reg *File, char Index) { wHolder = NULL; sprintf(str + strlen(str), "\tincfsz\t%s%d, w\n", File->Name, Index); File->wasUsed = true; return str; } char *PIC16 :: incff(Reg *File, char Index) { if(wValid(File, Index)) { wHolder = NULL; } sprintf(str + strlen(str), "\tincf\t%s%d, f\n", File->Name, Index); File->wasUsed = true; return str; } char *PIC16 :: decff(Reg *File, char Index) { if(wValid(File, Index)) { wHolder = NULL; } sprintf(str + strlen(str), "\tdecf\t%s%d, f\n", File->Name, Index); File->wasUsed = true; return str; } bool PIC16 :: wValid(Reg *File, char Index) { if((File == wHolder) && (wIndex == Index)) { return true; } return false; } //--------------------------------------------------------------- int main() { llist entries; char Error = 0; char AccName[32]; char TmpName[32]; char AccVal=0; endianType endianVal; /* Generate header and title */ html_header(); html_begin("Code Generator Results"); /* Read form values */ read_cgi_input(&entries); if(is_field_exists(entries, "Const")) { Const = atof(cgi_val(entries, "Const")); } if(is_field_exists(entries, "Acc")) { strcpy(AccName, cgi_val(entries, "Acc")); } if(is_field_exists(entries, "Bits")) { AccVal = atoi(cgi_val(entries, "Bits")); } if(is_field_exists(entries, "ConstErr")) { ConstErr = atof(cgi_val(entries, "ConstErr")); } if(is_field_exists(entries, "Temp")) { strcpy(TmpName, cgi_val(entries, "Temp")); } endianVal = big; if(is_field_exists(entries, "endian")) { if(cgi_val(entries, "endian")[0] == 'l') { endianVal = little; } } /* Check for range */ if((strlen(TmpName) == 0) || !isalpha(TmpName[0])) { Error = 4; //Enter temporary register(s) name } if((ConstErr < 0) || (ConstErr > 50)) { Error = 6; //Constant error must be between 0 and 50% } if(Const <= 0) { Error = 2; //Constant value is negative, zero, or error in input } else { AddBits = (char) ceil(log10(Const) / log10(2)); OutBits = AddBits + AccVal; if((AddBits + 1) > ALGINTSIZE) /* 1 added because constant will be decomposed in series of powers of 2 and the highest power may exceed constant value, e.g. 7 = 8 - 1 */ { Error = 5; //Constant out of range (1..ALGINTSIZE) } if(OutBits <= 0) { Error = 7; //Zero result } } if((AccVal < 1) || (AccVal > MAXINPBITS)) { Error = 1; //Accumulator size out of range (1..32) } if((strlen(AccName) == 0) || !isalpha(AccName[0])) { Error = 3; //Enter accumulator name } if(Error == 0) { /* construct register objects */ Reg Acc = Reg(AccName, (char)AccVal, endianVal); Reg Temp = Reg(TmpName, 0, endianVal); //0 bits in temporary /* Open preformatted block */ printf("
\n");
		/* Call code generation */
		constdivmul(&Acc, &Temp);
		/* Close preformatted block */
		printf("
\n"); TimeStamp(); Banner(); } else { /* Report error */ ReportError(Error); } html_end(); list_clear(&entries); return 0; } void ReportError(char Err) { printf("

#%d Error in input

", Err); switch(Err) { case 1: printf("Input size out of range (1..%d bits).\n", MAXINPBITS); break; case 2: printf("Constant value is negative, zero, or not a number.\n"); break; case 3: printf("Enter input register(s) name.\n"); break; case 4: printf("Enter temporary register(s) name.\n"); break; case 5: printf("Too big constant, size over %d bits.\n", ALGINTSIZE); break; case 6: printf("Constant error must be between 0 and 50%.\n"); break; case 7: printf("Result is zero for this combination of input size and constant."); break; default: break; } printf("


Back to form\n"); } void constdivmul(Reg *Acc, Reg *Tmp) { double i, accum; char j, k, last, //counters terms, shifts, alg[MAXALGSIZE], /* algorithm, contains 0, +1, -1 for each shift Point is fixed before index ALGINTSIZE */ AlgSize; //real size of algorithm int copytotempindex = 0, copytotempend = 0; char code[MAXCODESIZE]; code[0] = 0; printf("; %s = %s * %f\n;\n", Acc->Name, Acc->Name, Const); // Determine shifts and adds/subs //1) convert to binary fraction accum = Const; i = pow(2, ALGINTSIZE - 1); for(j = 0; j < MAXALGSIZE; j++, i = i / 2) { alg[j] = 0; if(accum > i) { alg[j] = 1; accum -= i; } } //2) optimize fraction by converting sum of powers of 2 to sum/difference for(j = MAXALGSIZE - 1; j > 1 ; j--) { if((alg[j] + alg[j - 1] + alg[j - 2]) == 3) { //at least three consecutive ones - //change them to difference (111 = 1000 - 1) alg[j] = -1; while(--j >= 0) { if(alg[j] != 0) { alg[j] = 0; } else { alg[j++] = 1; //continue from this bit break; } } } } //3) Show algorithm and choose the size of algorithm i = pow(2, ALGINTSIZE - 1); printf("; ALGORITHM:\n; Clear accumulator\n"); terms = 0; last = 0; accum = Const; for(j = 0; j < MAXALGSIZE; j++) { //check space between shifts if(last < (ALGINTSIZE - 1)) { k = ALGINTSIZE - 1; } else { k = last; } if((j - k) >= Acc->GetSize()) { //too much right shifts - algorithm generation can be stopped printf("; WARNING:\n"); printf("; Needed precision can't be reached because the input register size is too small\n"); j = last; break; } if(alg[j] == 1) { accum -= i; terms++; if(i >= 1) { printf ("; Add input * %.0f to accumulator\n", i); } else { printf ("; Add input / %.0f to accumulator\n", 1 / i); } } if(alg[j] == -1) { accum += i; terms++; if(i >= 1) { printf ("; Substract input * %.0f from accumulator\n", i); } else { printf ("; Substract input / %.0f from accumulator\n", 1 / i); } } if( fabs(accum) <= (ConstErr / 100 * Const) ) { break; } i = i / 2; if(alg[j] != 0) { last = j; } } AlgSize = j + 1; printf("; Move accumulator to result\n"); printf(";\n; Error in constant approximation : %f, %%\n", fabs(accum) / Const * 100); /* Now code can be generated alg[] contains algorithm */ InpBytes = Acc->GetBytes(); OutBytes = (OutBits + 7) / 8; printf("\n\n; Input: %s0", Acc->Name); if(InpBytes > 1) { printf(" .. %s%d", Acc->Name, InpBytes - 1); } printf("\t(%d bits)", Acc->GetSize()); printf("\n; Output: %s0", Acc->Name); if(OutBytes > 1) { printf(" .. %s%d", Acc->Name, OutBytes - 1); } printf("\t(%d bits)", OutBits); ALU = new(PIC16); if(AlgSize < ALGINTSIZE) { //shift left accumulator if its wegiht is higher then 1 sprintf(code + strlen(code), "%s", Acc->ShiftLeft(ALGINTSIZE - AlgSize)); } if(terms != 1) { copytotempindex = strlen(code); sprintf(code + strlen(code), "%s", Tmp->Copy(Acc)); //if more than 1 term, copy input to temporary copytotempend = strlen(code); } for(k = AlgSize - 2; k >= 0; k--) { j = k + 1; //j indexes last value in alg[] shifts = 1; while((alg[k] == 0) && (k >= 0) && (k != (ALGINTSIZE - 1))) { shifts++; k--; } if(k >= 0) { if(j >= ALGINTSIZE) { /* fraction - shift right */ //Acc->RegT = Static; sprintf(code + strlen(code), "%s", Acc->ShiftRight(shifts)); } if(alg[AlgSize - 1] == - 1) { //don't forget to make initial input negative if needed //for integer make negative before shift //for fraction ' ' after " alg[AlgSize - 1] = 0; sprintf(code + strlen(code), "%s", Acc->Neg()); Acc->Sign = true; } if(j < ALGINTSIZE) { /* integer - shift left */ //Acc->RegT = Dynamic; sprintf(code + strlen(code), "%s", Tmp->ShiftLeft(shifts)); } } else { /* end reached - break away */ break; } if(alg[j - shifts] == 1) { // if 1, add sprintf(code + strlen(code), "%s", Acc->Add(Tmp)); if(Acc->Sign) { //before addition accumulator was negative //after became positive //so carry can't be used, because it's set ALU->SetValidCarry(false, Acc); ALU->SetNoteCarry(false, Acc); } Acc->Sign = false; } else { if(alg[j - shifts] == -1) { //if -1, substract (on zero do nothing) sprintf(code + strlen(code), "%s", Acc->Sub(Tmp)); Acc->Sign = true; //always substracted bigger number } } } if(OutBits > Acc->GetSize()) { ALU->ClearSnippet(); sprintf(code + strlen(code), "%s", ALU->TakeCarry()); } if((!Tmp->wasUsed) && (terms != 1)) { ALU->ClearSnippet(); ALU->movfw(Acc, InpBytes - 1); copytotempindex = sprintf(code + copytotempindex, "%s", ALU->GetSnippet()); strcpy(code + copytotempindex, code + copytotempend); } printf("\n\n\tcblock\n"); printf("%s", Acc->ShowUsedRegs()); printf("%s", Tmp->ShowUsedRegs()); printf("\tendc\n\n"); printf("%s\n", code); delete(ALU); } void TimeStamp() { time_t ltime; struct tm *gmt; /* Display UTC. */ time(<ime); gmt = gmtime(<ime); printf("; Generated by www.piclist.com/cgi-bin/constdivmul.exe (version %s)
\n", VERSIONDATE); printf("; %s GMT
\n", asctime(gmt)); } void Banner() { printf("\n"); printf(" \n"); printf(" \n"); printf(" \n"); printf("
\n", "%"); printf("
\n"); printf("I hope my little code generator helps you. Would you like to help \n"); printf("me find a job in U.S.?
\n"); printf("Nikolai Golovchenko\n"); printf("
\n"); }