📄 avr.cpp
字号:
arg1 = arg1 - addrAt - 1;
if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
arg1 &= (128-1);
return (0xf << 12) | (arg1 << 3) | 1;
case OP_BRNE:
CHECK(arg2, 0);
arg1 = arg1 - addrAt - 1;
if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
arg1 &= (128-1);
return (0xf << 12) | (1 << 10) | (arg1 << 3) | 1;
case OP_BRLO:
CHECK(arg2, 0);
arg1 = arg1 - addrAt - 1;
if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
arg1 &= (128-1);
return (0xf << 12) | (arg1 << 3);
case OP_BRGE:
CHECK(arg2, 0);
arg1 = arg1 - addrAt - 1;
if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
arg1 &= (128-1);
return (0xf << 12) | (1 << 10) | (arg1 << 3) | 4;
case OP_BRLT:
CHECK(arg2, 0);
arg1 = arg1 - addrAt - 1;
if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
arg1 &= (128-1);
return (0xf << 12) | (arg1 << 3) | 4;
case OP_BRCC:
CHECK(arg2, 0);
arg1 = arg1 - addrAt - 1;
if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
arg1 &= (128-1);
return (0xf << 12) | (1 << 10) | (arg1 << 3);
case OP_BRCS:
CHECK(arg2, 0);
arg1 = arg1 - addrAt - 1;
if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
arg1 &= (128-1);
return (0xf << 12) | (arg1 << 3);
case OP_MOV:
CHECK(arg1, 5); CHECK(arg2, 5);
return (0xb << 10) | ((arg2 & 0x10) << 5) | (arg1 << 4) |
(arg2 & 0x0f);
case OP_LDI:
CHECK(arg1, 5); CHECK(arg2, 8);
if(!(arg1 & 0x10)) oops();
arg1 &= ~0x10;
return (0xe << 12) | ((arg2 & 0xf0) << 4) | (arg1 << 4) |
(arg2 & 0x0f);
case OP_LD_X:
CHECK(arg1, 5); CHECK(arg2, 0);
return (9 << 12) | (arg1 << 4) | 12;
case OP_ST_X:
CHECK(arg1, 5); CHECK(arg2, 0);
return (0x49 << 9) | (arg1 << 4) | 12;
case OP_WDR:
CHECK(arg1, 0); CHECK(arg2, 0);
return 0x95a8;
default:
oops();
break;
}
}
//-----------------------------------------------------------------------------
// Write an intel IHEX format description of the program assembled so far.
// This is where we actually do the assembly to binary format.
//-----------------------------------------------------------------------------
static void WriteHexFile(FILE *f)
{
BYTE soFar[16];
int soFarCount = 0;
DWORD soFarStart = 0;
DWORD i;
for(i = 0; i < AvrProgWriteP; i++) {
DWORD w = Assemble(i, AvrProg[i].op, AvrProg[i].arg1, AvrProg[i].arg2);
if(soFarCount == 0) soFarStart = i;
soFar[soFarCount++] = (BYTE)(w & 0xff);
soFar[soFarCount++] = (BYTE)(w >> 8);
if(soFarCount >= 0x10 || i == (AvrProgWriteP-1)) {
StartIhex(f);
WriteIhex(f, soFarCount);
WriteIhex(f, (BYTE)((soFarStart*2) >> 8));
WriteIhex(f, (BYTE)((soFarStart*2) & 0xff));
WriteIhex(f, 0x00);
int j;
for(j = 0; j < soFarCount; j++) {
WriteIhex(f, soFar[j]);
}
FinishIhex(f);
soFarCount = 0;
}
}
// end of file record
fprintf(f, ":00000001FF\n");
}
//-----------------------------------------------------------------------------
// Make sure that the given address is loaded in the X register; might not
// have to update all of it.
//-----------------------------------------------------------------------------
static void LoadXAddr(DWORD addr)
{
Instruction(OP_LDI, 27, (addr >> 8));
Instruction(OP_LDI, 26, (addr & 0xff));
}
//-----------------------------------------------------------------------------
// Generate code to write an 8-bit value to a particular register.
//-----------------------------------------------------------------------------
static void WriteMemory(DWORD addr, BYTE val)
{
LoadXAddr(addr);
// load r16 with the data
Instruction(OP_LDI, 16, val);
// do the store
Instruction(OP_ST_X, 16, 0);
}
//-----------------------------------------------------------------------------
// Copy just one bit from one place to another.
//-----------------------------------------------------------------------------
static void CopyBit(DWORD addrDest, int bitDest, DWORD addrSrc, int bitSrc)
{
LoadXAddr(addrSrc); Instruction(OP_LD_X, 16, 0);
LoadXAddr(addrDest); Instruction(OP_LD_X, 17, 0);
Instruction(OP_SBRS, 16, bitSrc);
Instruction(OP_CBR, 17, (1 << bitDest));
Instruction(OP_SBRC, 16, bitSrc);
Instruction(OP_SBR, 17, (1 << bitDest));
Instruction(OP_ST_X, 17, 0);
}
//-----------------------------------------------------------------------------
// Execute the next instruction only if the specified bit of the specified
// memory location is clear (i.e. skip if set).
//-----------------------------------------------------------------------------
static void IfBitClear(DWORD addr, int bit)
{
LoadXAddr(addr);
Instruction(OP_LD_X, 16, 0);
Instruction(OP_SBRS, 16, bit);
}
//-----------------------------------------------------------------------------
// Execute the next instruction only if the specified bit of the specified
// memory location is set (i.e. skip if clear).
//-----------------------------------------------------------------------------
static void IfBitSet(DWORD addr, int bit)
{
LoadXAddr(addr);
Instruction(OP_LD_X, 16, 0);
Instruction(OP_SBRC, 16, bit);
}
//-----------------------------------------------------------------------------
// Set a given bit in an arbitrary (not necessarily I/O memory) location in
// memory.
//-----------------------------------------------------------------------------
static void SetBit(DWORD addr, int bit)
{
LoadXAddr(addr);
Instruction(OP_LD_X, 16, 0);
Instruction(OP_SBR, 16, (1 << bit));
Instruction(OP_ST_X, 16, 0);
}
//-----------------------------------------------------------------------------
// Clear a given bit in an arbitrary (not necessarily I/O memory) location in
// memory.
//-----------------------------------------------------------------------------
static void ClearBit(DWORD addr, int bit)
{
LoadXAddr(addr);
Instruction(OP_LD_X, 16, 0);
Instruction(OP_CBR, 16, (1 << bit));
Instruction(OP_ST_X, 16, 0);
}
//-----------------------------------------------------------------------------
// Configure AVR 16-bit Timer1 to do the timing for us.
//-----------------------------------------------------------------------------
static void ConfigureTimer1(int cycleTimeMicroseconds)
{
int divisor = 1;
int countsPerCycle;
while(divisor <= 1024) {
int timerRate = (Prog.mcuClock / divisor); // hertz
double timerPeriod = 1e6 / timerRate; // timer period, us
countsPerCycle = ((int)(cycleTimeMicroseconds / timerPeriod)) - 1;
if(countsPerCycle < 1000) {
Error(_("Cycle time too fast; increase cycle time, or use faster "
"crystal."));
CompileError();
} else if(countsPerCycle > 0xffff) {
if(divisor >= 1024) {
Error(
_("Cycle time too slow; decrease cycle time, or use slower "
"crystal."));
CompileError();
}
} else {
break;
}
if(divisor == 1) divisor = 8;
else if(divisor == 8) divisor = 64;
else if(divisor == 64) divisor = 256;
else if(divisor == 256) divisor = 1024;
}
WriteMemory(REG_TCCR1A, 0x00); // WGM11=0, WGM10=0
int csn;
switch(divisor) {
case 1: csn = 1; break;
case 8: csn = 2; break;
case 64: csn = 3; break;
case 256: csn = 4; break;
case 1024: csn = 5; break;
default: oops();
}
WriteMemory(REG_TCCR1B, (1<<3) | csn); // WGM13=0, WGM12=1
// `the high byte must be written before the low byte'
WriteMemory(REG_OCR1AH, (countsPerCycle - 1) >> 8);
WriteMemory(REG_OCR1AL, (countsPerCycle - 1) & 0xff);
// Okay, so many AVRs have a register called TIFR, but the meaning of
// the bits in that register varies from device to device...
if(strcmp(Prog.mcu->mcuName, "Atmel AVR ATmega162 40-PDIP")==0) {
WriteMemory(REG_TIMSK, (1 << 6));
} else {
WriteMemory(REG_TIMSK, (1 << 4));
}
}
//-----------------------------------------------------------------------------
// Write the basic runtime. We set up our reset vector, configure all the
// I/O pins, then set up the timer that does the cycling. Next instruction
// written after calling WriteRuntime should be first instruction of the
// timer loop (i.e. the PLC logic cycle).
//-----------------------------------------------------------------------------
static void WriteRuntime(void)
{
DWORD resetVector = AllocFwdAddr();
int i;
Instruction(OP_RJMP, resetVector, 0); // $0000, RESET
for(i = 0; i < 34; i++)
Instruction(OP_RETI, 0, 0);
FwdAddrIsNow(resetVector);
// set up the stack, which we use only when we jump to multiply/divide
// routine
WORD topOfMemory = (WORD)Prog.mcu->ram[0].start + Prog.mcu->ram[0].len - 1;
WriteMemory(REG_SPH, topOfMemory >> 8);
WriteMemory(REG_SPL, topOfMemory & 0xff);
// zero out the memory used for timers, internal relays, etc.
LoadXAddr(Prog.mcu->ram[0].start + Prog.mcu->ram[0].len);
Instruction(OP_LDI, 16, 0);
Instruction(OP_LDI, 18, (Prog.mcu->ram[0].len) & 0xff);
Instruction(OP_LDI, 19, (Prog.mcu->ram[0].len) >> 8);
DWORD loopZero = AvrProgWriteP;
Instruction(OP_SUBI, 26, 1);
Instruction(OP_SBCI, 27, 0);
Instruction(OP_ST_X, 16, 0);
Instruction(OP_SUBI, 18, 1);
Instruction(OP_SBCI, 19, 0);
Instruction(OP_TST, 18, 0);
Instruction(OP_BRNE, loopZero, 0);
Instruction(OP_TST, 19, 0);
Instruction(OP_BRNE, loopZero, 0);
// set up I/O pins
BYTE isInput[MAX_IO_PORTS], isOutput[MAX_IO_PORTS];
BuildDirectionRegisters(isInput, isOutput);
if(UartFunctionUsed()) {
if(Prog.baudRate == 0) {
Error(_("Zero baud rate not possible."));
return;
}
// bps = Fosc/(16*(X+1))
// bps*16*(X + 1) = Fosc
// X = Fosc/(bps*16)-1
// and round, don't truncate
int divisor = (Prog.mcuClock + Prog.baudRate*8)/(Prog.baudRate*16) - 1;
double actual = Prog.mcuClock/(16.0*(divisor+1));
double percentErr = 100*(actual - Prog.baudRate)/Prog.baudRate;
if(fabs(percentErr) > 2) {
ComplainAboutBaudRateError(divisor, actual, percentErr);
}
if(divisor > 4095) ComplainAboutBaudRateOverflow();
WriteMemory(REG_UBRRH, divisor >> 8);
WriteMemory(REG_UBRRL, divisor & 0xff);
WriteMemory(REG_UCSRB, (1 << 4) | (1 << 3)); // RXEN, TXEN
for(i = 0; i < Prog.mcu->pinCount; i++) {
if(Prog.mcu->pinInfo[i].pin == Prog.mcu->uartNeeds.txPin) {
McuIoPinInfo *iop = &(Prog.mcu->pinInfo[i]);
isOutput[iop->port - 'A'] |= (1 << iop->bit);
break;
}
}
if(i == Prog.mcu->pinCount) oops();
}
if(PwmFunctionUsed()) {
for(i = 0; i < Prog.mcu->pinCount; i++) {
if(Prog.mcu->pinInfo[i].pin == Prog.mcu->pwmNeedsPin) {
McuIoPinInfo *iop = &(Prog.mcu->pinInfo[i]);
isOutput[iop->port - 'A'] |= (1 << iop->bit);
break;
}
}
if(i == Prog.mcu->pinCount) oops();
}
for(i = 0; Prog.mcu->dirRegs[i] != 0; i++) {
if(Prog.mcu->dirRegs[i] == 0xff && Prog.mcu->outputRegs[i] == 0xff) {
// skip this one, dummy entry for MCUs with I/O ports not
// starting from A
} else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -