Mirror of CollapseOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
4.0KB

  1. #include <string.h>
  2. #include "t6a04.h"
  3. void t6a04_init(T6A04 *lcd)
  4. {
  5. memset(lcd->ram, 0, T6A04_RAMSIZE);
  6. lcd->enabled = false;
  7. lcd->incmode = T6A04_XINC;
  8. lcd->offset = 0;
  9. lcd->currow = 0;
  10. lcd->curcol = 0;
  11. lcd->just_moved = true;
  12. }
  13. uint8_t t6a04_cmd_rd(T6A04 *lcd)
  14. {
  15. return 0; // we are always ready for a new cmd
  16. }
  17. /*
  18. * 0x00/0x01: 6/8 bit mode
  19. * 0x02/0x03: enable/disable
  20. * 0x04-0x07: incmodes
  21. * 0x20-0x34: set col
  22. * 0x40-0x7f: set Z offset
  23. * 0x80-0xbf: set row
  24. * 0xc0-0xff: set contrast
  25. */
  26. void t6a04_cmd_wr(T6A04 *lcd, uint8_t val)
  27. {
  28. if ((val & 0xc0) == 0xc0) {
  29. // contrast, ignoring
  30. } else if (val & 0x80) {
  31. lcd->currow = val & 0x3f;
  32. lcd->just_moved = true;
  33. } else if (val & 0x40) {
  34. lcd->offset = val & 0x3f;
  35. } else if (val & 0x20) {
  36. lcd->curcol = val & 0x1f;
  37. lcd->just_moved = true;
  38. } else if (val & 0x18) {
  39. // stuff we don't emulate
  40. } else if (val & 0x04) {
  41. lcd->incmode = val & 0x03;
  42. } else if (val & 0x02) {
  43. lcd->enabled = val & 0x01;
  44. } else {
  45. lcd->has8bitmode = val;
  46. }
  47. }
  48. // Advance current position according to current incmode
  49. static void _advance(T6A04 *lcd)
  50. {
  51. uint8_t maxY = lcd->has8bitmode ? 14 : 19;
  52. switch (lcd->incmode) {
  53. case T6A04_XDEC:
  54. lcd->currow = (lcd->currow-1) & 0x3f;
  55. break;
  56. case T6A04_XINC:
  57. lcd->currow = (lcd->currow+1) & 0x3f;
  58. break;
  59. case T6A04_YDEC:
  60. if (lcd->curcol == 0) {
  61. lcd->curcol = maxY;
  62. } else {
  63. lcd->curcol--;
  64. }
  65. break;
  66. case T6A04_YINC:
  67. if (lcd->curcol < maxY) {
  68. lcd->curcol++;
  69. } else {
  70. lcd->curcol = 0;
  71. }
  72. break;
  73. }
  74. }
  75. uint8_t t6a04_data_rd(T6A04 *lcd)
  76. {
  77. uint8_t res;
  78. if (lcd->just_moved) {
  79. // After a move command, the first read op is a noop.
  80. lcd->just_moved = false;
  81. return 0;
  82. }
  83. if (lcd->has8bitmode) {
  84. int pos = lcd->currow * T6A04_ROWSIZE + lcd->curcol;
  85. res = lcd->ram[pos];
  86. } else {
  87. // 6bit mode is a bit more complicated because the 6-bit number often
  88. // spans two bytes. We manage this by loading two bytes into a uint16_t
  89. // and then shift it right properly.
  90. // bitpos represents the leftmost bit of our 6bit number.
  91. int bitpos = lcd->curcol * 6;
  92. // offset represents the shift right we need to perform from the two
  93. // bytes following bitpos/8 so that we can have our number with a 6-bit
  94. // mask.
  95. // Example, col 3 has a bitpos of 18, which means that it loads bytes 2
  96. // and 3. Its bits would be in bit pos 14:8, which means it has an
  97. // offset of 8. There is always an offset and its always in the 3-10
  98. // range
  99. int offset = 10 - (bitpos % 8); // 10 is for 16bit - 6bit
  100. int pos = (lcd->currow * T6A04_ROWSIZE) + (bitpos / 8);
  101. uint16_t word = lcd->ram[pos] << 8;
  102. word |= lcd->ram[pos+1];
  103. res = (word >> offset) & 0x3f;
  104. }
  105. _advance(lcd);
  106. return res;
  107. }
  108. void t6a04_data_wr(T6A04 *lcd, uint8_t val)
  109. {
  110. lcd->just_moved = false;
  111. if (lcd->has8bitmode) {
  112. int pos = lcd->currow * T6A04_ROWSIZE + lcd->curcol;
  113. lcd->ram[pos] = val;
  114. } else {
  115. // See comments in t6a04_data_rd().
  116. int bitpos = lcd->curcol * 6;
  117. int offset = 10 - (bitpos % 8);
  118. int pos = (lcd->currow * T6A04_ROWSIZE) + (bitpos / 8);
  119. uint16_t word = lcd->ram[pos] << 8;
  120. word |= lcd->ram[pos+1];
  121. // word contains our current ram value. Let's fit val in this.
  122. word &= ~(0x003f << offset);
  123. word |= val << offset;
  124. lcd->ram[pos] = word >> 8;
  125. lcd->ram[pos+1] = word & 0xff;
  126. }
  127. _advance(lcd);
  128. }
  129. bool t6a04_pixel(T6A04 *lcd, uint8_t y, uint8_t x)
  130. {
  131. x = (x + lcd->offset) & 0x3f;
  132. uint8_t val = lcd->ram[x * T6A04_ROWSIZE + (y / 8)];
  133. return (val >> (7 - (y % 8))) & 1;
  134. }