-
Notifications
You must be signed in to change notification settings - Fork 0
/
delayCyc.c
185 lines (166 loc) · 5.3 KB
/
delayCyc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include "delayCyc.h"
//This'll optimze-out in some cases.
// The timings and instructions used are probably specific to the
// instruction-set in the MCU, the GCC version, optimization-level, etc.
// a/o LCDdirectLVDS11 HLow_delay() this is how it's compiling...
// The actual number of cycs will probably be a few higher...
// (or who knows, if things optimze-out, e.g. small ~0-8 numCycs)
// Due to init, and division...
// Using rounding-up as well...
// the argument is int32_t to allow for negative value testing
// BUT: numCyc is only tested against a uint16_t...
// the greatest value (?) is (UINT16_MAX - 7)
// (maybe it'd make more sense to do the math outside the delay_cyc call
// and allow the preprocessor to change it to 0, instead of doing it here.
//This should probably be reimplemented using _delay_loop_1/2() from
// util/delay_basic.h
// 1 uses three cycles per count, counts from 1-256,
// 256 counts: _delay_loop_1(0)
// 2 uses four, counts from 1-65536, 65536 is passed as 0
//#define DELAY_CYC_DELAY_LOOP TRUE//FALSE
#if(defined(DELAY_CYC_DELAY_LOOP) && DELAY_CYC_DELAY_LOOP)
#warning "This has only been tested with v54+... rowSegBuffer, etc."
void delay_cyc(int32_t numCyc)
{
if(numCyc <= 0)
return;
uint16_t numLoops = (numCyc+3)/4;
_delay_loop_2(numLoops);
/* uint32_t delayLoops = (numCyc+3)/4;
do
{
delayLoops--;
// _delay_loop_2(delayLoops&0xffff);
// delayLoops -= (delayLoops&0xffff);
} while(delayLoops);
*/
/*
//Since this is inline, AND it's only called with values computed
// at compile time, only one of these should be compiled in...
// as necessary...
// If called without precomputed value (i.e. a variable)????
// Maybe I should only use delay_loop_2...
if(numCyc < 256*3)
_delay_loop_1(numCyc/&0xff);
else
*/
}
#else
void delay_cyc(int32_t numCyc)
{
//This shouldn't happen often, but some delay_cyc() calls use math
// to calculate the number of cycles, and it could be negative
if(numCyc < 0)
return;
//#Clocks
//Two instructions:
// ldi r24, 0 //1 i=0
// ldi r25, 0 //1
uint16_t i;
//Loop instructions:
//nop //1
//adiw r24, 0x01 ; 1 //2 i++
//cpi r24, 0x77 ; 119 //1 i<numCyc (119 in this case)
//cpc r25, r1 //1 Apparently it's also testing
// the high byte is 0
//brne .-10 ; //"1/2" return to nop
// if I understand, this is two
// cyc when branching
// or one if not (when complete)
//READ THIS:
// Current Compilation Settings: A/O v18:
// THIS LOOP WILL BE UNROLLED if numLoops <= 5!!!
// Which then turns into numLoops*2 cycles (instead of numLoops*8)
//
// Here's an attempted hack...
// it *should* optimize the test out in either case, so it's like a
// preprocessing directive...
uint16_t numLoops = (((uint16_t)(numCyc)+7)>>3);
// HACK ATTEMPT 2: THATS A LOT OF CODE.
switch(numLoops)
{
case 5:
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
case 4:
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
case 3:
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
case 2:
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
case 1:
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
return;
break;
default:
break;
}
// THUS:
// Each loop is 7 cycles, make it 8 by adding an extra nop and we can
// use >> instead of / for calculations...
// +7 assures rounding-up...
#warning "This loop seems to be optimizing out!"
//for(i=0; i<((numCyc+7)>>3); i++)
for(i=0; i<numLoops; i++)
{
//THIS IS A HACK DUE TO OPTIMIZATION, see above
// It will NOT likely be happy with different versions of gcc...
/* // NOGO: Apparently it won't expand the loop if this is part of it
// so then we have 5 loops AND 8 instructions /within/ the loop
// AND the comparison overhead!`
if(numLoops <= 5)
{
asm("nop");
asm("nop");
// asm("nop");
// asm("nop");
// asm("nop");
// asm("nop");
}
else
{
asm("nop");
asm("nop");
}
*/
//Apparently this loop will optimize-out without this:
// Obviously, one instruction each...
asm("nop");
asm("nop");
}
}
#endif