1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/examples/vga-cpu/Makefile Fri Nov 02 02:15:09 2018 +0100
1.3 @@ -0,0 +1,38 @@
1.4 +# Makefile - Build the PIC32 deployment payload
1.5 +#
1.6 +# Copyright (C) 2015, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
1.7 +# Copyright (C) Xiangfu Liu <xiangfu@sharism.cc>
1.8 +#
1.9 +# This program is free software: you can redistribute it and/or modify
1.10 +# it under the terms of the GNU General Public License as published by
1.11 +# the Free Software Foundation, either version 3 of the License, or
1.12 +# (at your option) any later version.
1.13 +#
1.14 +# This program is distributed in the hope that it will be useful,
1.15 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 +# GNU General Public License for more details.
1.18 +#
1.19 +# You should have received a copy of the GNU General Public License
1.20 +# along with this program. If not, see <http://www.gnu.org/licenses/>.
1.21 +
1.22 +include ../../mk/common.mk
1.23 +
1.24 +TARGET = vga.elf
1.25 +DUMP = $(TARGET:.elf=.dump)
1.26 +MAP = $(TARGET:.elf=.map)
1.27 +
1.28 +HEX = $(TARGET:.elf=.hex)
1.29 +SREC = $(TARGET:.elf=.srec)
1.30 +
1.31 +# Ordering of objects is important and cannot be left to replacement rules.
1.32 +
1.33 +SRC = $(START_SRC) main.c $(COMMON_SRC) $(DISPLAY_CPU_SRC) screendata.S sprite.S font.S
1.34 +OBJ = $(START_OBJ) main.o $(COMMON_OBJ) $(DISPLAY_CPU_OBJ) screendata.o sprite.o font.o
1.35 +
1.36 +# Application-specific adjustments.
1.37 +# See: examples/vga/Makefile
1.38 +
1.39 +CFLAGS += -DTRANSFER_CPU -I../vga
1.40 +
1.41 +include ../../mk/rules.mk
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/examples/vga-cpu/README.txt Fri Nov 02 02:15:09 2018 +0100
2.3 @@ -0,0 +1,118 @@
2.4 +Introduction
2.5 +------------
2.6 +
2.7 +This example demonstrates the generation of an analogue VGA signal from a
2.8 +PIC32 microcontroller using general output pins. Instead of using DMA, which
2.9 +was the focus of the VGAPIC32 project and is a central feature of the
2.10 +approaches demonstrated by other examples (vga, vga-dual, vga-pmp, vga-timer),
2.11 +here the CPU is given the task of transferring pixel data to the output pins.
2.12 +
2.13 +Instead of a timer interrupt condition initiating DMA transfers, the interrupt
2.14 +is handled and a routine invoked to issue the necessary load and store
2.15 +instructions in a loop. Otherwise, the use of the timer to generate sync
2.16 +pulses is as in the other examples and the general display state machine is
2.17 +largely the same.
2.18 +
2.19 +The resulting picture is more pleasing than that produced by most of the DMA
2.20 +examples in that the display pixels have consistent widths. Moreover, the
2.21 +pixels are also narrower than those produced by the vga-timer example. It is
2.22 +possible to generate a display with something approaching 200 pixels
2.23 +horizontally, with 160 pixels being demonstrated.
2.24 +
2.25 +However, the CPU now spends a lot of time occupied in an interrupt request
2.26 +handler generating pixels. This seems less elegant than using DMA, but in
2.27 +practice, the CPU may be effectively stalled where DMA transfers dominate
2.28 +access to the RAM. Even if, in such situations, the CPU may be able to access
2.29 +flash memory to load instructions, programs typically end up accessing RAM at
2.30 +some point, and this would effectively limit the concurrency within the
2.31 +system.
2.32 +
2.33 +One potential advantage of this approach is in the flexibility that might be
2.34 +achieved by manipulating the pixel data. With DMA, data is transferred as it
2.35 +is found and is generally not transformed (although there are some features in
2.36 +the PIC32 DMA controller for certain kinds of data), whereas we might envisage
2.37 +supporting display modes employing fewer bits for the output signal, reducing
2.38 +the number of colours but also the size of the framebuffer.
2.39 +
2.40 +Hardware Details
2.41 +================
2.42 +
2.43 +The pin usage of this solution is documented below.
2.44 +
2.45 +PIC32MX270F256B-50I/SP Pin Assignments
2.46 +--------------------------------------
2.47 +
2.48 +MCLR# 1 \/ 28
2.49 +HSYNC/OC1/RA0 2 27
2.50 +VSYNC/OC2/RA1 3 26 RB15/U1TX
2.51 + D0/RB0 4 25 RB14
2.52 + D1/RB1 5 24 RB13/U1RX
2.53 + D2/RB2 6 23
2.54 + D3/RB3 7 22 RB11/PGEC2
2.55 + 8 21 RB10/PGEC3
2.56 + RA2 9 20
2.57 + RA3 10 19
2.58 + D4/RB4 11 18 RB9
2.59 + 12 17 RB8
2.60 + 13 16 RB7/D7
2.61 + D5/RB5 14 15
2.62 +
2.63 +Note that RB6 is not available on pin 15 on this device (it is needed for VBUS
2.64 +unlike the MX170 variant).
2.65 +
2.66 +UART Connections
2.67 +----------------
2.68 +
2.69 +UART1 is exposed by the RB13 and RB15 pins.
2.70 +
2.71 +Data Signal Routing
2.72 +-------------------
2.73 +
2.74 +For one bit of intensity, two bits per colour channel:
2.75 +
2.76 +D7 -> 2200R -> I
2.77 +
2.78 +I -> diode -> R
2.79 +I -> diode -> G
2.80 +I -> diode -> B
2.81 +
2.82 +D6 (not connected)
2.83 +
2.84 +D5 -> 470R -> R
2.85 +D4 -> 1000R -> R
2.86 +D3 -> 470R -> G
2.87 +D2 -> 1000R -> G
2.88 +D1 -> 470R -> B
2.89 +D0 -> 1000R -> B
2.90 +
2.91 +HSYNC -> HS
2.92 +VSYNC -> VS
2.93 +
2.94 +Output Socket Pinout
2.95 +--------------------
2.96 +
2.97 + 5 (GND) 4 (NC) 3 (B) 2 (G) 1 (R)
2.98 +
2.99 + 10 (GND) 9 (NC) 8 (GND) 7 (GND) 6 (GND)
2.100 +
2.101 + 15 (NC) 14 (VS) 13 (HS) 12 (NC) 11 (NC)
2.102 +
2.103 +Output Cable Pinout
2.104 +-------------------
2.105 +
2.106 + 1 (R) 2 (G) 3 (B) 4 (NC) 5 (GND)
2.107 +
2.108 + 6 (GND) 7 (GND) 8 (GND) 9 (NC) 10 (GND)
2.109 +
2.110 + 11 (NC) 12 (NC) 13 (HS) 14 (VS) 15 (NC)
2.111 +
2.112 +References
2.113 +----------
2.114 +
2.115 +https://en.wikipedia.org/wiki/VGA_connector
2.116 +
2.117 +http://papilio.cc/index.php?n=Papilio.VGAWing
2.118 +
2.119 +http://lucidscience.com/pro-vga%20video%20generator-2.aspx
2.120 +
2.121 +https://sites.google.com/site/h2obsession/CBM/C128/rgbi-to-vga
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/examples/vga-cpu/devconfig.h Fri Nov 02 02:15:09 2018 +0100
3.3 @@ -0,0 +1,63 @@
3.4 +/*
3.5 + * Device configuration.
3.6 + *
3.7 + * Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk>
3.8 + *
3.9 + * This program is free software: you can redistribute it and/or modify
3.10 + * it under the terms of the GNU General Public License as published by
3.11 + * the Free Software Foundation, either version 3 of the License, or
3.12 + * (at your option) any later version.
3.13 + *
3.14 + * This program is distributed in the hope that it will be useful,
3.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.17 + * GNU General Public License for more details.
3.18 + *
3.19 + * You should have received a copy of the GNU General Public License
3.20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
3.21 + */
3.22 +
3.23 +#ifndef __CONFIG_H__
3.24 +#define __CONFIG_H__
3.25 +
3.26 +#include "pic32.h"
3.27 +
3.28 +/*
3.29 +Set the oscillator to be the FRC oscillator with PLL, with peripheral clock
3.30 +divided by 2 (FPBDIV), and FRCDIV+PLL selected (FNOSC).
3.31 +
3.32 +The watchdog timer (FWDTEN) is also disabled.
3.33 +
3.34 +The secondary oscillator pin (FSOSCEN) is disabled to avoid pin conflicts with
3.35 +RPB4.
3.36 +*/
3.37 +
3.38 +#define DEVCFG1_CONFIG (DEVCFG1_FWDTEN_OFF | DEVCFG1_FPBDIV_2 | \
3.39 + DEVCFG1_OSCIOFNC_OFF | DEVCFG1_FSOSCEN_OFF | \
3.40 + DEVCFG1_FNOSC_FRCDIV_PLL)
3.41 +
3.42 +/*
3.43 +Set the FRC oscillator PLL function with an input division of 2, an output
3.44 +division of 2, a multiplication of 24, yielding a multiplication of 6.
3.45 +
3.46 +The FRC is apparently at 8MHz but enforces input division of 2 to produce a
3.47 +frequency in the acceptable range from 4MHz to 5MHz for the PLL:
3.48 +
3.49 +8MHz / 2 = 4MHz
3.50 +
3.51 +Multiplication and output division should produce a system clock of 48MHz:
3.52 +
3.53 +4MHz * 24 / 2 = 48MHz
3.54 +*/
3.55 +
3.56 +#define DEVCFG2_CONFIG (DEVCFG2_FPLLODIV_2 | DEVCFG2_FPLLMUL_24 | \
3.57 + DEVCFG2_FPLLIDIV_2)
3.58 +
3.59 +/*
3.60 +The peripheral clock frequency (FPB) will be 24MHz given the above DEVCFG1 and
3.61 +DEVCFG2 settings.
3.62 +*/
3.63 +
3.64 +#define FPB 24000000
3.65 +
3.66 +#endif /* __CONFIG_H__ */
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/examples/vga-cpu/font.S Fri Nov 02 02:15:09 2018 +0100
4.3 @@ -0,0 +1,1 @@
4.4 +../../data/font.S
4.5 \ No newline at end of file
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/examples/vga-cpu/main.c Fri Nov 02 02:15:09 2018 +0100
5.3 @@ -0,0 +1,1 @@
5.4 +../vga/main.c
5.5 \ No newline at end of file
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/examples/vga-cpu/screendata.S Fri Nov 02 02:15:09 2018 +0100
6.3 @@ -0,0 +1,1 @@
6.4 +../vga/screendata.S
6.5 \ No newline at end of file
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/examples/vga-cpu/sprite.S Fri Nov 02 02:15:09 2018 +0100
7.3 @@ -0,0 +1,1 @@
7.4 +../vga/sprite.S
7.5 \ No newline at end of file
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/examples/vga-cpu/vga.h Fri Nov 02 02:15:09 2018 +0100
8.3 @@ -0,0 +1,45 @@
8.4 +/*
8.5 + * Generate a VGA signal using a PIC32 microcontroller.
8.6 + *
8.7 + * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
8.8 + *
8.9 + * This program is free software: you can redistribute it and/or modify
8.10 + * it under the terms of the GNU General Public License as published by
8.11 + * the Free Software Foundation, either version 3 of the License, or
8.12 + * (at your option) any later version.
8.13 + *
8.14 + * This program is distributed in the hope that it will be useful,
8.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8.17 + * GNU General Public License for more details.
8.18 + *
8.19 + * You should have received a copy of the GNU General Public License
8.20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
8.21 + */
8.22 +
8.23 +#ifndef __VGA_H__
8.24 +#define __VGA_H__
8.25 +
8.26 +#include "vga_common.h"
8.27 +
8.28 +#define LINE_LENGTH 160 /* pixels */
8.29 +#define LINE_COUNT 256 /* distinct display lines */
8.30 +#define LINE_MULTIPLIER (SCANLINES / LINE_COUNT)
8.31 +
8.32 +/* 24MHz cycle measurements. */
8.33 +
8.34 +#define HFREQ_LIMIT 643
8.35 +#define HSYNC_START 520
8.36 +#define HSYNC_LIMIT 64
8.37 +#define HSYNC_END (HSYNC_START + HSYNC_LIMIT)
8.38 +
8.39 +/* Framebuffer properties. */
8.40 +
8.41 +#define SCREEN_SIZE (LINE_LENGTH * LINE_COUNT)
8.42 +
8.43 +/* Transfer and pixel allocation properties. */
8.44 +
8.45 +#define TRANSFER_CELL_SIZE LINE_LENGTH
8.46 +#define CELL_SIZE LINE_LENGTH
8.47 +
8.48 +#endif /* __VGA_H__ */
9.1 --- a/examples/vga/main.c Fri Nov 02 01:53:03 2018 +0100
9.2 +++ b/examples/vga/main.c Fri Nov 02 02:15:09 2018 +0100
9.3 @@ -30,7 +30,12 @@
9.4 #include "font.h"
9.5 #include "main.h"
9.6 #include "vga.h"
9.7 +
9.8 +#ifndef TRANSFER_CPU
9.9 #include "vga_display.h"
9.10 +#else
9.11 +#include "vga_display_cpu.h"
9.12 +#endif
9.13
9.14
9.15
9.16 @@ -260,7 +265,9 @@
9.17 config_uart();
9.18 lock_config();
9.19
9.20 +#ifndef TRANSFER_CPU
9.21 init_dma();
9.22 +#endif
9.23
9.24 #ifdef PARALLEL_MODE
9.25 init_pm();
9.26 @@ -276,7 +283,11 @@
9.27 timer and any transfer timer, with an initiating channel being introduced
9.28 if a transfer timer is specified. */
9.29
9.30 +#ifndef TRANSFER_CPU
9.31 init_vga_with_timers(&display_config, LINE_CHANNELS, LINE_TIMER, TRANSFER_TIMER);
9.32 +#else
9.33 + init_vga_with_timer(&display_config, LINE_TIMER);
9.34 +#endif
9.35
9.36 /* Configure VGA output transfer to the output register, also configuring
9.37 output compare units for horizontal and vertical sync. */
9.38 @@ -317,6 +328,18 @@
9.39 {
9.40 uint32_t ifs;
9.41
9.42 +#ifdef TRANSFER_CPU
9.43 + /* Check for a timer interrupt condition. */
9.44 +
9.45 + ifs = REG(TIMERIFS) & TIMER_INT_FLAGS(LINE_TIMER, TxIF);
9.46 +
9.47 + if (ifs)
9.48 + {
9.49 + vga_transfer_interrupt_handler();
9.50 + CLR_REG(TIMERIFS, ifs);
9.51 + }
9.52 +#endif
9.53 +
9.54 /* Check for a OC1 interrupt condition. */
9.55
9.56 ifs = REG(OCIFS) & OC_INT_FLAGS(1, OCxIF);
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/include/vga_display_cpu.h Fri Nov 02 02:15:09 2018 +0100
10.3 @@ -0,0 +1,95 @@
10.4 +/*
10.5 + * VGA display-related functions.
10.6 + *
10.7 + * Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk>
10.8 + *
10.9 + * This program is free software: you can redistribute it and/or modify
10.10 + * it under the terms of the GNU General Public License as published by
10.11 + * the Free Software Foundation, either version 3 of the License, or
10.12 + * (at your option) any later version.
10.13 + *
10.14 + * This program is distributed in the hope that it will be useful,
10.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
10.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10.17 + * GNU General Public License for more details.
10.18 + *
10.19 + * You should have received a copy of the GNU General Public License
10.20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
10.21 + */
10.22 +
10.23 +#ifndef __VGA_DISPLAY_CPU_H__
10.24 +#define __VGA_DISPLAY_CPU_H__
10.25 +
10.26 +#include "pic32_c.h"
10.27 +#include "display.h"
10.28 +
10.29 +
10.30 +
10.31 +/* Display configuration type. */
10.32 +
10.33 +typedef struct
10.34 +{
10.35 + /* Current display state handler. */
10.36 +
10.37 + void (*state_handler)();
10.38 +
10.39 + /* Transfer properties. */
10.40 +
10.41 + int line_timer;
10.42 + uint32_t output;
10.43 +
10.44 + /* Horizontal and vertical sync peripherals. */
10.45 +
10.46 + int hsync_unit, vsync_unit;
10.47 +
10.48 + /* Current scanline. */
10.49 +
10.50 + uint32_t line;
10.51 +
10.52 + /* Pointers to pixel lines. */
10.53 +
10.54 + uint8_t *linedata;
10.55 +
10.56 + /* General display configuration. */
10.57 +
10.58 + display_config_t *display_config;
10.59 +
10.60 +} vga_display_t;
10.61 +
10.62 +
10.63 +
10.64 +/* Initialisation. */
10.65 +
10.66 +void init_vga(display_config_t *display_config, int line_timer);
10.67 +
10.68 +void init_vga_with_timer(display_config_t *display_config, int line_timer);
10.69 +
10.70 +void vga_configure_sync(int hsync_unit, int vsync_unit);
10.71 +
10.72 +void vga_configure_transfer(uint32_t output);
10.73 +
10.74 +/* Interrupt handlers. */
10.75 +
10.76 +void vga_interrupt_handler(void);
10.77 +void vga_transfer_interrupt_handler(void);
10.78 +
10.79 +/* Display state handlers. */
10.80 +
10.81 +void vbp_active(void);
10.82 +void visible_active(void);
10.83 +void vfp_active(void);
10.84 +void vsync_active(void);
10.85 +
10.86 +/* Display operations. */
10.87 +
10.88 +void start_visible(void);
10.89 +void update_visible(void);
10.90 +void stop_visible(void);
10.91 +void update_transfers(int enable);
10.92 +
10.93 +/* Vertical sync operations. */
10.94 +
10.95 +void vsync_high(void);
10.96 +void vsync_low(void);
10.97 +
10.98 +#endif /* __VGA_DISPLAY_CPU_H__ */
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/lib/vga_display_cpu.c Fri Nov 02 02:15:09 2018 +0100
11.3 @@ -0,0 +1,242 @@
11.4 +/*
11.5 + * Generate a VGA signal using a PIC32 microcontroller.
11.6 + *
11.7 + * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
11.8 + *
11.9 + * This program is free software: you can redistribute it and/or modify
11.10 + * it under the terms of the GNU General Public License as published by
11.11 + * the Free Software Foundation, either version 3 of the License, or
11.12 + * (at your option) any later version.
11.13 + *
11.14 + * This program is distributed in the hope that it will be useful,
11.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11.17 + * GNU General Public License for more details.
11.18 + *
11.19 + * You should have received a copy of the GNU General Public License
11.20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
11.21 + */
11.22 +
11.23 +#include "pic32_c.h"
11.24 +#include "init.h"
11.25 +#include "vga_display_cpu.h"
11.26 +
11.27 +
11.28 +
11.29 +/* Display state. */
11.30 +
11.31 +vga_display_t vga_display;
11.32 +
11.33 +
11.34 +
11.35 +/* Initialise the state machine. */
11.36 +
11.37 +void init_vga(display_config_t *display_config, int line_timer)
11.38 +{
11.39 + /* Display parameters. */
11.40 +
11.41 + vga_display.display_config = display_config;
11.42 +
11.43 + /* Initial state. */
11.44 +
11.45 + vga_display.state_handler = vbp_active;
11.46 + vga_display.line = 0;
11.47 +
11.48 + /* Configure a general display timer to start line data transfer and for the
11.49 + horizontal sync. */
11.50 +
11.51 + vga_display.line_timer = line_timer;
11.52 +}
11.53 +
11.54 +/* Initialise a separate transfer timer if different from the general display
11.55 + timer. */
11.56 +
11.57 +void init_vga_with_timer(display_config_t *display_config, int line_timer)
11.58 +{
11.59 + /* Initialise the basic properties of the display. */
11.60 +
11.61 + init_vga(display_config, line_timer);
11.62 +
11.63 + /* Configure a line timer for horizontal sync and line data transfers. The
11.64 + interrupt is handled to produce line data and to drive the display state
11.65 + machine. */
11.66 +
11.67 + /* The timer has no prescaling (0). */
11.68 +
11.69 + timer_init(line_timer, 0, display_config->hfreq_limit);
11.70 + timer_init_interrupt(line_timer, 7, 3);
11.71 + timer_on(line_timer);
11.72 +}
11.73 +
11.74 +
11.75 +
11.76 +/* Configure the output port. */
11.77 +
11.78 +void vga_configure_transfer(uint32_t output)
11.79 +{
11.80 + vga_display.output = output;
11.81 +}
11.82 +
11.83 +/* Configure output compare units for horizontal and vertical sync. */
11.84 +
11.85 +void vga_configure_sync(int hsync_unit, int vsync_unit)
11.86 +{
11.87 + /* Record the peripherals in use. */
11.88 +
11.89 + vga_display.hsync_unit = hsync_unit;
11.90 + vga_display.vsync_unit = vsync_unit;
11.91 +
11.92 + /* Horizontal sync. */
11.93 +
11.94 + /* Configure output compare in dual compare (continuous output) mode using
11.95 + the timer as time base. */
11.96 +
11.97 + oc_init(hsync_unit, 0b101, vga_display.line_timer);
11.98 + oc_set_pulse(hsync_unit, vga_display.display_config->hsync_end);
11.99 + oc_set_pulse_end(hsync_unit, vga_display.display_config->hsync_start);
11.100 + oc_init_interrupt(hsync_unit, 7, 3);
11.101 + oc_on(hsync_unit);
11.102 +
11.103 + /* Vertical sync. */
11.104 +
11.105 + /* Configure output compare in single compare (output driven low) mode using
11.106 + the timer as time base. The unit is enabled later. It is only really used
11.107 + to achieve precisely-timed level transitions in hardware. */
11.108 +
11.109 + oc_init(vsync_unit, 0b010, vga_display.line_timer);
11.110 + oc_set_pulse(vsync_unit, 0);
11.111 +}
11.112 +
11.113 +
11.114 +
11.115 +/* Interrupt handlers. */
11.116 +
11.117 +void vga_interrupt_handler(void)
11.118 +{
11.119 + vga_display.line += 1;
11.120 + vga_display.state_handler();
11.121 +}
11.122 +
11.123 +/* Visible region pixel output handler. */
11.124 +
11.125 +void vga_transfer_interrupt_handler(void)
11.126 +{
11.127 + display_config_t *cfg = vga_display.display_config;
11.128 + uint8_t *current, *end, *output;
11.129 +
11.130 + if (vga_display.state_handler != visible_active)
11.131 + return;
11.132 +
11.133 + /* Generate the pixel signal. */
11.134 +
11.135 + output = (uint8_t *) vga_display.output;
11.136 + end = vga_display.linedata + cfg->line_length;
11.137 +
11.138 + /* This is potentially not as efficient as loading words and shifting bytes
11.139 + but it appears difficult to implement that approach without experiencing
11.140 + data load exceptions. */
11.141 +
11.142 + for (current = vga_display.linedata; current < end; current++)
11.143 + REG(output) = *current;
11.144 +
11.145 + /* Reset the signal level. */
11.146 +
11.147 + REG(output) = 0;
11.148 +}
11.149 +
11.150 +
11.151 +
11.152 +/* Vertical back porch region. */
11.153 +
11.154 +void vbp_active(void)
11.155 +{
11.156 + if (vga_display.line < vga_display.display_config->visible_start)
11.157 + return;
11.158 +
11.159 + /* Enter the visible region. */
11.160 +
11.161 + vga_display.state_handler = visible_active;
11.162 +
11.163 + /* Set the line address. */
11.164 +
11.165 + vga_display.linedata = vga_display.display_config->screen_start;
11.166 +}
11.167 +
11.168 +/* Visible region. */
11.169 +
11.170 +void visible_active(void)
11.171 +{
11.172 + display_config_t *cfg = vga_display.display_config;
11.173 +
11.174 + if (vga_display.line < cfg->vfp_start)
11.175 + {
11.176 + /* Update the line address and handle wraparound. */
11.177 +
11.178 + if (!(vga_display.line % cfg->line_multiplier))
11.179 + {
11.180 + vga_display.linedata += cfg->line_length;
11.181 +
11.182 + if (vga_display.linedata >= cfg->screen_limit)
11.183 + vga_display.linedata -= cfg->screen_size;
11.184 + }
11.185 +
11.186 + return;
11.187 + }
11.188 +
11.189 + /* End the visible region. */
11.190 +
11.191 + vga_display.state_handler = vfp_active;
11.192 +}
11.193 +
11.194 +/* Vertical front porch region. */
11.195 +
11.196 +void vfp_active(void)
11.197 +{
11.198 + if (vga_display.line < vga_display.display_config->vsync_start)
11.199 + return;
11.200 +
11.201 + /* Enter the vertical sync region. */
11.202 +
11.203 + vga_display.state_handler = vsync_active;
11.204 +
11.205 + /* Bring vsync low when the next line starts. */
11.206 +
11.207 + vsync_low();
11.208 +}
11.209 +
11.210 +/* Vertical sync region. */
11.211 +
11.212 +void vsync_active(void)
11.213 +{
11.214 + if (vga_display.line < vga_display.display_config->vsync_end)
11.215 + return;
11.216 +
11.217 + /* Start again at the top of the display. */
11.218 +
11.219 + vga_display.line = 0;
11.220 + vga_display.state_handler = vbp_active;
11.221 +
11.222 + /* Bring vsync high when the next line starts. */
11.223 +
11.224 + vsync_high();
11.225 +}
11.226 +
11.227 +
11.228 +
11.229 +/* Bring vsync low (single compare, output driven low) when the next line
11.230 + starts. */
11.231 +
11.232 +void vsync_low(void)
11.233 +{
11.234 + oc_init(vga_display.vsync_unit, 0b010, vga_display.line_timer);
11.235 + oc_on(vga_display.vsync_unit);
11.236 +}
11.237 +
11.238 +/* Bring vsync high (single compare, output driven high) when the next line
11.239 + starts. */
11.240 +
11.241 +void vsync_high(void)
11.242 +{
11.243 + oc_init(vga_display.vsync_unit, 0b001, vga_display.line_timer);
11.244 + oc_on(vga_display.vsync_unit);
11.245 +}
12.1 --- a/mk/common.mk Fri Nov 02 01:53:03 2018 +0100
12.2 +++ b/mk/common.mk Fri Nov 02 02:15:09 2018 +0100
12.3 @@ -51,8 +51,14 @@
12.4 COMMON_SRC = $(LIBDIR)/payload.c $(LIBDIR)/init.c $(LIBDIR)/debug.c $(LIBDIR)/cpu.S
12.5 COMMON_OBJ = $(LIBDIR)/payload.o $(LIBDIR)/init.o $(LIBDIR)/debug.o $(LIBDIR)/cpu.o
12.6
12.7 -DISPLAY_SRC = $(LIBDIR)/display.c $(LIBDIR)/vga_display.c $(LIBDIR)/font.c
12.8 -DISPLAY_OBJ = $(LIBDIR)/display.o $(LIBDIR)/vga_display.o $(LIBDIR)/font.o
12.9 +DISPLAY_COMMON_SRC = $(LIBDIR)/display.c $(LIBDIR)/font.c
12.10 +DISPLAY_COMMON_OBJ = $(LIBDIR)/display.o $(LIBDIR)/font.o
12.11 +
12.12 +DISPLAY_SRC = $(DISPLAY_COMMON_SRC) $(LIBDIR)/vga_display.c
12.13 +DISPLAY_OBJ = $(DISPLAY_COMMON_OBJ) $(LIBDIR)/vga_display.o
12.14 +
12.15 +DISPLAY_CPU_SRC = $(DISPLAY_COMMON_SRC) $(LIBDIR)/vga_display_cpu.c
12.16 +DISPLAY_CPU_OBJ = $(DISPLAY_COMMON_OBJ) $(LIBDIR)/vga_display_cpu.o
12.17
12.18 # Common linker script.
12.19