# HG changeset patch # User Paul Boddie # Date 1541278060 -3600 # Node ID 9ef06df79194663a7f73c8095e79199986c54f39 # Parent 51cbfbb4c17e00d139836f07d39cd24fb9c9c792 Introduced initial support for multiple display frames. diff -r 51cbfbb4c17e -r 9ef06df79194 examples/vga-cpu/vga.h --- a/examples/vga-cpu/vga.h Sat Nov 03 16:42:17 2018 +0100 +++ b/examples/vga-cpu/vga.h Sat Nov 03 21:47:40 2018 +0100 @@ -23,8 +23,8 @@ #include "vga_common.h" #define LINE_LENGTH 160 /* pixels */ -#define LINE_COUNT 256 /* distinct display lines */ -#define LINE_MULTIPLIER (SCANLINES / LINE_COUNT) +#define LINE_COUNT 256 /* display lines per frame */ +#define FRAME_COUNT 1 /* double-buffered display */ /* 24MHz cycle measurements. */ @@ -37,6 +37,12 @@ #define SCREEN_SIZE (LINE_LENGTH * LINE_COUNT) +/* A frame has an entire screen plus one line to allow horizontal scrolling, + since a horizontal scroll offset causes the final transfer line to exceed the + screen limit. */ + +#define FRAME_SIZE (SCREEN_SIZE + LINE_COUNT) + /* Transfer and pixel allocation properties. */ #define TRANSFER_CELL_SIZE LINE_LENGTH diff -r 51cbfbb4c17e -r 9ef06df79194 examples/vga-dual/vga.h --- a/examples/vga-dual/vga.h Sat Nov 03 16:42:17 2018 +0100 +++ b/examples/vga-dual/vga.h Sat Nov 03 21:47:40 2018 +0100 @@ -23,8 +23,8 @@ #include "vga_common.h" #define LINE_LENGTH 160 /* pixels */ -#define LINE_COUNT 256 /* distinct display lines */ -#define LINE_MULTIPLIER (SCANLINES / LINE_COUNT) +#define LINE_COUNT 256 /* display lines per frame */ +#define FRAME_COUNT 1 /* double-buffered display */ /* 24MHz cycle measurements. */ @@ -37,6 +37,12 @@ #define SCREEN_SIZE (LINE_LENGTH * LINE_COUNT) +/* A frame has an entire screen plus one line to allow horizontal scrolling, + since a horizontal scroll offset causes the final transfer line to exceed the + screen limit. */ + +#define FRAME_SIZE (SCREEN_SIZE + LINE_COUNT) + /* Transfer and pixel allocation properties. */ #define TRANSFER_CELL_SIZE (LINE_LENGTH / 2) diff -r 51cbfbb4c17e -r 9ef06df79194 examples/vga-pmp/vga.h --- a/examples/vga-pmp/vga.h Sat Nov 03 16:42:17 2018 +0100 +++ b/examples/vga-pmp/vga.h Sat Nov 03 21:47:40 2018 +0100 @@ -23,8 +23,8 @@ #include "vga_common.h" #define LINE_LENGTH 160 /* pixels */ -#define LINE_COUNT 256 /* distinct display lines */ -#define LINE_MULTIPLIER (SCANLINES / LINE_COUNT) +#define LINE_COUNT 256 /* display lines per frame */ +#define FRAME_COUNT 1 /* double-buffered display */ /* 48MHz cycle measurements. */ @@ -37,6 +37,12 @@ #define SCREEN_SIZE (LINE_LENGTH * LINE_COUNT) +/* A frame has an entire screen plus one line to allow horizontal scrolling, + since a horizontal scroll offset causes the final transfer line to exceed the + screen limit. */ + +#define FRAME_SIZE (SCREEN_SIZE + LINE_COUNT) + /* Transfer and pixel allocation properties. */ #define TRANSFER_CELL_SIZE LINE_LENGTH diff -r 51cbfbb4c17e -r 9ef06df79194 examples/vga-timer/vga.h --- a/examples/vga-timer/vga.h Sat Nov 03 16:42:17 2018 +0100 +++ b/examples/vga-timer/vga.h Sat Nov 03 21:47:40 2018 +0100 @@ -24,7 +24,7 @@ #define LINE_LENGTH 92 /* pixels */ #define LINE_COUNT 128 /* distinct display lines */ -#define LINE_MULTIPLIER (SCANLINES / LINE_COUNT) +#define FRAME_COUNT 1 /* double-buffered display */ /* 24MHz cycle measurements. */ @@ -37,6 +37,12 @@ #define SCREEN_SIZE (LINE_LENGTH * LINE_COUNT) +/* A frame has an entire screen plus one line to allow horizontal scrolling, + since a horizontal scroll offset causes the final transfer line to exceed the + screen limit. */ + +#define FRAME_SIZE (SCREEN_SIZE + LINE_COUNT) + /* Transfer and pixel allocation properties. */ #define TRANSFER_CELL_SIZE 1 diff -r 51cbfbb4c17e -r 9ef06df79194 examples/vga/main.c --- a/examples/vga/main.c Sat Nov 03 16:42:17 2018 +0100 +++ b/examples/vga/main.c Sat Nov 03 21:47:40 2018 +0100 @@ -81,6 +81,12 @@ +/* Framebuffer memory. */ + +static uint8_t framebuffer[FRAME_SIZE * FRAME_COUNT]; + + + /* Bundled image and font data. */ extern uint8_t screendata[]; @@ -309,6 +315,13 @@ pm_on(0); #endif + uart_init(1, FPB, 115200); + uart_on(1); + + /* Initialise memory for a double-buffered display. */ + + init_display(&display_config, framebuffer, LINE_LENGTH, LINE_COUNT, FRAME_COUNT); + /* Initialise VGA output with one or two line channels, configuring a line timer and any transfer timer, with an initiating channel being introduced if a transfer timer is specified. */ @@ -321,16 +334,13 @@ vga_configure_transfer(VGA_OUTPUT); vga_configure_sync(1, 2); - uart_init(1, FPB, 115200); - uart_on(1); - interrupts_on(); /* Plot the image centred on the screen. */ copy_display(&display_config, screendata, screendata_width, screendata_height, - (LINE_LENGTH - screendata_width) / 2, - (LINE_COUNT - screendata_height) / 2, -1, 1); + (display_config.line_length - screendata_width) / 2, + (display_config.line_count - screendata_height) / 2, -1, 1); /* Write a sequence of characters. */ @@ -338,7 +348,7 @@ /* Move a sprite around on the screen with a delay between each movement. */ - animate(1 << 21); + animate(1 << 18); } diff -r 51cbfbb4c17e -r 9ef06df79194 examples/vga/vga.h --- a/examples/vga/vga.h Sat Nov 03 16:42:17 2018 +0100 +++ b/examples/vga/vga.h Sat Nov 03 21:47:40 2018 +0100 @@ -23,8 +23,8 @@ #include "vga_common.h" #define LINE_LENGTH 160 /* pixels */ -#define LINE_COUNT 256 /* distinct display lines */ -#define LINE_MULTIPLIER (SCANLINES / LINE_COUNT) +#define LINE_COUNT 256 /* display lines per frame */ +#define FRAME_COUNT 1 /* double-buffered display */ /* 24MHz cycle measurements. */ @@ -37,6 +37,12 @@ #define SCREEN_SIZE (LINE_LENGTH * LINE_COUNT) +/* A frame has an entire screen plus one line to allow horizontal scrolling, + since a horizontal scroll offset causes the final transfer line to exceed the + screen limit. */ + +#define FRAME_SIZE (SCREEN_SIZE + LINE_COUNT) + /* Transfer and pixel allocation properties. */ #define TRANSFER_CELL_SIZE LINE_LENGTH diff -r 51cbfbb4c17e -r 9ef06df79194 include/display.h --- a/include/display.h Sat Nov 03 16:42:17 2018 +0100 +++ b/include/display.h Sat Nov 03 21:47:40 2018 +0100 @@ -28,19 +28,43 @@ typedef struct { - /* Framebuffer pointer and size. */ + /* Framebuffer address, potentially referencing many frames. */ uint8_t *framebuffer; - uint32_t screen_size; + + /* The total number of lines in the framebuffer including spare lines to + support horizontal scrolling. */ + + uint32_t total_lines; + + /* The screen dimensions and size (derived from the dimensions). */ + uint32_t line_length, line_count; /* width, height */ + uint32_t screen_size; /* = width * height */ + + /* The current frame, number of frames, and the maximum number supported. */ + + int frame, frames, max_frames; - /* Screen start/top and limit pointers. */ + /* The fixed start address of the current frame. */ + + uint8_t *frame_start; /* = framebuffer + (frame_size * frame) */ + + /* The floating screen start/top pointer. */ + + uint8_t *screen_start; /* >= frame_start; < screen_limit */ - uint8_t *screen_start, *screen_limit; + /* The fixed end address of the current frame. */ + + uint8_t *screen_limit; /* = frame_start + screen_size */ + + /* Number of scanlines on the display. */ + + uint32_t scanlines; /* Number of scanlines per display line. */ - int line_multiplier; + int line_multiplier; /* = scanlines / line_count */ /* Number of consecutive pixels provided by a framebuffer region. */ @@ -62,6 +86,19 @@ +/* Configuration functions. */ + +void init_display(display_config_t *cfg, uint8_t *framebuffer, + uint32_t line_length, uint32_t line_count, int frames); + +void init_display_properties(display_config_t *cfg, uint32_t offset); + +void select_frame(display_config_t *cfg, int frame, uint32_t offset); + +void set_frames(display_config_t *cfg, int frames); + +uint32_t get_start_offset(display_config_t *cfg); + /* Access functions. */ int get_position(display_config_t *cfg, int x); diff -r 51cbfbb4c17e -r 9ef06df79194 include/display_config.h --- a/include/display_config.h Sat Nov 03 16:42:17 2018 +0100 +++ b/include/display_config.h Sat Nov 03 21:47:40 2018 +0100 @@ -24,30 +24,13 @@ #include "display.h" #include "vga.h" -/* Reserve enough space for a screen, plus one line to allow horizontal - scrolling, since a horizontal scroll offset causes the final transfer line to - exceed the screen limit. */ - -uint8_t framebuffer[SCREEN_SIZE + LINE_LENGTH]; - - - /* Define a structure containing the display parameters. */ display_config_t display_config = { - /* Set the reserved memory as the framebuffer. */ - - .framebuffer = framebuffer, - .screen_start = framebuffer, - .screen_limit = framebuffer + SCREEN_SIZE, + /* Define display properties. */ - /* Define screen dimensions and properties. */ - - .screen_size = SCREEN_SIZE, - .line_length = LINE_LENGTH, - .line_count = LINE_COUNT, - .line_multiplier = LINE_MULTIPLIER, + .scanlines = SCANLINES, .cell_size = CELL_SIZE, .transfer_cell_size = TRANSFER_CELL_SIZE, diff -r 51cbfbb4c17e -r 9ef06df79194 lib/display.c --- a/lib/display.c Sat Nov 03 16:42:17 2018 +0100 +++ b/lib/display.c Sat Nov 03 21:47:40 2018 +0100 @@ -21,6 +21,99 @@ +/* Initialise a display configuration. */ + +void init_display(display_config_t *cfg, uint8_t *framebuffer, + uint32_t line_length, uint32_t line_count, int frames) +{ + /* Framebuffer address. */ + + cfg->framebuffer = framebuffer; + + /* Frame allocation limits. */ + + cfg->total_lines = (line_count + 1) * frames; + cfg->max_frames = frames; + + /* Screen size and dimensions. */ + + cfg->screen_size = line_length * line_count; + cfg->line_length = line_length; + cfg->line_count = line_count; + + /* Set the number of frames and the current frame. */ + + cfg->frames = frames; + cfg->frame = 0; + + init_display_properties(cfg, 0); +} + +/* Initialise the display constraints. */ + +void init_display_properties(display_config_t *cfg, uint32_t offset) +{ + /* Fixed address of the frame. */ + + cfg->frame_start = cfg->framebuffer + + (cfg->screen_size + cfg->line_length) * cfg->frame; + + /* Floating address of the screen contents. */ + + cfg->screen_start = cfg->frame_start + offset; + + /* Fixed limit of the frame. */ + + cfg->screen_limit = cfg->frame_start + cfg->screen_size; + + /* Recalculate the line multiplier. */ + + cfg->line_multiplier = cfg->scanlines / cfg->line_count; +} + +/* Set the number of frames in the framebuffer memory. */ + +void set_frames(display_config_t *cfg, int frames) +{ + /* Recalculate the number of lines. */ + + cfg->line_count = (cfg->total_lines - cfg->max_frames) / frames; + + /* Recalculate the screen size. */ + + cfg->screen_size = cfg->line_count * cfg->line_length; + + /* Set the number of frames and the current frame. */ + + cfg->frames = frames; + cfg->frame = 0; + + init_display_properties(cfg, 0); +} + +/* Select a frame in the framebuffer. */ + +void select_frame(display_config_t *cfg, int frame, uint32_t offset) +{ + if ((frame < 0) || (frame >= cfg->frames)) + return; + + /* Update the frame details. */ + + cfg->frame = frame; + + /* Set the screen start offset when switching frames. */ + + init_display_properties(cfg, offset); +} + +/* Return the screen start offset. */ + +uint32_t get_start_offset(display_config_t *cfg) +{ + return cfg->screen_start - cfg->frame_start; +} + /* Return the line data position for the given pixel. */ int get_position(display_config_t *cfg, int x) @@ -125,13 +218,13 @@ /* Wrap around the start of the framebuffer to the end. */ - if (start < cfg->framebuffer) - start = cfg->screen_limit - (cfg->screen_limit - start) % cfg->screen_size; + if (start < cfg->frame_start) + start = cfg->screen_limit - (cfg->frame_start - start) % cfg->screen_size; /* Wrap around the end of the framebuffer to the start. */ else if (start >= cfg->screen_limit) - start = cfg->framebuffer + (start - cfg->framebuffer) % cfg->screen_size; + start = cfg->frame_start + (start - cfg->screen_limit) % cfg->screen_size; cfg->screen_start = start; }