summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd.c')
-rw-r--r--firmware/drivers/lcd.c116
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() */
185void lcd_write_data(unsigned char* p_bytes, int count) __attribute__ ((section (".icode"))); 183void 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 */
186void lcd_write_data(unsigned char* p_bytes, int count) 187void 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 */
295void 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 */