1.1 --- a/lib/vga_display.c Tue Nov 13 00:02:15 2018 +0100
1.2 +++ b/lib/vga_display.c Tue Nov 13 00:05:51 2018 +0100
1.3 @@ -24,7 +24,7 @@
1.4
1.5 /* Display state. */
1.6
1.7 -VGA_Display(vga_display);
1.8 +VGA_Display(vga_display, 2);
1.9
1.10 /* Pixel data. */
1.11
1.12 @@ -40,12 +40,12 @@
1.13 {
1.14 /* Display parameters. */
1.15
1.16 - vga_display.display_config = display_config;
1.17 vga_display.line_channels = line_channels;
1.18
1.19 /* Initial state. */
1.20
1.21 vga_display.state_handler = vbp_active;
1.22 + vga_display.scanline = 0;
1.23 vga_display.line = 0;
1.24
1.25 /* Configure a general display timer to start line data transfer and for the
1.26 @@ -58,9 +58,23 @@
1.27
1.28 vga_display.transfer_int_num = transfer_int_num;
1.29
1.30 - /* Update the addresses used for the display. */
1.31 + /* Configure a single window. */
1.32 +
1.33 + vga_display.window_end[0] = display_config->line_count;
1.34 + vga_display.windows = 1;
1.35 +
1.36 + /* Define the line length and count from this window. */
1.37
1.38 - vga_set_frame(display_config);
1.39 + vga_display.line_length = display_config->line_length;
1.40 + vga_display.line_count = display_config->line_count;
1.41 +
1.42 + /* Update the addresses used for the first window of the display. */
1.43 +
1.44 + vga_set_frame(display_config, 0);
1.45 +
1.46 + /* Compute display properties. */
1.47 +
1.48 + vga_update_properties();
1.49 }
1.50
1.51 /* Initialise a separate transfer timer if different from the general display
1.52 @@ -99,6 +113,13 @@
1.53 timer_on(transfer_timer);
1.54 }
1.55
1.56 +/* Update computed properties. */
1.57 +
1.58 +void vga_update_properties(void)
1.59 +{
1.60 + vga_display.line_multiplier = vga_display.scanlines / vga_display.line_count;
1.61 +}
1.62 +
1.63
1.64
1.65 /* Configure the transfer of pixel data. */
1.66 @@ -246,15 +267,42 @@
1.67
1.68
1.69
1.70 +/* Initialise display window details. */
1.71 +
1.72 +void vga_add_window(display_config_t *display_config)
1.73 +{
1.74 + if (vga_display.windows >= vga_display.max_windows)
1.75 + return;
1.76 +
1.77 + /* Set the end of the window. */
1.78 +
1.79 + vga_display.window_end[vga_display.windows] =
1.80 + vga_display.window_end[vga_display.windows - 1] +
1.81 + display_config->line_count;
1.82 +
1.83 + /* Add the window height to the display height. */
1.84 +
1.85 + vga_display.line_count += display_config->line_count;
1.86 +
1.87 + /* Add the window. */
1.88 +
1.89 + vga_set_frame(display_config, vga_display.windows);
1.90 + vga_display.windows++;
1.91 +
1.92 + /* Compute display properties. */
1.93 +
1.94 + vga_update_properties();
1.95 +}
1.96 +
1.97 /* Update the display addresses from the general display configuration. */
1.98
1.99 -void vga_set_frame(display_config_t *display_config)
1.100 +void vga_set_frame(display_config_t *display_config, int window)
1.101 {
1.102 vga_wait_visible();
1.103
1.104 - vga_display.screen_start = display_config->screen_start;
1.105 - vga_display.screen_limit = display_config->screen_limit;
1.106 - vga_display.screen_size = display_config->screen_size;
1.107 + vga_display.screen_start[window] = display_config->screen_start;
1.108 + vga_display.screen_limit[window] = display_config->screen_limit;
1.109 + vga_display.screen_size[window] = display_config->screen_size;
1.110 }
1.111
1.112 /* Wait for the visible region to be completed. */
1.113 @@ -302,7 +350,7 @@
1.114
1.115 void vga_hsync_interrupt_handler(void)
1.116 {
1.117 - vga_display.line += 1;
1.118 + vga_display.scanline += 1;
1.119 vga_display.state_handler();
1.120 }
1.121
1.122 @@ -311,7 +359,6 @@
1.123
1.124 void vga_transfer_interrupt_handler(void)
1.125 {
1.126 - display_config_t *cfg = vga_display.display_config;
1.127 uint8_t *current, *end, *output;
1.128
1.129 if (vga_display.state_handler != visible_active)
1.130 @@ -320,7 +367,7 @@
1.131 /* Generate the pixel signal. */
1.132
1.133 output = (uint8_t *) vga_display.output;
1.134 - end = vga_display.linedata + cfg->line_length;
1.135 + end = vga_display.linedata + vga_display.line_length;
1.136
1.137 /* This is potentially not as efficient as loading words and shifting bytes
1.138 but it appears difficult to implement that approach without experiencing
1.139 @@ -340,16 +387,21 @@
1.140
1.141 void vbp_active(void)
1.142 {
1.143 - if (vga_display.line < vga_display.visible_start)
1.144 + if (vga_display.scanline < vga_display.visible_start)
1.145 return;
1.146
1.147 /* Enter the visible region. */
1.148
1.149 vga_display.state_handler = visible_active;
1.150
1.151 + /* Prepare to show the first window. */
1.152 +
1.153 + vga_display.window = 0;
1.154 + vga_display.line = 0;
1.155 +
1.156 /* Set the line address. */
1.157
1.158 - vga_display.linedata = vga_display.screen_start;
1.159 + vga_display.linedata = vga_display.screen_start[0];
1.160
1.161 if (vga_display.line_channels)
1.162 start_visible();
1.163 @@ -359,18 +411,35 @@
1.164
1.165 void visible_active(void)
1.166 {
1.167 - display_config_t *cfg = vga_display.display_config;
1.168 -
1.169 - if (vga_display.line < vga_display.vfp_start)
1.170 + if (vga_display.scanline < vga_display.vfp_start)
1.171 {
1.172 /* Update the line address and handle wraparound. */
1.173
1.174 - if (!(vga_display.line % cfg->line_multiplier))
1.175 + if (!(vga_display.scanline % vga_display.line_multiplier))
1.176 {
1.177 - vga_display.linedata += cfg->line_length;
1.178 + vga_display.line += 1;
1.179 +
1.180 + /* Move to the next window if the end has been reached. */
1.181 +
1.182 + if (vga_display.line == vga_display.window_end[vga_display.window])
1.183 + {
1.184 + vga_display.window++;
1.185
1.186 - if (vga_display.linedata >= vga_display.screen_limit)
1.187 - vga_display.linedata -= vga_display.screen_size;
1.188 + if (vga_display.window == vga_display.windows)
1.189 + {
1.190 + vga_display.window = 0;
1.191 + vga_display.line = 0;
1.192 + }
1.193 +
1.194 + vga_display.linedata = vga_display.screen_start[vga_display.window];
1.195 + }
1.196 + else
1.197 + {
1.198 + vga_display.linedata += vga_display.line_length;
1.199 +
1.200 + if (vga_display.linedata >= vga_display.screen_limit[vga_display.window])
1.201 + vga_display.linedata -= vga_display.screen_size[vga_display.window];
1.202 + }
1.203 }
1.204
1.205 if (vga_display.line_channels)
1.206 @@ -392,7 +461,7 @@
1.207
1.208 void vfp_active(void)
1.209 {
1.210 - if (vga_display.line < vga_display.vsync_start)
1.211 + if (vga_display.scanline < vga_display.vsync_start)
1.212 return;
1.213
1.214 /* Enter the vertical sync region. */
1.215 @@ -408,12 +477,12 @@
1.216
1.217 void vsync_active(void)
1.218 {
1.219 - if (vga_display.line < vga_display.vsync_end)
1.220 + if (vga_display.scanline < vga_display.vsync_end)
1.221 return;
1.222
1.223 /* Start again at the top of the display. */
1.224
1.225 - vga_display.line = 0;
1.226 + vga_display.scanline = 0;
1.227 vga_display.state_handler = vbp_active;
1.228
1.229 /* Bring vsync high when the next line starts. */
1.230 @@ -436,7 +505,7 @@
1.231 void update_visible(void)
1.232 {
1.233 uint32_t transfer_start = (uint32_t) vga_display.linedata;
1.234 - uint32_t transfer_length = vga_display.display_config->line_length /
1.235 + uint32_t transfer_length = vga_display.line_length /
1.236 vga_display.line_channels;
1.237
1.238 /* Determine whether an initiating channel is used. */