📄 vdp_pack.vhd
字号:
SIGNAL dav : OUT STD_LOGIC;
SIGNAL hdb_busy : IN STD_LOGIC
) IS
VARIABLE cmdword : STD_LOGIC_VECTOR(15 DOWNTO 0);
-- drive host bus with a new command
-- wait until handshake is complete before returning
BEGIN
-- check parameters are legal
ASSERT x >= 0 AND x < 64 AND y >= 0 AND y < 64 REPORT
"Invalid parameters for send_vdp_command : x = " & i2s(x) &
", y = " & i2s(y)
SEVERITY error;
CASE cmd IS
WHEN movepen => cmdword(15 DOWNTO 14) := "00";
WHEN drawline => cmdword(15 DOWNTO 14) := "01";
WHEN clearscreen => cmdword(15 DOWNTO 14) := "10";
WHEN flushcache => cmdword(15 DOWNTO 14) := "11";
END CASE;
CASE pen IS
WHEN black => cmdword(1 DOWNTO 0) := "00";
WHEN white => cmdword(1 DOWNTO 0) := "01";
WHEN invert => cmdword(1 DOWNTO 0) := "10";
END CASE;
cmdword(13 DOWNTO 8) := conv_std_logic_vector( x, 6);
cmdword( 7 DOWNTO 2) := conv_std_logic_vector( y, 6);
-- terminate last command if necessary
ASSERT hdb_busy = '0' OR hdb_busy = '1' REPORT
"hdb_busy (" & STD_LOGIC'IMAGE(hdb_busy) & " is not a valid value"
SEVERITY error;
IF hdb_busy /= '0' THEN
WAIT UNTIL hdb_busy = '0';
END IF;
hdb <= cmdword; -- put command on host bus
dav <= '1';
WAIT UNTIL hdb_busy = '1'; -- wait until data has been read
dav <= '0'; -- host side of handshake is now complete
WAIT FOR 0 ns; -- make sure dav changes
END send_vdp_command;
----------------------------------------------------------
------------- Software VDP --------------------------------
----------------------------------------------------------
PROCEDURE decode_paras(
cmdword : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
VARIABLE cmd : OUT cmd_type;
VARIABLE x : OUT INTEGER;
VARIABLE y : OUT INTEGER;
VARIABLE pen : OUT pen_type
) IS
BEGIN
CASE cmdword(15 DOWNTO 14) IS
WHEN "00" => cmd := movepen;
WHEN "01" => cmd := drawline;
WHEN "10" => cmd := clearscreen;
WHEN "11" => cmd := flushcache;
WHEN OTHERS => REPORT "bad cmd field for do_command : " &
v2s(cmdword(15 DOWNTO 14));
END CASE;
CASE cmdword(1 DOWNTO 0) IS
WHEN "00" => pen := black;
WHEN "01" => pen := white;
WHEN "10" => pen := invert;
WHEN OTHERS => REPORT "bad pen field for do_command : " &
v2s(cmdword(1 DOWNTO 0));
END CASE;
x := conv_integer(UNSIGNED(cmdword(13 DOWNTO 8)));
y := conv_integer(UNSIGNED(cmdword(7 DOWNTO 2)));
END PROCEDURE decode_paras;
-- persistant state for do_command
SHARED VARIABLE x_old : INTEGER RANGE 0 TO 63 := 0;
SHARED VARIABLE y_old : INTEGER RANGE 0 TO 63 := 0;
TYPE image_vector IS RECORD
x : INTEGER;
y : INTEGER;
END RECORD;
PROCEDURE do_vdp_command(
cmd : IN cmd_type;
x : IN INTEGER;
y : IN INTEGER;
pen : IN pen_type;
SIGNAL cycle_init : OUT STD_LOGIC;
SIGNAL cycle_done : IN STD_LOGIC;
dest : IN ram_mode_type
) IS
VARIABLE xt, yt : INTEGER; -- temporary coordinates
VARIABLE z : INTEGER; --temporary current perpendicular offset
VARIABLE xa, xb, ya, yb, yinc : INTEGER;
VARIABLE v1, v2, vdir, v : image_vector;
VARIABLE oct : STD_LOGIC_VECTOR( 0 TO 2); -- bits determine octant
PROCEDURE change_ram_bit(
x : IN INTEGER;
y : IN INTEGER;
pen : IN pen_type;
SIGNAL cycle_init : OUT STD_LOGIC;
SIGNAL cycle_done : IN STD_LOGIC;
dest : IN ram_mode_type
) IS
-- alters (x,y) pixel in image ram_array as specified by pen
-- may need to read and write to ram_array (for invert writing)
VARIABLE val : STD_LOGIC; -- initial value in ram of bit to be written
BEGIN
CASE pen IS
WHEN black => write_ram_bit( x, y, '0', cycle_init, cycle_done, dest);
WHEN white => write_ram_bit( x, y, '1', cycle_init, cycle_done, dest);
WHEN invert =>
read_ram_bit(x, y, cycle_init, cycle_done, dest, val);
write_ram_bit( x, y, NOT val, cycle_init, cycle_done, dest);
END CASE;
END change_ram_bit;
FUNCTION cross(
v1 : image_vector;
v2 : image_vector
) RETURN INTEGER IS
-- magnitude of v1 component in direction perpendicular to v2
BEGIN
RETURN v1.x*v2.y-v1.y*v2.x;
END cross;
PROCEDURE swap(
-- sets big, small from a,b swapping if necessary so that big > small
a : IN INTEGER;
b : IN INTEGER;
VARIABLE big : OUT INTEGER;
VARIABLE small : OUT INTEGER
) IS
BEGIN
big := maximum(a, b);
small := minimum(a, b);
END swap;
BEGIN
-- implement the command by writing bits in ram
CASE cmd IS
WHEN movepen => NULL;
WHEN clearscreen =>
swap( x, x_old, xb, xa);
swap( y, y_old, yb, ya);
--REPORT "clearing screen... xa=" & i2s(xa) &", xb="&i2s(xb)&
-- ", ya="&i2s(ya)&", yb="&i2s(yb);
-- xa<xb and ya<yb
FOR i IN xa TO xb LOOP
FOR j IN ya TO yb LOOP
change_ram_bit( i, j, pen, cycle_init, cycle_done, dest);
END LOOP;
END LOOP;
-- flush cache does nothing in the behavioural VDP
WHEN flushcache => NULL;
WHEN drawline =>
-- print out stuff for debugging
-- REPORT integer'image(x_old) & ", " & integer'image(y_old) & " " &
-- integer'image(x) & "," & integer'image(y);
--
-- swap coordinates so that we are always drawing line in direction
-- of octant 1 or 2, 7 or 8 (ie x increasing)
xt := x_old;
yt := y_old;
z := 0;
vdir := (x-x_old, y-y_old); -- vector to draw
FOR i IN 0 TO 2 LOOP
oct(i) := '0';
END LOOP;
IF vdir.x > 0 THEN
oct(0) := '1';
END IF;
IF vdir.y > 0 THEN
oct(1) := '1';
END IF;
IF ABS(vdir.x) > ABS(vdir.y) THEN
oct(2) := '1';
END IF;
CASE oct IS
WHEN "111" => v1 := (1,1); v2 := (1,0);
WHEN "110" => v1 := (0,1); v2 := (1,1);
WHEN "010" => v1 := (-1,1); v2 := (0,1);
WHEN "011" => v1 := (-1,0); v2 := (-1,1);
WHEN "001" => v1 := (-1,-1); v2 := (-1,0);
WHEN "000" => v1 := (0,-1); v2 := (-1,-1);
WHEN "100" => v1 := (1,-1); v2 := (0,-1);
WHEN "101" => v1 := (1,0); v2 := (1,-1);
WHEN OTHERS => NULL;
END CASE;
-- implement line drawing algorithm
WHILE NOT((xt = x) AND (yt = y)) LOOP
-- this check should always pass
ASSERT (ABS(xt) < 65) AND (ABS(yt) < 65)
REPORT "Overflow: xt=" & INTEGER'IMAGE(xt) & ", yt=" & INTEGER'IMAGE(yt) &
", z=" & INTEGER'IMAGE(z) &
", vdir=(" & INTEGER'IMAGE(vdir.x) & "," & INTEGER'IMAGE(vdir.y)& ")"
SEVERITY failure;
change_ram_bit( xt, yt, pen, cycle_init, cycle_done, dest);
IF ABS(z + cross( v1, vdir)) < ABS(z+cross(v2, vdir)) THEN
v := v1;
ELSE
v := v2;
END IF;
xt := xt+v.x; yt := yt+v.y;
z := z + cross( v, vdir);
END LOOP;
-- set last pixel
change_ram_bit( xt, yt, pen, cycle_init, cycle_done, dest);
END CASE;
-- tidy up setting old coords to new
x_old := x;
y_old := y;
-- finished!
END do_vdp_command;
PROCEDURE write_lines(fname : IN STRING) IS
-- writes out a sequence of commands to a file with filename fname
-- the commands draw a star pattern on the screen, including lines
-- in every possible octant, and every octant boundary
-- The file can be read, and run through the behavioural VDP
-- using vdp_testbench.
CONSTANT r : INTEGER := 10;
CONSTANT xcentre : INTEGER := 32;
CONSTANT ycentre : INTEGER := 32;
FILE f : TEXT OPEN write_mode IS fname;
VARIABLE buf : LINE;
BEGIN
FOR i IN -2 TO 2 LOOP
FOR j IN -2 TO 2 LOOP
IF ABS(i) = 2 OR ABS(j) = 2 THEN
write( buf, STRING'("MB "));
write( buf, xcentre+r*i);
write( buf, STRING'(" "));
write( buf, ycentre+r*j);
writeline(f, buf);
write( buf, STRING'("DB "));
write( buf, xcentre);
write( buf, STRING'(" "));
write( buf, ycentre);
writeline(f, buf);
END IF;
END LOOP;
END LOOP;
END write_lines;
-- this runs a set of commands from file fname through a behavioural
-- VDP which writes to ram using do_ram_cycle, with destination ram_data_model
PROCEDURE run_command_file(
fname : IN STRING;
SIGNAL cycle_init : OUT STD_LOGIC;
SIGNAL cycle_done : IN STD_LOGIC
) IS
FILE f : TEXT OPEN read_mode IS fname;
VARIABLE buf : LINE;
VARIABLE ch : CHARACTER;
VARIABLE cmd : cmd_type;
VARIABLE pen : pen_type;
VARIABLE x, y : INTEGER;
VARIABLE n : INTEGER;
VARIABLE skipline : BOOLEAN;
BEGIN
n := 1;
WHILE NOT endfile(f) LOOP
readline( f, buf);
read( buf, ch);
skipline := false;
CASE ch IS
WHEN 'D' => cmd := drawline;
WHEN 'M' => cmd := movepen;
WHEN 'C' => cmd := clearscreen;
WHEN 'F' => cmd := flushcache;
WHEN '-' => skipline := true;
WHEN OTHERS =>
REPORT "Bad character ("& ch &
") should be [DMC] in col 1, line "&i2s(n);
END CASE;
IF NOT skipline THEN
read( buf, ch);
CASE ch IS
WHEN 'B' => pen := black;
WHEN 'W' => pen := white;
WHEN 'I' => pen := invert;
WHEN OTHERS =>
REPORT "Bad character ("& ch &
") should be [BWI] in col 2, line "&i2s(n);
END CASE;
read( buf, x);
read( buf, y);
do_vdp_command(cmd, x, y, pen, cycle_init, cycle_done, model);
END IF;
n := n+1;
END LOOP;
END run_command_file;
END vdp_pack;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -