diff options
-rw-r--r-- | firmware/drivers/lcd.c | 116 |
1 files changed, 110 insertions, 6 deletions
diff --git a/firmware/drivers/lcd.c b/firmware/drivers/lcd.c index 4925ea63d2..5c2c514f10 100644 --- a/firmware/drivers/lcd.c +++ b/firmware/drivers/lcd.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2002 by Alan Korr | 10 | * Copyright (C) 2002 by Alan Korr, speedup by Jörg Hohensohn |
11 | * | 11 | * |
12 | * All files in this archive are subject to the GNU General Public License. | 12 | * All files in this archive are subject to the GNU General Public License. |
13 | * See the file COPYING in the source tree root for full license agreement. | 13 | * See the file COPYING in the source tree root for full license agreement. |
@@ -180,9 +180,10 @@ void lcd_write(bool command, int byte) | |||
180 | Ultimately, all calls to lcd_write(false, xxx) should be substituted by | 180 | Ultimately, all calls to lcd_write(false, xxx) should be substituted by |
181 | this, it will be most efficient if the LCD buffer is tilted to have the | 181 | this, it will be most efficient if the LCD buffer is tilted to have the |
182 | X row as consecutive bytes, so we can write a whole row */ | 182 | X row as consecutive bytes, so we can write a whole row */ |
183 | /* FixMe: somehow the red LED is affected by this, although I don't touch | ||
184 | any other bit. Therefore not used yet, except for lcd_blit() */ | ||
185 | void lcd_write_data(unsigned char* p_bytes, int count) __attribute__ ((section (".icode"))); | 183 | void lcd_write_data(unsigned char* p_bytes, int count) __attribute__ ((section (".icode"))); |
184 | |||
185 | #ifdef HAVE_LCD_CHARCELLS | ||
186 | /* This version works for both Player and Recorder models */ | ||
186 | void lcd_write_data(unsigned char* p_bytes, int count) | 187 | void lcd_write_data(unsigned char* p_bytes, int count) |
187 | { | 188 | { |
188 | do | 189 | do |
@@ -193,7 +194,8 @@ void lcd_write_data(unsigned char* p_bytes, int count) | |||
193 | 194 | ||
194 | byte = *p_bytes++ << 24; /* fetch to MSB position */ | 195 | byte = *p_bytes++ << 24; /* fetch to MSB position */ |
195 | 196 | ||
196 | cli(); /* make port modifications atomic */ | 197 | cli(); /* make port modifications atomic, in case an IRQ uses PBDRL */ |
198 | /* (currently not the case, so this could be optimized away) */ | ||
197 | 199 | ||
198 | /* precalculate the values for later bit toggling, init data write */ | 200 | /* precalculate the values for later bit toggling, init data write */ |
199 | asm ( | 201 | asm ( |
@@ -268,9 +270,9 @@ void lcd_write_data(unsigned char* p_bytes, int count) | |||
268 | "mov.b %3,@%4\n" | 270 | "mov.b %3,@%4\n" |
269 | 271 | ||
270 | "bf 1f\n" | 272 | "bf 1f\n" |
271 | "mov.b %1,@%4\n" | 273 | "mov.b %1,@%4\n" /* set SD high, SC low still */ |
272 | "1: \n" | 274 | "1: \n" |
273 | "or.b %2, @(r0,gbr)\n" | 275 | "or.b %2, @(r0,gbr)\n" /* rise SC (independent of SD level) */ |
274 | 276 | ||
275 | "or.b %5, @(r0,gbr)\n" /* restore port */ | 277 | "or.b %5, @(r0,gbr)\n" /* restore port */ |
276 | : | 278 | : |
@@ -287,3 +289,105 @@ void lcd_write_data(unsigned char* p_bytes, int count) | |||
287 | 289 | ||
288 | } while (--count); /* tail loop is faster */ | 290 | } while (--count); /* tail loop is faster */ |
289 | } | 291 | } |
292 | |||
293 | #else /* #ifdef HAVE_LCD_CHARCELLS */ | ||
294 | /* A further optimized version, exploits that SD is on bit 0 for recorders */ | ||
295 | void lcd_write_data(unsigned char* p_bytes, int count) | ||
296 | { | ||
297 | do | ||
298 | { | ||
299 | unsigned byte; | ||
300 | unsigned sda1; /* precalculated SC=low,SD=1 */ | ||
301 | |||
302 | /* take inverse data, so I can use the NEGC instruction below, it is | ||
303 | the only carry add/sub which does not destroy a source register */ | ||
304 | byte = ~(*p_bytes++ << 24); /* fetch to MSB position */ | ||
305 | |||
306 | cli(); /* make port modifications atomic, in case an IRQ uses PBDRL */ | ||
307 | /* (currently not the case, so this could be optimized away) */ | ||
308 | |||
309 | /* precalculate the values for later bit toggling, init data write */ | ||
310 | asm ( | ||
311 | "mov.b @%1,r0\n" /* r0 = PBDRL */ | ||
312 | "or %3,r0\n" /* r0 |= LCD_DS | LCD_SD DS and SD high, */ | ||
313 | "and %2,r0\n" /* r0 &= ~(LCD_CS | LCD_SC) CS and SC low */ | ||
314 | "mov.b r0,@%1\n" /* PBDRL = r0 */ | ||
315 | "neg r0,%0\n" /* sda1 = 0-r0 */ | ||
316 | : /* outputs: */ | ||
317 | /* %0 */ "=r"(sda1) | ||
318 | : /* inputs: */ | ||
319 | /* %1 */ "r"(LCDR), | ||
320 | /* %2 */ "I"(~(LCD_CS | LCD_SC)), | ||
321 | /* %3 */ "I"(LCD_DS | LCD_SD) | ||
322 | : /* trashed */ | ||
323 | "r0" | ||
324 | ); | ||
325 | |||
326 | /* unrolled loop to serialize the byte */ | ||
327 | asm ( | ||
328 | "shll %0 \n" /* shift the MSB into carry */ | ||
329 | "negc %1, r0\n" /* carry to SD, SC low */ | ||
330 | "mov.b r0,@%3\n" /* set data to port */ | ||
331 | "or %2, r0\n" /* rise SC (independent of SD level) */ | ||
332 | "mov.b r0,@%3\n" /* set to port */ | ||
333 | |||
334 | "shll %0 \n" | ||
335 | "negc %1, r0\n" | ||
336 | "mov.b r0,@%3\n" | ||
337 | "or %2, r0\n" | ||
338 | "mov.b r0,@%3\n" | ||
339 | |||
340 | "shll %0 \n" | ||
341 | "negc %1, r0\n" | ||
342 | "mov.b r0,@%3\n" | ||
343 | "or %2, r0\n" | ||
344 | "mov.b r0,@%3\n" | ||
345 | |||
346 | "shll %0 \n" | ||
347 | "negc %1, r0\n" | ||
348 | "mov.b r0,@%3\n" | ||
349 | "or %2, r0\n" | ||
350 | "mov.b r0,@%3\n" | ||
351 | |||
352 | "shll %0 \n" | ||
353 | "negc %1, r0\n" | ||
354 | "mov.b r0,@%3\n" | ||
355 | "or %2, r0\n" | ||
356 | "mov.b r0,@%3\n" | ||
357 | |||
358 | "shll %0 \n" | ||
359 | "negc %1, r0\n" | ||
360 | "mov.b r0,@%3\n" | ||
361 | "or %2, r0\n" | ||
362 | "mov.b r0,@%3\n" | ||
363 | |||
364 | "shll %0 \n" | ||
365 | "negc %1, r0\n" | ||
366 | "mov.b r0,@%3\n" | ||
367 | "or %2, r0\n" | ||
368 | "mov.b r0,@%3\n" | ||
369 | |||
370 | "shll %0 \n" | ||
371 | "negc %1, r0\n" | ||
372 | "mov.b r0,@%3\n" | ||
373 | "or %2, r0\n" | ||
374 | "mov.b r0,@%3\n" | ||
375 | |||
376 | "or %4, r0\n" /* restore port */ | ||
377 | "mov.b r0,@%3\n" | ||
378 | : /* outputs: */ | ||
379 | : /* inputs: */ | ||
380 | /* %0 */ "r"(byte), | ||
381 | /* %1 */ "r"(sda1), | ||
382 | /* %2 */ "I"(LCD_SC), | ||
383 | /* %3 */ "r"(LCDR), | ||
384 | /* %4 */ "I"(LCD_CS|LCD_DS|LCD_SD|LCD_SC) | ||
385 | : /* trashed: */ | ||
386 | "r0" | ||
387 | ); | ||
388 | |||
389 | sti(); /* end of atomic port modifications */ | ||
390 | |||
391 | } while (--count); /* tail loop is faster */ | ||
392 | } | ||
393 | #endif /* #ifdef HAVE_LCD_CHARCELLS */ | ||