Commit 1fb3d0dab277a05507009ffd4a5bb0b7e2b66b6a
1 parent
3947c3d5
HD44780 LCD Controller
Only very simple emulation of the LCD controller is included. The controller features the standard HD44780 interface and supports character output on four lines using a static 5x7 font and optional backlight controlled by signal on a separate pin. Capabilities such as custom characters, cursor and 5x10 fonts are not implemented. Saving/loading of device state is not implemented either. Signed-off-by: Filip Navara <filip.navara@gmail.com>
Showing
3 changed files
with
431 additions
and
1 deletions
Makefile.target
| ... | ... | @@ -433,7 +433,7 @@ obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o |
| 433 | 433 | obj-arm-y += syborg_virtio.o |
| 434 | 434 | obj-arm-y += at91_aic.o at91_dbgu.o at91_pio.o at91_pit.o at91_pmc.o at91_rtt.o |
| 435 | 435 | obj-arm-y += at91_rstc.o at91_intor.o at91_tc.o at91_emac.o at91pes.o |
| 436 | -obj-arm-y += gpio_rotary.o gpio_keypad.o | |
| 436 | +obj-arm-y += gpio_rotary.o gpio_keypad.o hd44780.o | |
| 437 | 437 | |
| 438 | 438 | ifeq ($(TARGET_BASE_ARCH), arm) |
| 439 | 439 | CPPFLAGS += -DHAS_AUDIO | ... | ... |
hw/at91pes.c
| ... | ... | @@ -95,6 +95,17 @@ static void at91pes_init(ram_addr_t ram_size, |
| 95 | 95 | sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xFFFDC000); |
| 96 | 96 | sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[16]); |
| 97 | 97 | |
| 98 | + dev = qdev_create(NULL, "gpio,hd44780"); | |
| 99 | + qdev_init(dev); | |
| 100 | + for (i = 0; i < 3; i++) { | |
| 101 | + qdev_connect_gpio_out(pioa, 15 - i, qdev_get_gpio_in(dev, 8 + i)); | |
| 102 | + } | |
| 103 | + qdev_connect_gpio_out(piob, 28, qdev_get_gpio_in(dev, 11)); | |
| 104 | + for (i = 0; i < 4; i++) { | |
| 105 | + qdev_connect_gpio_out(pioa, 5 + i, qdev_get_gpio_in(dev, 4 + i)); | |
| 106 | + qdev_connect_gpio_out(dev, 4 + i, qdev_get_gpio_in(pioa, 5 + i)); | |
| 107 | + } | |
| 108 | + | |
| 98 | 109 | dev = qdev_create(NULL, "gpio,keypad"); |
| 99 | 110 | qdev_prop_set_ptr(dev, "keys", keys); |
| 100 | 111 | qdev_init(dev); | ... | ... |
hw/hd44780.c
0 → 100644
| 1 | +/* | |
| 2 | + * HD44780 LCD Controller | |
| 3 | + * | |
| 4 | + * Copyright (c) 2009 Filip Navara | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | + | |
| 25 | +#include "sysbus.h" | |
| 26 | +#include "console.h" | |
| 27 | +#include "pixel_ops.h" | |
| 28 | + | |
| 29 | +/* pin mapping: | |
| 30 | + 8x Data | |
| 31 | + Register Select (input only) | |
| 32 | + Read/Write (input only) | |
| 33 | + Enable (input only) | |
| 34 | + Backlight (input only) */ | |
| 35 | + | |
| 36 | +#define D(x) x | |
| 37 | + | |
| 38 | +#define PIN_RS 8 | |
| 39 | +#define PIN_RW 9 | |
| 40 | +#define PIN_E 10 | |
| 41 | +#define PIN_BL 11 | |
| 42 | + | |
| 43 | +#define LCD_CLR 1 /* DB0: clear display */ | |
| 44 | +#define LCD_HOME 2 /* DB1: return to home position */ | |
| 45 | +#define LCD_ENTRY_MODE 4 /* DB2: set entry mode */ | |
| 46 | +#define LCD_ENTRY_INC 2 /* DB1: increment */ | |
| 47 | +#define LCD_ENTRY_SHIFT 1 /* DB2: shift */ | |
| 48 | +#define LCD_ON_CTRL 8 /* DB3: turn lcd/cursor on */ | |
| 49 | +#define LCD_ON_DISPLAY 4 /* DB2: turn display on */ | |
| 50 | +#define LCD_ON_CURSOR 2 /* DB1: turn cursor on */ | |
| 51 | +#define LCD_ON_BLINK 1 /* DB0: blinking cursor */ | |
| 52 | +#define LCD_MOVE 16 /* DB4: move cursor/display */ | |
| 53 | +#define LCD_MOVE_DISP 8 /* DB3: move display (0-> move cursor) */ | |
| 54 | +#define LCD_MOVE_RIGHT 4 /* DB2: move right (0-> left) */ | |
| 55 | +#define LCD_FUNCTION 32 /* DB5: function set */ | |
| 56 | +#define LCD_FUNCTION_8BIT 16 /* DB4: set 8BIT mode (0->4BIT mode) */ | |
| 57 | +#define LCD_FUNCTION_2LINES 8 /* DB3: two lines (0->one line) */ | |
| 58 | +#define LCD_FUNCTION_10DOTS 4 /* DB2: 5x10 font (0->5x7 font) */ | |
| 59 | +#define LCD_CGRAM 64 /* DB6: set CG RAM address */ | |
| 60 | +#define LCD_DDRAM 128 /* DB7: set DD RAM address */ | |
| 61 | +#define LCD_BUSY 64 /* DB7: LCD is busy */ | |
| 62 | + | |
| 63 | +#define WIDTH 20 | |
| 64 | +#define HEIGHT 4 | |
| 65 | +#define CZOOM 3 | |
| 66 | + | |
| 67 | +uint8_t font5x7[][7]={ | |
| 68 | +/* */ {0x00,0x00,0x00,0x00,0x00,0x00,0x00}, | |
| 69 | +/* ! */ {0x04,0x04,0x04,0x04,0x00,0x00,0x04}, | |
| 70 | +/* " */ {0x0A,0x0A,0x0A,0x00,0x00,0x00,0x00}, | |
| 71 | +/* # */ {0x0A,0x0A,0x1F,0x0A,0x1F,0x0A,0x0A}, | |
| 72 | +/* $ */ {0x04,0x0F,0x14,0x0E,0x05,0x1E,0x04}, | |
| 73 | +/* % */ {0x18,0x19,0x02,0x04,0x08,0x13,0x03}, | |
| 74 | +/* & */ {0x00,0x00,0x00,0x00,0x00,0x00,0x00}, | |
| 75 | +/* ' */ {0x0C,0x04,0x08,0x00,0x00,0x00,0x00}, | |
| 76 | +/* ( */ {0x02,0x04,0x08,0x08,0x08,0x04,0x02}, | |
| 77 | +/* ) */ {0x08,0x04,0x02,0x02,0x02,0x04,0x08}, | |
| 78 | +/* * */ {0x00,0x04,0x15,0x0E,0x15,0x04,0x00}, | |
| 79 | +/* + */ {0x00,0x04,0x04,0x1F,0x04,0x04,0x00}, | |
| 80 | +/* , */ {0x00,0x00,0x00,0x00,0x0C,0x04,0x08}, | |
| 81 | +/* - */ {0x00,0x00,0x00,0x1F,0x00,0x00,0x00}, | |
| 82 | +/* . */ {0x00,0x00,0x00,0x00,0x00,0x0C,0x0C}, | |
| 83 | +/* / */ {0x00,0x01,0x02,0x04,0x08,0x10,0x00}, | |
| 84 | +/* 0 */ {0x0E,0x11,0x13,0x15,0x19,0x11,0x0E}, | |
| 85 | +/* 1 */ {0x04,0x0C,0x04,0x04,0x04,0x04,0x0E}, | |
| 86 | +/* 2 */ {0x0E,0x11,0x01,0x02,0x04,0x08,0x1F}, | |
| 87 | +/* 3 */ {0x1F,0x02,0x04,0x02,0x01,0x11,0x0E}, | |
| 88 | +/* 4 */ {0x02,0x06,0x0A,0x12,0x1F,0x02,0x02}, | |
| 89 | +/* 5 */ {0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E}, | |
| 90 | +/* 6 */ {0x06,0x08,0x10,0x1E,0x11,0x11,0x0E}, | |
| 91 | +/* 7 */ {0x1F,0x01,0x02,0x04,0x08,0x08,0x08}, | |
| 92 | +/* 8 */ {0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E}, | |
| 93 | +/* 9 */ {0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C}, | |
| 94 | +/* : */ {0x00,0x0C,0x0C,0x00,0x0C,0x0C,0x00}, | |
| 95 | +/* ; */ {0x00,0x0C,0x0C,0x00,0x0C,0x04,0x08}, | |
| 96 | +/* < */ {0x02,0x04,0x08,0x10,0x08,0x04,0x02}, | |
| 97 | +/* = */ {0x00,0x00,0x1F,0x00,0x1F,0x00,0x00}, | |
| 98 | +/* > */ {0x08,0x04,0x02,0x01,0x02,0x04,0x08}, | |
| 99 | +/* ? */ {0x0E,0x11,0x01,0x02,0x04,0x00,0x04}, | |
| 100 | +/* @ */ {0x0E,0x11,0x01,0x0D,0x15,0x15,0x0E}, | |
| 101 | +/* A */ {0x0E,0x11,0x11,0x11,0x1F,0x11,0x11}, | |
| 102 | +/* B */ {0x1E,0x11,0x11,0x1E,0x11,0x11,0x1E}, | |
| 103 | +/* C */ {0x0E,0x11,0x10,0x10,0x10,0x11,0x0E}, | |
| 104 | +/* D */ {0x1C,0x12,0x11,0x11,0x11,0x12,0x1C}, | |
| 105 | +/* E */ {0x1F,0x10,0x10,0x1E,0x10,0x10,0x1F}, | |
| 106 | +/* F */ {0x1F,0x10,0x10,0x1E,0x10,0x10,0x10}, | |
| 107 | +/* G */ {0x0E,0x11,0x10,0x17,0x11,0x11,0x0F}, | |
| 108 | +/* H */ {0x11,0x11,0x11,0x1F,0x11,0x11,0x11}, | |
| 109 | +/* I */ {0x0E,0x04,0x04,0x04,0x04,0x04,0x0E}, | |
| 110 | +/* J */ {0x07,0x02,0x02,0x02,0x02,0x12,0x0C}, | |
| 111 | +/* K */ {0x11,0x12,0x14,0x18,0x14,0x12,0x11}, | |
| 112 | +/* L */ {0x10,0x10,0x10,0x10,0x10,0x10,0x1F}, | |
| 113 | +/* M */ {0x11,0x1B,0x15,0x15,0x11,0x11,0x11}, | |
| 114 | +/* N */ {0x11,0x11,0x19,0x15,0x13,0x11,0x11}, | |
| 115 | +/* O */ {0x0E,0x11,0x11,0x11,0x11,0x11,0x0E}, | |
| 116 | +/* P */ {0x1E,0x11,0x11,0x1E,0x10,0x10,0x10}, | |
| 117 | +/* Q */ {0x0E,0x11,0x11,0x11,0x15,0x12,0x0D}, | |
| 118 | +/* R */ {0x1E,0x11,0x11,0x1E,0x14,0x12,0x11}, | |
| 119 | +/* S */ {0x0F,0x10,0x10,0x0E,0x01,0x01,0x1E}, | |
| 120 | +/* T */ {0x1F,0x04,0x04,0x04,0x04,0x04,0x04}, | |
| 121 | +/* U */ {0x11,0x11,0x11,0x11,0x11,0x11,0x0E}, | |
| 122 | +/* V */ {0x11,0x11,0x11,0x11,0x11,0x0A,0x04}, | |
| 123 | +/* W */ {0x11,0x11,0x11,0x15,0x15,0x15,0x0A}, | |
| 124 | +/* X */ {0x11,0x11,0x0A,0x04,0x0A,0x11,0x11}, | |
| 125 | +/* Y */ {0x11,0x11,0x11,0x0A,0x04,0x04,0x04}, | |
| 126 | +/* Z */ {0x1F,0x01,0x02,0x04,0x08,0x10,0x1F}, | |
| 127 | +/* [ */ {0x0E,0x08,0x08,0x08,0x08,0x08,0x0E}, | |
| 128 | +/* \ */ {0x00,0x10,0x08,0x04,0x02,0x01,0x00}, | |
| 129 | +/* ] */ {0x0E,0x02,0x02,0x02,0x02,0x02,0x0E}, | |
| 130 | +/* ^ */ {0x04,0x0A,0x11,0x00,0x00,0x00,0x00}, | |
| 131 | +/* _ */ {0x00,0x00,0x00,0x00,0x00,0x00,0x1F}, | |
| 132 | +/* ` */ {0x08,0x04,0x02,0x00,0x00,0x00,0x00}, | |
| 133 | +/* a */ {0x00,0x00,0x0E,0x01,0x0F,0x11,0x0F}, | |
| 134 | +/* b */ {0x10,0x10,0x10,0x16,0x19,0x11,0x1E}, | |
| 135 | +/* c */ {0x00,0x00,0x0E,0x10,0x10,0x11,0x0E}, | |
| 136 | +/* d */ {0x01,0x01,0x01,0x0D,0x13,0x11,0x0F}, | |
| 137 | +/* e */ {0x00,0x00,0x0E,0x11,0x1F,0x10,0x0E}, | |
| 138 | +/* f */ {0x06,0x09,0x08,0x1C,0x08,0x08,0x08}, | |
| 139 | +/* g */ {0x00,0x0F,0x11,0x11,0x0F,0x01,0x0E}, | |
| 140 | +/* h */ {0x10,0x10,0x16,0x19,0x11,0x11,0x11}, | |
| 141 | +/* i */ {0x00,0x04,0x00,0x04,0x04,0x04,0x04}, | |
| 142 | +/* j */ {0x02,0x00,0x06,0x02,0x02,0x12,0x0C}, | |
| 143 | +/* k */ {0x10,0x10,0x12,0x14,0x18,0x14,0x12}, | |
| 144 | +/* l */ {0x04,0x04,0x04,0x04,0x04,0x04,0x0F}, | |
| 145 | +/* m */ {0x00,0x00,0x1A,0x15,0x15,0x11,0x11}, | |
| 146 | +/* n */ {0x00,0x00,0x16,0x19,0x11,0x11,0x11}, | |
| 147 | +/* o */ {0x00,0x00,0x0E,0x11,0x11,0x11,0x0E}, | |
| 148 | +/* p */ {0x00,0x00,0x1E,0x11,0x1E,0x10,0x10}, | |
| 149 | +/* q */ {0x00,0x00,0x0D,0x13,0x0F,0x01,0x01}, | |
| 150 | +/* r */ {0x00,0x00,0x16,0x19,0x10,0x10,0x10}, | |
| 151 | +/* s */ {0x00,0x00,0x0E,0x10,0x0E,0x01,0x1E}, | |
| 152 | +/* t */ {0x08,0x08,0x1C,0x08,0x08,0x09,0x06}, | |
| 153 | +/* u */ {0x00,0x00,0x11,0x11,0x11,0x13,0x0D}, | |
| 154 | +/* v */ {0x00,0x00,0x11,0x11,0x11,0x0A,0x04}, | |
| 155 | +/* w */ {0x00,0x00,0x11,0x11,0x15,0x15,0x0A}, | |
| 156 | +/* x */ {0x00,0x00,0x11,0x0A,0x04,0x0A,0x11}, | |
| 157 | +/* y */ {0x00,0x00,0x11,0x11,0x0F,0x01,0x0E}, | |
| 158 | +/* z */ {0x00,0x00,0x1F,0x02,0x04,0x08,0x1F}, | |
| 159 | +/* { */ {0x02,0x04,0x04,0x08,0x04,0x04,0x02}, | |
| 160 | +/* | */ {0x04,0x04,0x04,0x04,0x04,0x04,0x04}, | |
| 161 | +/* } */ {0x08,0x04,0x04,0x02,0x04,0x04,0x08}, | |
| 162 | +}; | |
| 163 | + | |
| 164 | +typedef struct LCDState { | |
| 165 | + SysBusDevice busdev; | |
| 166 | + qemu_irq out[8]; | |
| 167 | + DisplayState *ds; | |
| 168 | + | |
| 169 | + uint8_t input; | |
| 170 | + uint32_t control : 1; | |
| 171 | + uint32_t rw : 1; | |
| 172 | + uint32_t backlight : 1; | |
| 173 | + | |
| 174 | + uint8_t mode8bit : 1; | |
| 175 | + uint8_t write_low : 1; | |
| 176 | + | |
| 177 | + uint8_t ac; /* address counter */ | |
| 178 | + uint8_t dispcol; /* first visible column (display shift!) */ | |
| 179 | + uint8_t id : 1; /* cursor move increase(1)/decrease(0) */ | |
| 180 | + uint8_t sh : 1; /* shift display(1) */ | |
| 181 | + uint8_t ddram : 1; /* access ddram(1)/cgram(0) */ | |
| 182 | + | |
| 183 | + uint8_t display : 1; | |
| 184 | + uint8_t cursor : 1; | |
| 185 | + uint8_t blink : 1; | |
| 186 | + | |
| 187 | + uint8_t two_lines : 1; | |
| 188 | + uint8_t font5x10 : 1; | |
| 189 | + | |
| 190 | + uint8_t need_update : 1; | |
| 191 | + char data[20 * 4]; | |
| 192 | +} LCDState; | |
| 193 | + | |
| 194 | +static void draw_char(DisplayState *ds, int x, int y, char ch, uint32_t color, uint32_t backcolor) | |
| 195 | +{ | |
| 196 | + uint8_t *d; | |
| 197 | + uint8_t cdata; | |
| 198 | + int i, bpp, line; | |
| 199 | + | |
| 200 | + bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; | |
| 201 | + for (line = 0; line < 7 * CZOOM; line++) { | |
| 202 | + d = ds_get_data(ds) + ds_get_linesize(ds) * y + bpp * x; | |
| 203 | + if (ch >= ' ' && (ch - ' ') < sizeof(font5x7)/sizeof(font5x7[0])) | |
| 204 | + cdata = font5x7[(int)(ch - ' ')][line / CZOOM]; | |
| 205 | + else | |
| 206 | + cdata = font5x7[0][line / CZOOM]; | |
| 207 | + switch(bpp) { | |
| 208 | + case 1: | |
| 209 | + d += 5 * CZOOM; | |
| 210 | + for (i = 0; i < 5 * CZOOM; i++) { | |
| 211 | + *((uint8_t *)d) = (cdata & (1 << (i / CZOOM))) ? color : backcolor; | |
| 212 | + d--; | |
| 213 | + } | |
| 214 | + break; | |
| 215 | + case 2: | |
| 216 | + d += 10 * CZOOM; | |
| 217 | + for (i = 0; i < 5 * CZOOM; i++) { | |
| 218 | + *((uint16_t *)d) = (cdata & (1 << (i / CZOOM))) ? color : backcolor; | |
| 219 | + d -= 2; | |
| 220 | + } | |
| 221 | + break; | |
| 222 | + case 4: | |
| 223 | + d += 20 * CZOOM; | |
| 224 | + for (i = 0; i < 5 * CZOOM; i++) { | |
| 225 | + *((uint32_t *)d) = (cdata & (1 << (i / CZOOM))) ? color : backcolor; | |
| 226 | + d -= 4; | |
| 227 | + } | |
| 228 | + break; | |
| 229 | + } | |
| 230 | + y++; | |
| 231 | + } | |
| 232 | +} | |
| 233 | + | |
| 234 | +static void hd44780_enable(LCDState *s) | |
| 235 | +{ | |
| 236 | + if (s->control) { | |
| 237 | + //D(printf("CONTROL: %x\n", s->input)); | |
| 238 | + if (s->input & LCD_DDRAM) { | |
| 239 | + int ddram_addr = s->input & ~LCD_DDRAM; | |
| 240 | + if (ddram_addr >= 0 && ddram_addr < WIDTH) | |
| 241 | + s->ac = ddram_addr; | |
| 242 | + else if (ddram_addr >= 64 && ddram_addr < 64 + WIDTH) | |
| 243 | + s->ac = (ddram_addr - 64) + WIDTH; | |
| 244 | + else if (ddram_addr >= 20 && ddram_addr < 20 + WIDTH) | |
| 245 | + s->ac = (ddram_addr - 20) + WIDTH * 2; | |
| 246 | + else if (ddram_addr >= 84 && ddram_addr < 84 + WIDTH) | |
| 247 | + s->ac = (ddram_addr - 84) + WIDTH * 3; | |
| 248 | + s->ddram = 1; | |
| 249 | + } else if (s->input & LCD_CGRAM) { | |
| 250 | + s->ac = s->input & ~LCD_CGRAM; | |
| 251 | + s->ddram = 0; | |
| 252 | + } else if (s->input & LCD_FUNCTION) { | |
| 253 | + s->mode8bit = !!(s->input & LCD_FUNCTION_8BIT); | |
| 254 | + s->two_lines = !!(s->input & LCD_FUNCTION_2LINES); | |
| 255 | + s->font5x10 = !!(s->input & LCD_FUNCTION_10DOTS); | |
| 256 | + } else if (s->input & LCD_MOVE) { | |
| 257 | + if (s->input & LCD_MOVE_DISP) { | |
| 258 | + if (s->input & LCD_MOVE_RIGHT) { | |
| 259 | + s->dispcol--; | |
| 260 | + } else { | |
| 261 | + s->dispcol++; | |
| 262 | + } | |
| 263 | + s->dispcol %= sizeof(s->data); | |
| 264 | + } else { | |
| 265 | + // ... | |
| 266 | + } | |
| 267 | + } else if (s->input & LCD_ON_CTRL) { | |
| 268 | + s->display = !!(s->input & LCD_ON_DISPLAY); | |
| 269 | + s->cursor = !!(s->input & LCD_ON_CURSOR); | |
| 270 | + s->blink = !!(s->input & LCD_ON_BLINK); | |
| 271 | + } else if (s->input & LCD_ENTRY_MODE) { | |
| 272 | + s->id = !!(s->input & LCD_ENTRY_INC); | |
| 273 | + s->sh = !!(s->input & LCD_ENTRY_SHIFT); | |
| 274 | + } else if (s->input & LCD_HOME) { | |
| 275 | + s->ac = 0; | |
| 276 | + s->dispcol = 0; | |
| 277 | + s->ddram = 1; | |
| 278 | + } else if (s->input & LCD_CLR) { | |
| 279 | + memset(s->data, 32, sizeof(s->data)); | |
| 280 | + s->ac = 0; | |
| 281 | + s->dispcol = 0; | |
| 282 | + s->id = 1; | |
| 283 | + s->ddram = 1; | |
| 284 | + } | |
| 285 | + } else { | |
| 286 | + if (s->ddram) { | |
| 287 | + s->data[s->ac] = s->input; | |
| 288 | + s->ac++; | |
| 289 | + s->ac %= sizeof(s->data); | |
| 290 | + if (s->sh) { | |
| 291 | + if (s->id) { | |
| 292 | + s->dispcol++; | |
| 293 | + } else { | |
| 294 | + s->dispcol--; | |
| 295 | + } | |
| 296 | + s->dispcol %= sizeof(s->data); | |
| 297 | + } | |
| 298 | + s->need_update = 1; | |
| 299 | + } else { | |
| 300 | + // ... | |
| 301 | + } | |
| 302 | + } | |
| 303 | +} | |
| 304 | + | |
| 305 | +static void hd44780_set_pin(void *opaque, int pin, int level) | |
| 306 | +{ | |
| 307 | + LCDState *s = opaque; | |
| 308 | + | |
| 309 | + if (pin >= 0 && pin <= 7) { | |
| 310 | + if (!s->rw) { | |
| 311 | + if (!s->mode8bit && s->write_low) | |
| 312 | + pin -= 4; | |
| 313 | + if (level) | |
| 314 | + s->input |= 1 << pin; | |
| 315 | + else | |
| 316 | + s->input &= ~(1 << pin); | |
| 317 | + } | |
| 318 | + } else if (pin == PIN_RS) { | |
| 319 | + s->control = !level; | |
| 320 | + } else if (pin == PIN_RW) { | |
| 321 | + s->rw = level; | |
| 322 | + } else if (pin == PIN_E) { | |
| 323 | + if (!level && !s->rw) { | |
| 324 | + if (!s->mode8bit) { | |
| 325 | + s->write_low = !s->write_low; | |
| 326 | + if (!s->write_low) | |
| 327 | + hd44780_enable(s); | |
| 328 | + } else { | |
| 329 | + hd44780_enable(s); | |
| 330 | + } | |
| 331 | + } | |
| 332 | + } else if (pin == PIN_BL) { | |
| 333 | + s->backlight = level; | |
| 334 | + s->need_update = 1; | |
| 335 | + } | |
| 336 | +} | |
| 337 | + | |
| 338 | +static void hd44780_update_display(void *opaque) | |
| 339 | +{ | |
| 340 | + LCDState *s = opaque; | |
| 341 | + uint32_t color_segment, color_led; | |
| 342 | + int y, x, r, g, b; | |
| 343 | + | |
| 344 | + if (s->need_update) { | |
| 345 | + if (s->backlight) { | |
| 346 | + r = 0; | |
| 347 | + g = 0xff; | |
| 348 | + b = 0x80; | |
| 349 | + } else { | |
| 350 | + r = 0xf0; | |
| 351 | + g = 0xe0; | |
| 352 | + b = 0xb0; | |
| 353 | + } | |
| 354 | + | |
| 355 | + switch (ds_get_bits_per_pixel(s->ds)) { | |
| 356 | + case 8: | |
| 357 | + color_segment = rgb_to_pixel8(0, 0, 0); | |
| 358 | + color_led = rgb_to_pixel8(r, g, b); | |
| 359 | + break; | |
| 360 | + case 15: | |
| 361 | + color_segment = rgb_to_pixel15(0, 0, 0); | |
| 362 | + color_led = rgb_to_pixel15(r, g, b); | |
| 363 | + break; | |
| 364 | + case 16: | |
| 365 | + color_segment = rgb_to_pixel16(0, 0, 0); | |
| 366 | + color_led = rgb_to_pixel16(r, g, b); | |
| 367 | + break; | |
| 368 | + case 24: | |
| 369 | + color_segment = rgb_to_pixel24(0, 0, 0); | |
| 370 | + color_led = rgb_to_pixel24(r, g, b); | |
| 371 | + break; | |
| 372 | + case 32: | |
| 373 | + color_segment = rgb_to_pixel32(0, 0, 0); | |
| 374 | + color_led = rgb_to_pixel32(r, g, b); | |
| 375 | + break; | |
| 376 | + default: | |
| 377 | + return; | |
| 378 | + } | |
| 379 | + | |
| 380 | + if (s->display) { | |
| 381 | + for (y = 0; y < HEIGHT; y++) { | |
| 382 | + for (x = 0; x < WIDTH; x++) { | |
| 383 | + draw_char(s->ds, x * 5 * CZOOM, y * 7 * CZOOM, s->data[y * WIDTH + x], color_segment, color_led); | |
| 384 | + } | |
| 385 | + } | |
| 386 | + } | |
| 387 | + | |
| 388 | + dpy_update(s->ds, 0, 0, WIDTH * CZOOM * 5, HEIGHT * CZOOM * 7); | |
| 389 | + } | |
| 390 | +} | |
| 391 | + | |
| 392 | +static void hd44780_invalidate_display(void * opaque) | |
| 393 | +{ | |
| 394 | + LCDState *s = opaque; | |
| 395 | + s->need_update = 1; | |
| 396 | +} | |
| 397 | + | |
| 398 | +static void hd44780_init(SysBusDevice *dev) | |
| 399 | +{ | |
| 400 | + LCDState *s = FROM_SYSBUS(LCDState, dev); | |
| 401 | + | |
| 402 | + s->need_update = 1; | |
| 403 | + | |
| 404 | + qdev_init_gpio_in(&dev->qdev, hd44780_set_pin, 12); | |
| 405 | + qdev_init_gpio_out(&dev->qdev, s->out, 8); | |
| 406 | + | |
| 407 | + s->ds = graphic_console_init(hd44780_update_display, | |
| 408 | + hd44780_invalidate_display, | |
| 409 | + NULL, NULL, s); | |
| 410 | + qemu_console_resize(s->ds, WIDTH * CZOOM * 5, HEIGHT * CZOOM * 7); | |
| 411 | +} | |
| 412 | + | |
| 413 | +static void hd44780_register(void) | |
| 414 | +{ | |
| 415 | + sysbus_register_dev("gpio,hd44780", sizeof(LCDState), | |
| 416 | + hd44780_init); | |
| 417 | +} | |
| 418 | + | |
| 419 | +device_init(hd44780_register) | ... | ... |