Skip to content

Commit

Permalink
VGA: Add fractional pixel scaling
Browse files Browse the repository at this point in the history
See Issue #187
  • Loading branch information
MJoergen committed Nov 10, 2020
1 parent d7ee665 commit d6aa14d
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 60 deletions.
145 changes: 145 additions & 0 deletions c/test_programs/vga_fractional.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/* VGA Fractional Scaling demonstration
*
* How to compile: qvc vga_fractional.c conio.c -O3 -c99
*
* done by MJoergen in November 2020
*/

#include <qmon.h>
#include "conio.h"

//convenient mechanism to access QNICE's Memory Mapped IO registers
#define MMIO( __x ) *((unsigned int volatile *) __x )

const char text[73][30] = {
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
"It is a period of civil war.\0",
"Rebel spaceships, striking\0",
"from a hidden base, have won\0",
"their first victory against\0",
"the evil Galactic Empire.\0",
" \0",
"During the battle, Rebel\0",
"spies managed to steal secret\0",
"plans to the Empire's\0",
"ultimate weapon, the DEATH\0",
"STAR, an armored space\0",
"station with enough power to\0",
"destroy an entire planet.\0",
" \0",
"Pursued by the Empire's\0",
"sinister agents, Princess\0",
"Leia races home aboard her\0",
"starship, custodian of the\0",
"stolen plans that can save\0",
"her people and restore\0",
"freedom to the galaxy....\0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0",
" \0"};

int main()
{
MMIO(VGA_STATE) &= ~VGA_EN_HW_CURSOR; // Disable hardware cursor.
qmon_vga_cls(); // Clear screen.

int counter = 12*10;
int startline = 0;
while (1)
{
int dy = counter/10; // Scrolling speed of 6 pixels/second.

if (counter >= 12*10)
{
counter = 0;
dy = 0;
MMIO(VGA_ADJUST_Y) = 0;
startline += 1;

// Display text on screen
for (int y=0; y<26; ++y)
{
cputsxy(5, y+14, text[y+startline], 0);
}
}
MMIO(VGA_ADJUST_Y) = dy;

int y;
while ((y = MMIO(VGA_SCAN_LINE)) >= 480)
{}
while ((y = MMIO(VGA_SCAN_LINE)) < 480)
{
y += dy;
MMIO(VGA_PIXEL_X_SCALE) = (20*256)/(y/12);
MMIO(VGA_ADJUST_X) = ((y-480)/12)*160/(y/12);
}

if (MMIO(IO_UART_SRA) & 1)
{
unsigned int tmp = MMIO(IO_UART_RHRA);
break;
}
if (MMIO(IO_KBD_STATE) & KBD_NEW_ANY)
{
unsigned int tmp = MMIO(IO_KBD_DATA);
break;
}

counter += 1; // Should increment once every frame, i.e. at 60 Hz.
} // while

MMIO(VGA_PIXEL_X_SCALE) = 0x0100;
MMIO(VGA_PIXEL_Y_SCALE) = 0x0100;
MMIO(VGA_ADJUST_X) = 0;
MMIO(VGA_ADJUST_Y) = 0;
return 0;
} // int main()

2 changes: 2 additions & 0 deletions c/vbcc/machines/qnice/sysdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@
#define VGA_PALETTE_OFFS 0xFF39 // Offset in words into the Palette RAM used for display
#define VGA_PALETTE_ADDR 0xFF3A // Palette Address
#define VGA_PALETTE_DATA 0xFF3B // Palette Data
#define VGA_PIXEL_X_SCALE 0xFF3C // Horizontal scaling in units of 256
#define VGA_PIXEL_Y_SCALE 0xFF3D // Vertical scaling in units of 256
#define VGA_ADJUST_X 0xFF40 // Pixels to adjust screen in X direction
#define VGA_ADJUST_Y 0xFF41 // Pixels to adjust screen in Y direction
#define VGA_SCAN_LINE 0xFF42 // Current scan line
Expand Down
2 changes: 2 additions & 0 deletions monitor/sysdef.asm
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ VGA$FONT_DATA .EQU 0xFF38 ; Font Data
VGA$PALETTE_OFFS .EQU 0xFF39 ; Offset in words into the Palette RAM used for display
VGA$PALETTE_ADDR .EQU 0xFF3A ; Palette Address
VGA$PALETTE_DATA .EQU 0xFF3B ; Palette Data
VGA$PIXEL_X_SCALE .EQU 0xFF3C ; Horizontal scaling in units of 256
VGA$PIXEL_Y_SCALE .EQU 0xFF3D ; Vertical scaling in units of 256
VGA$ADJUST_X .EQU 0xFF40 ; Pixels to adjust screen in X direction
VGA$ADJUST_Y .EQU 0xFF41 ; Pixels to adjust screen in Y direction
VGA$SCAN_LINE .EQU 0xFF42 ; Current scan line
Expand Down
10 changes: 5 additions & 5 deletions vhdl/vga/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ SOURCES += ../vga_multicolor.vhd

#TB = tb_vga_text_mode
#TB_SOURCES = tb_vga_text_mode.vhd
TB = tb_vga_sprite
TB_SOURCES = tb_vga_sprite.vhd
#TB = tb_vga_multicolor
#TB_SOURCES = tb_vga_multicolor.vhd
#TB = tb_vga_sprite
#TB_SOURCES = tb_vga_sprite.vhd
TB = tb_vga_multicolor
TB_SOURCES = tb_vga_multicolor.vhd

WAVE = $(TB).ghw
SAVE = $(TB).gtkw
Expand All @@ -30,6 +30,6 @@ SAVE = $(TB).gtkw
sim: $(SOURCES)
ghdl -i --work=work $(SOURCES) $(TB_SOURCES)
ghdl -m --ieee=synopsys -fexplicit $(TB)
ghdl -r -fsynopsys $(TB) --wave=$(WAVE) --max-stack-alloc=1024 --stop-time=55us
ghdl -r --ieee=synopsys $(TB) --wave=$(WAVE) --max-stack-alloc=1024 --stop-time=55us
gtkwave $(WAVE) $(SAVE)

12 changes: 8 additions & 4 deletions vhdl/vga/tb_vga_sprite.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,14 @@ begin
G_FRAME_COUNT => 60
)
port map (
clk_i => clk,
pixel_x_o => pixel_x,
pixel_y_o => pixel_y,
frame_o => open
clk_i => clk,
pixel_scale_x_i => X"0100",
pixel_scale_y_i => X"0100",
buffer_pixel_x_o => pixel_x,
buffer_pixel_y_o => pixel_y,
monitor_pixel_x_o => pixel_x,
monitor_pixel_y_o => pixel_y,
monitor_frame_o => open
); -- i_vga_pixel_counters


Expand Down
63 changes: 36 additions & 27 deletions vhdl/vga/vga_output.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ entity vga_output is
cursor_x_i : in std_logic_vector(6 downto 0); -- 0 to 79
cursor_y_i : in std_logic_vector(5 downto 0); -- 0 to 39
pixel_y_o : out std_logic_vector(9 downto 0); -- 0 to 524
pixel_scale_x_i : in std_logic_vector(15 downto 0);
pixel_scale_y_i : in std_logic_vector(15 downto 0);
adjust_x_i : in std_logic_vector(9 downto 0);
adjust_y_i : in std_logic_vector(9 downto 0);

Expand Down Expand Up @@ -58,18 +60,21 @@ architecture synthesis of vga_output is
constant H_PIXELS : integer := 640;
constant V_PIXELS : integer := 480;

signal pixel_x : std_logic_vector(9 downto 0); -- 0 to 799
signal pixel_y : std_logic_vector(9 downto 0); -- 0 to 524
signal frame : std_logic_vector(5 downto 0); -- 0 to 59
signal color_text : std_logic_vector(15 downto 0);
signal color_sprite : std_logic_vector(15 downto 0);
signal delay_text : std_logic_vector(9 downto 0);
signal delay_sprite : std_logic_vector(9 downto 0);
signal delay : std_logic_vector(9 downto 0);
signal pixel_x_text : std_logic_vector(9 downto 0);
signal pixel_y_text : std_logic_vector(9 downto 0);
signal pixel_x_sprite : std_logic_vector(9 downto 0);
signal pixel_y_sprite : std_logic_vector(9 downto 0);
signal buffer_pixel_x : std_logic_vector(9 downto 0); -- 0 to 799
signal buffer_pixel_y : std_logic_vector(9 downto 0); -- 0 to 524
signal monitor_pixel_x : std_logic_vector(9 downto 0); -- 0 to 799
signal monitor_pixel_y : std_logic_vector(9 downto 0); -- 0 to 524
signal monitor_frame : std_logic_vector(5 downto 0); -- 0 to 59

signal color_text : std_logic_vector(15 downto 0);
signal color_sprite : std_logic_vector(15 downto 0);
signal delay_text : std_logic_vector(9 downto 0);
signal delay_sprite : std_logic_vector(9 downto 0);
signal delay : std_logic_vector(9 downto 0);
signal pixel_x_text : std_logic_vector(9 downto 0);
signal pixel_y_text : std_logic_vector(9 downto 0);
signal pixel_x_sprite : std_logic_vector(9 downto 0);
signal pixel_y_sprite : std_logic_vector(9 downto 0);

begin

Expand All @@ -84,19 +89,23 @@ begin
G_FRAME_COUNT => 60
)
port map (
clk_i => clk_i,
pixel_x_o => pixel_x,
pixel_y_o => pixel_y,
frame_o => frame
clk_i => clk_i,
pixel_scale_x_i => pixel_scale_x_i,
pixel_scale_y_i => pixel_scale_y_i,
buffer_pixel_x_o => buffer_pixel_x,
buffer_pixel_y_o => buffer_pixel_y,
monitor_pixel_x_o => monitor_pixel_x,
monitor_pixel_y_o => monitor_pixel_y,
monitor_frame_o => monitor_frame
); -- i_vga_pixel_counters


-------------------------
-- Instantiate Text Mode
-------------------------

pixel_x_text <= pixel_x + adjust_x_i;
pixel_y_text <= pixel_y + adjust_y_i;
pixel_x_text <= buffer_pixel_x + adjust_x_i;
pixel_y_text <= buffer_pixel_y + adjust_y_i;

i_vga_text_mode : entity work.vga_text_mode
port map (
Expand All @@ -113,7 +122,7 @@ begin
-- Pixel Counters
pixel_x_i => pixel_x_text,
pixel_y_i => pixel_y_text,
frame_i => frame,
frame_i => monitor_frame,
-- Interface to Video RAM
display_addr_o => display_addr_o,
display_data_i => display_data_i,
Expand All @@ -131,8 +140,8 @@ begin
-- Instantiate Sprites
-----------------------

pixel_x_sprite <= pixel_x - delay_text;
pixel_y_sprite <= pixel_y;
pixel_x_sprite <= buffer_pixel_x - delay_text;
pixel_y_sprite <= buffer_pixel_y;

i_vga_sprite : entity work.vga_sprite
generic map (
Expand Down Expand Up @@ -169,8 +178,8 @@ begin
port map (
clk_i => clk_i,
output_en_i => output_enable_i,
pixel_x_i => pixel_x,
pixel_y_i => pixel_y,
pixel_x_i => monitor_pixel_x,
pixel_y_i => monitor_pixel_y,
color_i => color_sprite(14 downto 0),
delay_i => delay,
hsync_o => hsync_o,
Expand All @@ -182,10 +191,10 @@ begin
p_pixel_y : process (clk_i)
begin
if rising_edge(clk_i) then
pixel_y_o <= pixel_y;
if conv_integer(pixel_x) >= H_PIXELS then
pixel_y_o <= pixel_y+1;
if conv_integer(pixel_y) = 524 then
pixel_y_o <= monitor_pixel_y;
if conv_integer(monitor_pixel_x) >= H_PIXELS then
pixel_y_o <= monitor_pixel_y+1;
if conv_integer(monitor_pixel_y) = 524 then
pixel_y_o <= (others => '0');
end if;
end if;
Expand Down
Loading

0 comments on commit d6aa14d

Please sign in to comment.