📄 avr.cpp
字号:
IfBitSet(REG_EECR, 1);
Instruction(OP_RJMP, isBusy, 0);
IfBitClear(EepromHighByteWaitingAddr, EepromHighByteWaitingBit);
Instruction(OP_RJMP, done, 0);
// Just increment EEARH:EEARL, to point to the high byte of
// whatever we just wrote the low byte for.
LoadXAddr(REG_EEARL);
Instruction(OP_LD_X, 16, 0);
LoadXAddr(REG_EEARH);
Instruction(OP_LD_X, 17, 0);
Instruction(OP_INC, 16, 0);
DWORD noCarry = AllocFwdAddr();
Instruction(OP_BRNE, noCarry, 0);
Instruction(OP_INC, 17, 0);
FwdAddrIsNow(noCarry);
// X is still REG_EEARH
Instruction(OP_ST_X, 17, 0);
LoadXAddr(REG_EEARL);
Instruction(OP_ST_X, 16, 0);
LoadXAddr(EepromHighByte);
Instruction(OP_LD_X, 16, 0);
LoadXAddr(REG_EEDR);
Instruction(OP_ST_X, 16, 0);
LoadXAddr(REG_EECR);
Instruction(OP_LDI, 16, 0x04);
Instruction(OP_ST_X, 16, 0);
Instruction(OP_LDI, 16, 0x06);
Instruction(OP_ST_X, 16, 0);
ClearBit(EepromHighByteWaitingAddr, EepromHighByteWaitingBit);
FwdAddrIsNow(isBusy);
SetBit(addr, bit);
FwdAddrIsNow(done);
break;
}
case INT_EEPROM_READ: {
MemForVariable(a->name1, &addrl, &addrh);
int i;
for(i = 0; i < 2; i++) {
WriteMemory(REG_EEARH, ((a->literal+i) >> 8));
WriteMemory(REG_EEARL, ((a->literal+i) & 0xff));
WriteMemory(REG_EECR, 0x01);
LoadXAddr(REG_EEDR);
Instruction(OP_LD_X, 16, 0);
if(i == 0) {
LoadXAddr(addrl);
} else {
LoadXAddr(addrh);
}
Instruction(OP_ST_X, 16, 0);
}
break;
}
case INT_EEPROM_WRITE:
MemForVariable(a->name1, &addrl, &addrh);
SetBit(EepromHighByteWaitingAddr, EepromHighByteWaitingBit);
LoadXAddr(addrh);
Instruction(OP_LD_X, 16, 0);
LoadXAddr(EepromHighByte);
Instruction(OP_ST_X, 16, 0);
WriteMemory(REG_EEARH, (a->literal >> 8));
WriteMemory(REG_EEARL, (a->literal & 0xff));
LoadXAddr(addrl);
Instruction(OP_LD_X, 16, 0);
LoadXAddr(REG_EEDR);
Instruction(OP_ST_X, 16, 0);
LoadXAddr(REG_EECR);
Instruction(OP_LDI, 16, 0x04);
Instruction(OP_ST_X, 16, 0);
Instruction(OP_LDI, 16, 0x06);
Instruction(OP_ST_X, 16, 0);
break;
case INT_READ_ADC: {
MemForVariable(a->name1, &addrl, &addrh);
WriteMemory(REG_ADMUX,
(0 << 6) | // AREF, internal Vref odd
(0 << 5) | // right-adjusted
MuxForAdcVariable(a->name1));
// target something around 200 kHz for the ADC clock, for
// 25/(200k) or 125 us conversion time, reasonable
int divisor = (Prog.mcuClock / 200000);
int j = 0;
for(j = 1; j <= 7; j++) {
if((1 << j) > divisor) break;
}
BYTE adcsra =
(1 << 7) | // ADC enabled
(0 << 5) | // not free running
(0 << 3) | // no interrupt enabled
j; // prescaler setup
WriteMemory(REG_ADCSRA, adcsra);
WriteMemory(REG_ADCSRA, (BYTE)(adcsra | (1 << 6)));
DWORD waitForFinsh = AvrProgWriteP;
IfBitSet(REG_ADCSRA, 6);
Instruction(OP_RJMP, waitForFinsh, 0);
LoadXAddr(REG_ADCL);
Instruction(OP_LD_X, 16, 0);
LoadXAddr(addrl);
Instruction(OP_ST_X, 16, 0);
LoadXAddr(REG_ADCH);
Instruction(OP_LD_X, 16, 0);
LoadXAddr(addrh);
Instruction(OP_ST_X, 16, 0);
break;
}
case INT_UART_SEND: {
MemForVariable(a->name1, &addrl, &addrh);
MemForSingleBit(a->name2, TRUE, &addr, &bit);
DWORD noSend = AllocFwdAddr();
IfBitClear(addr, bit);
Instruction(OP_RJMP, noSend, 0);
SetBit(REG_UCSRA, 6); // write 1 to clear bit
LoadXAddr(addrl);
Instruction(OP_LD_X, 16, 0);
LoadXAddr(REG_UDR);
Instruction(OP_ST_X, 16, 0);
FwdAddrIsNow(noSend);
ClearBit(addr, bit);
DWORD dontSet = AllocFwdAddr();
IfBitSet(REG_UCSRA, 6);
Instruction(OP_RJMP, dontSet, 0);
SetBit(addr, bit);
FwdAddrIsNow(dontSet);
break;
}
case INT_UART_RECV: {
MemForVariable(a->name1, &addrl, &addrh);
MemForSingleBit(a->name2, TRUE, &addr, &bit);
ClearBit(addr, bit);
DWORD noChar = AllocFwdAddr();
IfBitClear(REG_UCSRA, 7);
Instruction(OP_RJMP, noChar, 0);
SetBit(addr, bit);
LoadXAddr(REG_UDR);
Instruction(OP_LD_X, 16, 0);
LoadXAddr(addrl);
Instruction(OP_ST_X, 16, 0);
LoadXAddr(addrh);
Instruction(OP_LDI, 16, 0);
Instruction(OP_ST_X, 16, 0);
FwdAddrIsNow(noChar);
break;
}
case INT_END_IF:
case INT_ELSE:
return;
case INT_SIMULATE_NODE_STATE:
case INT_COMMENT:
break;
default:
oops();
break;
}
}
}
//-----------------------------------------------------------------------------
// 16x16 signed multiply, code from Atmel app note AVR200. op1 in r17:16,
// op2 in r19:18, result low word goes into r19:18.
//-----------------------------------------------------------------------------
static void MultiplyRoutine(void)
{
FwdAddrIsNow(MultiplyAddress);
DWORD m16s_1;
DWORD m16s_2 = AllocFwdAddr();
Instruction(OP_SUB, 21, 21);
Instruction(OP_SUB, 20, 20);
Instruction(OP_LDI, 22, 16);
m16s_1 = AvrProgWriteP; Instruction(OP_BRCC, m16s_2, 0);
Instruction(OP_ADD, 20, 16);
Instruction(OP_ADC, 21, 17);
FwdAddrIsNow(m16s_2); Instruction(OP_SBRC, 18, 0);
Instruction(OP_SUB, 20, 16);
Instruction(OP_SBRC, 18, 0);
Instruction(OP_SBC, 21, 17);
Instruction(OP_ASR, 21, 0);
Instruction(OP_ROR, 20, 0);
Instruction(OP_ROR, 19, 0);
Instruction(OP_ROR, 18, 0);
Instruction(OP_DEC, 22, 0);
Instruction(OP_BRNE, m16s_1, 0);
Instruction(OP_RET, 0, 0);
}
//-----------------------------------------------------------------------------
// 16/16 signed divide, code from the same app note. Dividend in r17:16,
// divisor in r19:18, result goes in r17:16 (and remainder in r15:14).
//-----------------------------------------------------------------------------
static void DivideRoutine(void)
{
FwdAddrIsNow(DivideAddress);
DWORD d16s_1 = AllocFwdAddr();
DWORD d16s_2 = AllocFwdAddr();
DWORD d16s_3;
DWORD d16s_4 = AllocFwdAddr();
DWORD d16s_5 = AllocFwdAddr();
DWORD d16s_6 = AllocFwdAddr();
Instruction(OP_MOV, 13, 17);
Instruction(OP_EOR, 13, 19);
Instruction(OP_SBRS, 17, 7);
Instruction(OP_RJMP, d16s_1, 0);
Instruction(OP_COM, 17, 0);
Instruction(OP_COM, 16, 0);
Instruction(OP_SUBI, 16, 0xff);
Instruction(OP_SBCI, 17, 0xff);
FwdAddrIsNow(d16s_1); Instruction(OP_SBRS, 19, 7);
Instruction(OP_RJMP, d16s_2, 0);
Instruction(OP_COM, 19, 0);
Instruction(OP_COM, 18, 0);
Instruction(OP_SUBI, 18, 0xff);
Instruction(OP_SBCI, 19, 0xff);
FwdAddrIsNow(d16s_2); Instruction(OP_EOR, 14, 14);
Instruction(OP_SUB, 15, 15);
Instruction(OP_LDI, 20, 17);
d16s_3 = AvrProgWriteP; Instruction(OP_ADC, 16, 16);
Instruction(OP_ADC, 17, 17);
Instruction(OP_DEC, 20, 0);
Instruction(OP_BRNE, d16s_5, 0);
Instruction(OP_SBRS, 13, 7);
Instruction(OP_RJMP, d16s_4, 0);
Instruction(OP_COM, 17, 0);
Instruction(OP_COM, 16, 0);
Instruction(OP_SUBI, 16, 0xff);
Instruction(OP_SBCI, 17, 0xff);
FwdAddrIsNow(d16s_4); Instruction(OP_RET, 0, 0);
FwdAddrIsNow(d16s_5); Instruction(OP_ADC, 14, 14);
Instruction(OP_ADC, 15, 15);
Instruction(OP_SUB, 14, 18);
Instruction(OP_SBC, 15, 19);
Instruction(OP_BRCC, d16s_6, 0);
Instruction(OP_ADD, 14, 18);
Instruction(OP_ADC, 15, 19);
Instruction(OP_CLC, 0, 0);
Instruction(OP_RJMP, d16s_3, 0);
FwdAddrIsNow(d16s_6); Instruction(OP_SEC, 0, 0);
Instruction(OP_RJMP, d16s_3, 0);
}
//-----------------------------------------------------------------------------
// Compile the program to REG code for the currently selected processor
// and write it to the given file. Produce an error message if we cannot
// write to the file, or if there is something inconsistent about the
// program.
//-----------------------------------------------------------------------------
void CompileAvr(char *outFile)
{
FILE *f = fopen(outFile, "w");
if(!f) {
Error(_("Couldn't open file '%s'"), outFile);
return;
}
if(setjmp(CompileErrorBuf) != 0) {
fclose(f);
return;
}
// Here we must set up the addresses of some registers that for some
// stupid reason move around from AVR to AVR.
if(strcmp(Prog.mcu->mcuName, "Atmel AVR ATmega16 40-PDIP")==0 ||
strcmp(Prog.mcu->mcuName, "Atmel AVR ATmega32 40-PDIP")==0 ||
strcmp(Prog.mcu->mcuName, "Atmel AVR ATmega162 40-PDIP")==0 ||
strcmp(Prog.mcu->mcuName, "Atmel AVR ATmega8 28-PDIP")==0)
{
REG_TIMSK = 0x59;
REG_TIFR = 0x58;
REG_UBRRH = 0x40;
REG_UBRRL = 0x29;
REG_UCSRB = 0x2a;
REG_UCSRA = 0x2b;
REG_UDR = 0x2c;
} else {
REG_TIMSK = 0x57;
REG_TIFR = 0x56;
REG_UBRRH = 0x98;
REG_UBRRL = 0x99;
REG_UCSRB = 0x9a;
REG_UCSRA = 0x9b;
REG_UDR = 0x9c;
}
WipeMemory();
MultiplyUsed = FALSE;
MultiplyAddress = AllocFwdAddr();
DivideUsed = FALSE;
DivideAddress = AllocFwdAddr();
AllocStart();
// Where we hold the high byte to program in EEPROM while the low byte
// programs.
EepromHighByte = AllocOctetRam();
AllocBitRam(&EepromHighByteWaitingAddr, &EepromHighByteWaitingBit);
WriteRuntime();
IntPc = 0;
CompileFromIntermediate();
if(Prog.mcu->avrUseIjmp) {
Instruction(OP_LDI, 30, (BeginningOfCycleAddr & 0xff));
Instruction(OP_LDI, 31, (BeginningOfCycleAddr >> 8));
Instruction(OP_IJMP, 0, 0);
} else {
Instruction(OP_RJMP, BeginningOfCycleAddr, 0);
}
MemCheckForErrorsPostCompile();
if(MultiplyUsed) MultiplyRoutine();
if(DivideUsed) DivideRoutine();
WriteHexFile(f);
fclose(f);
char str[MAX_PATH+500];
sprintf(str, _("Compile successful; wrote IHEX for AVR to '%s'.\r\n\r\n"
"Remember to set the processor configuration (fuses) correctly. "
"This does not happen automatically."), outFile);
CompileSuccessfulMessage(str);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -