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