1 /* 2 * Write to display memory. 3 * 4 * Copyright (C) 2017 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <stdint.h> 21 #include "mips.h" 22 #include "vga.h" 23 24 /* The font base and limit are locations containing the first and last codes. */ 25 26 extern uint8_t fontbase, fontlimit; 27 28 /* The font character data is a list of bitmap bytes. */ 29 30 extern uint8_t fontchars; 31 static uint8_t *fontdata = &fontchars; 32 33 /* 34 The font table is a list of byte-resolution indexes to be combined with the font 35 character data list address. 36 */ 37 38 extern uint32_t fonttable; 39 static uint32_t *fontoffsets = &fonttable; 40 41 42 43 /* Wrap addresses around at the end of the screen area. */ 44 45 uint32_t *wrap_address(uint32_t *target) 46 { 47 if (target > (uint32_t *) SCREEN_LIMIT_KSEG0) 48 return target - SCREEN_SIZE / 4; 49 else 50 return target; 51 } 52 53 /* Framebuffer initialisation using image data. */ 54 55 void init_framebuffer(uint32_t *data) 56 { 57 uint32_t *addr = (uint32_t *) SCREEN_BASE_KSEG0; 58 uint16_t x, y; 59 60 for (y = 0; y < LINE_COUNT; y++) 61 { 62 for (x = 0; x < LINE_LENGTH; x += 4) 63 { 64 *addr = *data; 65 addr++; 66 data++; 67 } 68 } 69 } 70 71 /* Framebuffer initialisation using a test pattern. */ 72 73 void init_framebuffer_with_pattern() 74 { 75 uint32_t *addr = (uint32_t *) SCREEN_BASE_KSEG0; 76 uint32_t base, value; 77 uint16_t x, y; 78 uint8_t row, offset; 79 80 /* For each line in the screen... */ 81 82 for (y = 0; y < LINE_COUNT; y++) 83 { 84 /* 85 Start each line with a base value. 86 Each byte: 00bbbb00 87 */ 88 89 row = y / 16; 90 base = (row << 26) | (row << 18) | (row << 10) | (row << 2); 91 92 /* 93 Set the intensity bit on every other palette row. 94 Each byte: i0bbbb00 95 */ 96 97 if (row % 2) base |= 0x80808080; 98 99 /* For each word in the line... */ 100 101 for (x = 0; x < LINE_LENGTH; x += 4) 102 { 103 /* 104 Combine the base value with the offset. 105 Each byte: i0bbbboo 106 */ 107 108 offset = x / 20; 109 value = base | (offset << 24) | (offset << 16) | (offset << 8) | offset; 110 111 /* Store the value. */ 112 113 *addr = value; 114 115 /* Access the next word. */ 116 117 addr++; 118 } 119 } 120 } 121 122 /* Font-related routines. */ 123 124 uint8_t *find_char(uint8_t code) 125 { 126 return &fontdata[fontoffsets[code - fontbase]]; 127 } 128 129 uint32_t rowdata_to_bitmap(uint8_t rowdata, uint8_t mask, uint8_t mask_limit) 130 { 131 uint32_t output = 0; 132 133 while (mask != mask_limit) 134 { 135 output = output >> 8; 136 if (rowdata & mask) 137 output |= 0xff000000; 138 mask = mask >> 1; 139 } 140 141 return output; 142 } 143 144 void blit_char(uint8_t code, uint32_t *target) 145 { 146 /* Get the source address of the character data. */ 147 148 uint8_t *source = find_char(code); 149 150 /* Get the limit of the character data. */ 151 152 uint8_t *limit = find_char(code + 1); 153 uint8_t rowdata; 154 155 /* 156 Read each byte of the character data, representing a row of bitmap 157 cells. 158 */ 159 160 while (source < limit) 161 { 162 rowdata = *source; 163 164 /* 165 Write two consecutive words, one for the upper four bits of the 166 data, one for the lower four bits of the data. 167 168 For each bit, produce an "on" or "off" byte for the bitmap cell. 169 */ 170 171 *target = rowdata_to_bitmap(rowdata, 0x80, 0x08); 172 *(wrap_address(target + 1)) = rowdata_to_bitmap(rowdata, 0x08, 0x00); 173 174 /* Move on to the next line. The arithmetic employs words. */ 175 176 target = wrap_address(target + LINE_LENGTH / 4); 177 178 /* Move on to the next data byte. */ 179 180 source++; 181 } 182 } 183 184 uint32_t *char_address(uint32_t *base, uint8_t x, uint8_t y) 185 { 186 return wrap_address(base + (x * 2) + (y * LINE_LENGTH / 4)); 187 } 188 189 void blit_string(uint8_t *source, uint32_t *target) 190 { 191 uint8_t c; 192 193 /* Read byte values until a zero is found. */ 194 195 while ((c = *source) != 0) 196 { 197 blit_char(c, target); 198 source++; 199 200 /* Move across eight pixels (two words). */ 201 202 target = wrap_address(target + 2); 203 } 204 }