]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/commitdiff
apohw: A bit advanced virtual hd44780 driver. Needs fixes.
authorRostislav Lisovy <lisovy@gmail.com>
Fri, 30 Mar 2012 19:44:01 +0000 (21:44 +0200)
committerRostislav Lisovy <lisovy@gmail.com>
Fri, 30 Mar 2012 19:44:01 +0000 (21:44 +0200)
hw/apohw.c

index 55b84b4218cf12dfd0bdb2d0d588d98f3e617148..e5c48c7ca11f1377c679f7cb5f50e415da820e66 100644 (file)
 #define APOTERM_RD_LCD_RDATA                           0x3
 
 /**** HD44780 ****/
-#define APOTERM_HD44780_DISP_SIZE                      (16*2)
+#define APOTERM_HD44780_DISP_COLS                      16
+#define APOTERM_HD44780_DISP_LINES                     2
+#define APOTERM_HD44780_DISP_SIZE                      (APOTERM_HD44780_DISP_COLS \
+                                                       * APOTERM_HD44780_DISP_LINES)
 
 /* RW bit */
 #define APOTERM_HD44780_RD                             0x1
@@ -87,20 +90,28 @@ typedef struct apoio_state_t {
 typedef struct {
        int poweron;
        struct hd44780 {
+               /* Shifting not supported
+                  CGRAM not supported
+                  4-bit interface not supported */
+
                /* TO BE IMPLEMENTED IN FUTURE?
                int CGROM[208+32];
                int CGRAM[16];
                int CGRAM_addr;
                */
                int busyflag;
-               int cursor_val;
                int cursor_incr; /* Sets cursor move direction. This operation
                                    is performed during data write and read. */
 
+               int display_lines; /* Real count of display lines -- not the "N" bit*/
                int display_on;
 
-               char DDRAM[APOTERM_HD44780_DISP_SIZE];
-               int DDRAM_addr;
+#define APOTERM_HD44780_DDRAM_LINE1_START                      0x0
+#define APOTERM_HD44780_DDRAM_LINE2_START                      0x40
+#define APOTERM_HD44780_DDRAM_LINE_SIZE                                0x27
+               uint8_t DDRAM[0x67]; /* Always this size -- not corresponding
+                                    to real display size */
+               unsigned int DDRAM_addr;
        } lcd;
        uint8_t led;            /* LED reg */
        uint8_t kbd;            /* KBD reg */
@@ -119,7 +130,7 @@ typedef struct {
 
 int instance = 0; /* Shared among multiple APOHW devices */
 #define DEFAULT_PORT                   55555
-#define STR_BUFF                       255
+#define STR_BUFF                       256 // FIXME?
 #define DEBUG_APOHW                    1
 #undef DEBUG_APOHW
 
@@ -247,68 +258,127 @@ static void apoterm_init(apohw_state_t *d)
 {
        apoterm_state_t *apoterm = &d->apoterm;
 
+       apoterm->lcd.busyflag = 0;
+       apoterm->lcd.DDRAM_addr = 0;
        apoterm->lcd.cursor_incr = 1;
+       apoterm->lcd.display_lines = 1;
+}
+
+static void apoterm_hd44780_increment_DDRAM_addr(struct hd44780 *lcd)
+{
+       //printf("apoterm_hd44780_increment_DDRAM_addr invoked lcd->DDRAM_addr = 0x%x "
+       //      "lcd->cursor_incr = %i\n", lcd->DDRAM_addr, lcd->cursor_incr);
+       /* Same for display_lines = 1 or 2 */
+       lcd->DDRAM_addr = ((lcd->DDRAM_addr + lcd->cursor_incr)
+               % APOTERM_HD44780_DDRAM_LINE_SIZE);
+}
+
+static int apoterm_hd44780_print(struct hd44780 *lcd, int line, char* buff)
+{
+       if (lcd->display_on != 1)
+               buff[0] = '\0';
+               return 0;
+
+       if (line == 1) {
+               memcpy(buff, &lcd->DDRAM[APOTERM_HD44780_DDRAM_LINE1_START],
+                       APOTERM_HD44780_DISP_COLS);
+               buff[APOTERM_HD44780_DISP_COLS] = '\0';
+
+               return APOTERM_HD44780_DISP_COLS;
+       }
+
+       if (line == 2) {
+               memcpy(buff, &lcd->DDRAM[APOTERM_HD44780_DDRAM_LINE2_START],
+                       APOTERM_HD44780_DISP_COLS);
+               buff[APOTERM_HD44780_DISP_COLS] = '\0';
+
+               return APOTERM_HD44780_DISP_COLS;
+       }
+
+       buff[0] = '\0';
+       return 0;
 }
 
 static int apoterm_hd44780(uint8_t data, int rw, int rs, struct hd44780 *lcd)
 {
-       printf("apoterm_hd44780 invoked. data = %i; rw = %i; rs = %i\n", data, rw, rs);
+       uint8_t ret;
+       //printf("apoterm_hd44780 invoked. data = %i; rw = %i; rs = %i\n", data, rw, rs);
 
        if (rw == APOTERM_HD44780_WR) {
                if (rs == APOTERM_HD44780_INSTREG) {
-                       if (data & APOTERM_HD44780_CLEAR_DISP_m) {
-                               lcd->cursor_val = 0;
-                               memset(lcd->DDRAM, 0, APOTERM_HD44780_DISP_SIZE);
+                       printf("APOTERM_HD44780_WR INSTREG data = 0x%x\n", data);
 
-                       } else if (data & APOTERM_HD44780_RETURN_HOME_m) {
-                               lcd->cursor_val = 0;
+                       /* Be aware of the sequence of checked conditions --
+                       we must start from the mast with the "more significant" bits */
+                       if (data & APOTERM_HD44780_SET_DDRAM_ADDR_m) {
+                               lcd->DDRAM_addr = ((uint8_t)data & 0x7F);
 
-                       } else if (data & APOTERM_HD44780_ENTRY_MODE_SET_m) {
-                               if (data & (1 << 1)) /* Increment */
-                                       lcd->cursor_incr = 1;
+                       } else if (data & APOTERM_HD44780_SET_CGRAM_ADDR_m) {
+
+                       } else if (data & APOTERM_HD44780_FUNCTION_SET_m) {
+                               if (data & (1 << 4)) /* Sets interface data length */
+                                       {} // FIXME
+
+                               if (data & (1 << 3)) /* Number of display lines */
+                                       lcd->display_lines = 2;
                                else
-                                       lcd->cursor_incr = -1;
+                                       lcd->display_lines = 1;
 
-                               if (data & (1 << 0)) { /* Shifts the entire display ... */
-                                       // FIXME
-                               }
+                               if (data & (1 << 2)) /* Character font */
+                                       {} // FIXME
+
+                       } else if (data & APOTERM_HD44780_CURSOR_DISPLAY_SHIFT_m) {
+                               /* Cursor or Display Shift */
 
                        } else if (data & APOTERM_HD44780_DISPLAY_ON_OFF_m) {
-                               if (data & (1 << 2)) /* Display on */
+                               if (data & (1 << 2)) /* Display on */
                                        lcd->display_on = 1;
-                               else
+                               } else {
                                        lcd->display_on = 0;
+                               }
 
                                if (data & (1 << 1)) /* The cursor is displayed */
                                        {} // FIXME
                                if (data & (1 << 0)) /* The character indicated by the cursor blinks */
                                        {} // FIXME
 
-                       } else if (data & APOTERM_HD44780_CURSOR_DISPLAY_SHIFT_m) {
-                               /* Cursor or Display Shift */
+                       } else if (data & APOTERM_HD44780_ENTRY_MODE_SET_m) {
+                               if (data & (1 << 1)) /* Increment */
+                                       lcd->cursor_incr = 1;
+                               else
+                                       lcd->cursor_incr = -1;
 
-                       } else if (data & APOTERM_HD44780_FUNCTION_SET_m) {
-                               /* Function set */
+                               if (data & (1 << 0)) { /* Shifts the entire display ... */
+                                       // FIXME
+                               }
 
-                       } else if (data & APOTERM_HD44780_SET_CGRAM_ADDR_m) {
+                       } else if (data & APOTERM_HD44780_RETURN_HOME_m) {
+                               lcd->DDRAM_addr = 0;
 
-                       } else if (data & APOTERM_HD44780_SET_DDRAM_ADDR_m) {
-                               lcd->DDRAM_addr = (data & 0x7F);
+                       } else if (data & APOTERM_HD44780_CLEAR_DISP_m) {
+                               lcd->DDRAM_addr = 0;
+                               memset(lcd->DDRAM, 0, APOTERM_HD44780_DISP_SIZE);
                        }
+
                }
 
                if (rs == APOTERM_HD44780_DATREG) {
-                       lcd->cursor_val = (lcd->cursor_val + lcd->cursor_incr) % APOTERM_HD44780_DISP_SIZE;
-                       lcd->DDRAM[lcd->cursor_val] = data;
+                       printf("APOTERM_HD44780_WR addr = 0x%x data = 0x%x\n", lcd->DDRAM_addr, (uint8_t)data);
+                       lcd->DDRAM[lcd->DDRAM_addr] = (uint8_t)data;
+                       apoterm_hd44780_increment_DDRAM_addr(lcd);
                }
 
        } else if (rw == APOTERM_HD44780_RD) {
                if (rs == APOTERM_HD44780_DATREG) {
-                       return lcd->DDRAM[lcd->DDRAM_addr];
+                       printf("APOTERM_HD44780_RD lcd->DDRAM_addr = 0x%x, data = 0x%x\n",
+                               lcd->DDRAM_addr, (uint8_t)lcd->DDRAM[lcd->DDRAM_addr]);
+                       ret = lcd->DDRAM[lcd->DDRAM_addr];
+                       apoterm_hd44780_increment_DDRAM_addr(lcd);
+                       return ret;
                }
 
                if (rs == APOTERM_HD44780_INSTREG) {
-                       return lcd->busyflag | lcd->cursor_val;
+                       return lcd->busyflag | (lcd->DDRAM_addr & 0x7F);
                }
        }
 
@@ -321,6 +391,7 @@ static void apoterm_display_update(apohw_state_t *d)
        apoio_state_t *apoio = &d->apoio;
        char buff[STR_BUFF];
        int i;
+       char lcd_buff[APOTERM_HD44780_DISP_COLS + 1];
 
        snprintf(buff, STR_BUFF, "---------------------------------------------------\n");
        socket_write(d, buff, strlen(buff));
@@ -341,8 +412,13 @@ static void apoterm_display_update(apohw_state_t *d)
        }
 
        socket_write(d, buff, strlen(buff));
-       snprintf(buff, STR_BUFF, "LCD: %s\n",
-               (apoterm->lcd.display_on == 1) ? apoterm->lcd.DDRAM : "");
+
+       apoterm_hd44780_print(&apoterm->lcd, 1, (char*)&lcd_buff);
+       snprintf(buff, STR_BUFF, "LCD1: %s\n", lcd_buff);
+       socket_write(d, buff, strlen(buff));
+
+       apoterm_hd44780_print(&apoterm->lcd, 2, (char*)&lcd_buff);
+       snprintf(buff, STR_BUFF, "LCD2: %s\n", lcd_buff);
        socket_write(d, buff, strlen(buff));
 }
 
@@ -400,21 +476,18 @@ static void upgrade_apoterm_state(apohw_state_t *d)
                }
 
                apoterm_display_update(d);
-       }
 
-       /* (RD | CS0): H -> L */
-       if (rd_en_old && !rd_en_new)
-       {
+       } else if (rd_en_old && !rd_en_new) { /* (RD | CS0): H -> L */
                switch (apoio->emul_bus_ctrl_new & APOTERM_ADDR_m) {
                case APOTERM_RD_LCD_STAT:
-                       apoterm_hd44780(apoio->emul_bus_data_out,
+                       apoio->emul_bus_data_in = apoterm_hd44780(0,
                                APOTERM_HD44780_RD,
                                APOTERM_HD44780_INSTREG,
                                &apoterm->lcd);
                        break;
 
                case APOTERM_RD_LCD_RDATA:
-                       apoterm_hd44780(apoio->emul_bus_data_out,
+                       apoio->emul_bus_data_in = apoterm_hd44780(0,
                                APOTERM_HD44780_RD,
                                APOTERM_HD44780_DATREG,
                                &apoterm->lcd);
@@ -440,9 +513,10 @@ static uint64_t apoio_bar0_read(void *opaque, target_phys_addr_t addr,
        DEBUG_PRINT("read  addr = 0x%02x size = %u\n", (uint32_t)addr, size);
 
        if (addr < APOIO_RAM_SIZE) {
-               return d->apoio.ram[addr];
+               return (uint8_t)d->apoio.ram[addr];
        } else if (addr == APOIO_EMUL_BUS_DATA_IN) {
-               return d->apoio.emul_bus_data_in;
+               DEBUG_PRINT(" data = 0x%02x\n", (uint8_t)d->apoio.emul_bus_data_in);
+               return (uint8_t)d->apoio.emul_bus_data_in;
        }
 
        return 0;
@@ -464,17 +538,19 @@ static void apoio_bar0_write(void *opaque, target_phys_addr_t addr,
                if (d->apoio.emul_bus_ctrl_new != data) {
                        d->apoio.emul_bus_ctrl_old = d->apoio.emul_bus_ctrl_new;
                        d->apoio.emul_bus_ctrl_new = data;
+
+                       upgrade_apoterm_state(d);
                }
 
        } else if (addr == APOIO_EMUL_BUS_DATA_OUT) {
                d->apoio.emul_bus_data_out = data;
+               upgrade_apoterm_state(d);
 
        } else if (addr == APOIO_LED_PIO) {
                d->apoio.led_pio = (unsigned int) data;
                printf(DEBUG_PREFIX "LED_PIO = 0x%X\n", d->apoio.led_pio);
        }
 
-       upgrade_apoterm_state(d);
 }
 
 static const MemoryRegionOps apoio_bar0_ops = {