mirror of
https://github.com/MiSTer-devel/MultiComp_MiSTer.git
synced 2026-04-19 03:04:38 +00:00
Initial Commit of the MuliComp. MuliComp is a port of Grant Searle's MultiComp to the MiSTer
1181 lines
40 KiB
VHDL
1181 lines
40 KiB
VHDL
-- This file is copyright by Grant Searle 2014
|
|
-- You are free to use this file in your own projects but must never charge for it nor use it without
|
|
-- acknowledgement.
|
|
-- Please ask permission from Grant Searle before republishing elsewhere.
|
|
-- If you use this file or any part of it, please add an acknowledgement to myself and
|
|
-- a link back to my main web site http://searle.hostei.com/grant/
|
|
-- and to the "multicomp" page at http://searle.hostei.com/grant/Multicomp/index.html
|
|
--
|
|
-- Please check on the above web pages to see if there are any updates before using this file.
|
|
-- If for some reason the page is no longer available, please search for "Grant Searle"
|
|
-- on the internet to see if I have moved to another web hosting service.
|
|
--
|
|
-- Grant Searle
|
|
-- eMail address available on my main web page link above.
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
use ieee.std_logic_unsigned.all;
|
|
|
|
entity SBCTextDisplayRGB is
|
|
generic(
|
|
constant EXTENDED_CHARSET : integer := 0; -- 1 = 256 chars, 0 = 128 chars
|
|
constant COLOUR_ATTS_ENABLED : integer := 1; -- 1=Colour for each character, 0=Colour applied to whole display
|
|
-- VGA 640x480 Default values
|
|
constant VERT_CHARS : integer := 25;
|
|
constant HORIZ_CHARS : integer := 80;
|
|
constant CLOCKS_PER_SCANLINE : integer := 1600; -- NTSC/PAL = 3200
|
|
constant DISPLAY_TOP_SCANLINE : integer := 35+40;
|
|
constant DISPLAY_LEFT_CLOCK : integer := 288; -- NTSC/PAL = 600+
|
|
constant VERT_SCANLINES : integer := 525; -- NTSC=262, PAL=312
|
|
constant VSYNC_SCANLINES : integer := 2; -- NTSC/PAL = 4
|
|
constant HSYNC_CLOCKS : integer := 192; -- NTSC/PAL = 235
|
|
constant VERT_PIXEL_SCANLINES : integer := 2;
|
|
constant CLOCKS_PER_PIXEL : integer := 2; -- min = 2
|
|
constant H_SYNC_ACTIVE : std_logic := '0';
|
|
constant V_SYNC_ACTIVE : std_logic := '0';
|
|
|
|
constant DEFAULT_ATT : std_logic_vector(7 downto 0) := "00001111"; -- background iBGR | foreground iBGR (i=intensity)
|
|
constant ANSI_DEFAULT_ATT : std_logic_vector(7 downto 0) := "00000111" -- background iBGR | foreground iBGR (i=intensity)
|
|
);
|
|
port (
|
|
n_reset : in std_logic;
|
|
clk : in std_logic;
|
|
n_wr : in std_logic;
|
|
n_rd : in std_logic;
|
|
regSel : in std_logic;
|
|
dataIn : in std_logic_vector(7 downto 0);
|
|
dataOut : out std_logic_vector(7 downto 0);
|
|
n_int : out std_logic;
|
|
n_rts : out std_logic :='0';
|
|
|
|
-- RGB video signals
|
|
videoR0 : out std_logic;
|
|
videoR1 : out std_logic;
|
|
videoG0 : out std_logic;
|
|
videoG1 : out std_logic;
|
|
videoB0 : out std_logic;
|
|
videoB1 : out std_logic;
|
|
hSync : buffer std_logic;
|
|
vSync : buffer std_logic;
|
|
hBlank : out std_logic;
|
|
vBlank : out std_logic;
|
|
cepix : out std_logic;
|
|
|
|
-- Monochrome video signals
|
|
video : buffer std_logic;
|
|
sync : out std_logic;
|
|
|
|
-- Keyboard signals
|
|
ps2Clk : in std_logic;
|
|
ps2Data : in std_logic;
|
|
|
|
-- FN keys passed out as general signals (momentary and toggled versions)
|
|
FNkeys : out std_logic_vector(12 downto 0);
|
|
FNtoggledKeys : out std_logic_vector(12 downto 0)
|
|
);
|
|
end SBCTextDisplayRGB;
|
|
|
|
architecture rtl of SBCTextDisplayRGB is
|
|
|
|
--VGA 640x400
|
|
--constant VERT_CHARS : integer := 25;
|
|
--constant HORIZ_CHARS : integer := 80;
|
|
--constant CLOCKS_PER_SCANLINE : integer := 1600;
|
|
--constant DISPLAY_TOP_SCANLINE : integer := 35;
|
|
--constant DISPLAY_LEFT_CLOCK : integer := 288;
|
|
--constant VERT_SCANLINES : integer := 448;
|
|
--constant VSYNC_SCANLINES : integer := 2;
|
|
--constant HSYNC_CLOCKS : integer := 192;
|
|
--constant VERT_PIXEL_SCANLINES : integer := 2;
|
|
--constant CLOCKS_PER_PIXEL : integer := 2; -- min = 2
|
|
--constant H_SYNC_ACTIVE : std_logic := '0';
|
|
--constant V_SYNC_ACTIVE : std_logic := '1';
|
|
|
|
constant HORIZ_CHAR_MAX : integer := HORIZ_CHARS-1;
|
|
constant VERT_CHAR_MAX : integer := VERT_CHARS-1;
|
|
constant CHARS_PER_SCREEN : integer := HORIZ_CHARS*VERT_CHARS;
|
|
|
|
signal FNkeysSig : std_logic_vector(12 downto 0) := (others => '0');
|
|
signal FNtoggledKeysSig : std_logic_vector(12 downto 0) := (others => '0');
|
|
|
|
signal vActive : std_logic := '0';
|
|
signal hActive : std_logic := '0';
|
|
|
|
signal pixelClockCount: STD_LOGIC_VECTOR(3 DOWNTO 0);
|
|
signal pixelCount: STD_LOGIC_VECTOR(2 DOWNTO 0);
|
|
|
|
signal horizCount: STD_LOGIC_VECTOR(11 DOWNTO 0);
|
|
signal vertLineCount: STD_LOGIC_VECTOR(9 DOWNTO 0);
|
|
|
|
signal charVert: integer range 0 to VERT_CHAR_MAX; --unsigned(4 DOWNTO 0);
|
|
signal charScanLine: STD_LOGIC_VECTOR(3 DOWNTO 0);
|
|
|
|
signal charHoriz: integer range 0 to HORIZ_CHAR_MAX; --unsigned(6 DOWNTO 0);
|
|
signal charBit: STD_LOGIC_VECTOR(3 DOWNTO 0);
|
|
|
|
signal cursorVert: integer range 0 to VERT_CHAR_MAX :=0;
|
|
signal cursorHoriz: integer range 0 to HORIZ_CHAR_MAX :=0;
|
|
|
|
signal cursorVertRestore: integer range 0 to VERT_CHAR_MAX :=0;
|
|
signal cursorHorizRestore: integer range 0 to HORIZ_CHAR_MAX :=0;
|
|
|
|
signal savedCursorVert: integer range 0 to VERT_CHAR_MAX :=0;
|
|
signal savedCursorHoriz: integer range 0 to HORIZ_CHAR_MAX :=0;
|
|
|
|
signal startAddr: integer range 0 to CHARS_PER_SCREEN;
|
|
signal cursAddr : integer range 0 to CHARS_PER_SCREEN;
|
|
|
|
signal dispAddr : integer range 0 to CHARS_PER_SCREEN;
|
|
signal charAddr : std_LOGIC_VECTOR(10 downto 0);
|
|
|
|
signal dispCharData : std_LOGIC_VECTOR(7 downto 0);
|
|
signal dispCharWRData : std_LOGIC_VECTOR(7 downto 0);
|
|
signal dispCharRDData : std_LOGIC_VECTOR(7 downto 0);
|
|
|
|
signal dispAttData : std_LOGIC_VECTOR(7 downto 0);
|
|
signal dispAttWRData : std_LOGIC_VECTOR(7 downto 0):=DEFAULT_ATT; -- iBGR(back) iBGR(text)
|
|
signal dispAttRDData : std_LOGIC_VECTOR(7 downto 0);
|
|
|
|
signal charData : std_LOGIC_VECTOR(7 downto 0);
|
|
|
|
signal cursorOn : std_logic := '1';
|
|
signal dispWR : std_logic := '0';
|
|
signal cursBlinkCount : unsigned(25 downto 0);
|
|
signal kbWatchdogTimer : integer range 0 to 50000000 :=0;
|
|
signal kbWriteTimer : integer range 0 to 50000000 :=0;
|
|
|
|
signal n_int_internal : std_logic := '1';
|
|
signal statusReg : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal controlReg : std_logic_vector(7 downto 0) := "00000000";
|
|
|
|
type kbBuffArray is array (0 to 7) of std_logic_vector(6 downto 0);
|
|
signal kbBuffer : kbBuffArray;
|
|
|
|
signal kbInPointer: integer range 0 to 15 :=0;
|
|
signal kbReadPointer: integer range 0 to 15 :=0;
|
|
signal kbBuffCount: integer range 0 to 15 :=0;
|
|
signal dispByteWritten : std_logic := '0';
|
|
signal dispByteSent : std_logic := '0';
|
|
|
|
signal dispByteLatch: std_logic_vector(7 DOWNTO 0);
|
|
type dispStateType is ( idle, dispWrite, dispNextLoc, clearLine, clearL2,
|
|
clearScreen, clearS2, clearChar, clearC2, insertLine, ins2, ins3, deleteLine, del2, del3);
|
|
signal dispState : dispStateType :=idle;
|
|
type nextStateType is ( none, waitForLeftBracket, processingParams, processingAdditionalParams );
|
|
signal nextState : nextStateType :=none;
|
|
|
|
signal param1: integer range 0 to 127 :=0;
|
|
signal param2: integer range 0 to 127 :=0;
|
|
signal param3: integer range 0 to 127 :=0;
|
|
signal param4: integer range 0 to 127 :=0;
|
|
signal paramCount: integer range 0 to 4 :=0;
|
|
|
|
signal attInverse : std_logic := '0';
|
|
signal attBold : std_logic := DEFAULT_ATT(3);
|
|
|
|
signal ps2Byte: std_logic_vector(7 DOWNTO 0);
|
|
signal ps2PreviousByte: std_logic_vector(7 DOWNTO 0);
|
|
signal ps2ConvertedByte: std_logic_vector(6 DOWNTO 0);
|
|
signal ps2ClkCount : integer range 0 to 10 :=0;
|
|
signal ps2WriteClkCount : integer range 0 to 20 :=0;
|
|
signal ps2WriteByte: std_logic_vector(7 DOWNTO 0) := x"FF";
|
|
signal ps2WriteByte2: std_logic_vector(7 DOWNTO 0):= x"FF";
|
|
signal ps2PrevClk: std_logic := '1';
|
|
signal ps2ClkFilter : integer range 0 to 50;
|
|
signal ps2ClkFiltered : std_logic := '1';
|
|
|
|
signal ps2Shift: std_logic := '0';
|
|
signal ps2Ctrl: std_logic := '0';
|
|
signal ps2Caps: std_logic := '1';
|
|
signal ps2Num: std_logic := '0';
|
|
signal ps2Scroll: std_logic := '0';
|
|
|
|
signal ps2DataOut: std_logic := '1';
|
|
signal ps2ClkOut: std_logic := '1';
|
|
signal n_kbWR: std_logic := '1';
|
|
signal kbWRParity: std_logic := '0';
|
|
|
|
type kbDataArray is array (0 to 131) of std_logic_vector(6 downto 0);
|
|
|
|
-- UK KEYBOARD MAPPING (except for shift-3 = "#")
|
|
|
|
--Original 8-bit HEX values
|
|
-- constant kbUnshifted : kbDataArray :=
|
|
-- (
|
|
-- --0 1 2 3 4 5 6 7 8 9 A B C D E F
|
|
-- x"00",x"19",x"00",x"00",x"13",x"11",x"12",x"1C",x"00",x"1A",x"18",x"16",x"00",x"09",x"60",x"00", -- 0
|
|
-- x"00",x"00",x"00",x"00",x"00",x"71",x"31",x"00",x"00",x"00",x"7A",x"73",x"61",x"77",x"32",x"00", -- 1
|
|
-- x"00",x"63",x"78",x"64",x"65",x"34",x"33",x"00",x"00",x"20",x"76",x"66",x"74",x"72",x"35",x"00", -- 2
|
|
-- x"00",x"6E",x"62",x"68",x"67",x"79",x"36",x"00",x"00",x"00",x"6D",x"6A",x"75",x"37",x"38",x"00", -- 3
|
|
-- x"00",x"2C",x"6B",x"69",x"6F",x"30",x"39",x"00",x"00",x"2E",x"2F",x"6C",x"3B",x"70",x"2D",x"00", -- 4
|
|
-- x"00",x"00",x"27",x"00",x"5B",x"3D",x"00",x"00",x"00",x"00",x"0D",x"5D",x"00",x"00",x"00",x"00", -- 5
|
|
-- x"00",x"00",x"00",x"00",x"00",x"00",x"08",x"00",x"00",x"31",x"00",x"34",x"37",x"00",x"00",x"00", -- 6
|
|
-- x"30",x"2E",x"32",x"35",x"36",x"38",x"03",x"00",x"1B",x"2B",x"33",x"2D",x"2A",x"39",x"00",x"00", -- 7
|
|
-- x"00",x"00",x"00",x"17"
|
|
-- );
|
|
-- constant kbShifted : kbDataArray :=
|
|
-- (
|
|
-- --0 1 2 3 4 5 6 7 8 9 A B C D E F
|
|
-- x"00",x"19",x"00",x"00",x"13",x"11",x"12",x"1C",x"00",x"1A",x"18",x"16",x"00",x"09",x"00",x"00", -- 0
|
|
-- x"00",x"00",x"00",x"00",x"00",x"51",x"21",x"00",x"00",x"00",x"5A",x"53",x"41",x"57",x"22",x"00", -- 1
|
|
-- x"00",x"43",x"58",x"44",x"45",x"24",x"23",x"00",x"00",x"20",x"56",x"46",x"54",x"52",x"25",x"00", -- 2
|
|
-- x"00",x"4E",x"42",x"48",x"47",x"59",x"5E",x"00",x"00",x"00",x"4D",x"4A",x"55",x"26",x"2A",x"00", -- 3
|
|
-- x"00",x"3C",x"4B",x"49",x"4F",x"29",x"28",x"00",x"00",x"3E",x"3F",x"4C",x"3A",x"50",x"5F",x"00", -- 4
|
|
-- x"00",x"00",x"40",x"00",x"7B",x"2B",x"00",x"00",x"00",x"00",x"0D",x"7D",x"00",x"00",x"00",x"00", -- 5
|
|
-- x"00",x"00",x"00",x"00",x"00",x"00",x"08",x"00",x"00",x"31",x"00",x"34",x"37",x"00",x"00",x"00", -- 6
|
|
-- x"30",x"2E",x"32",x"35",x"36",x"38",x"0C",x"00",x"1B",x"2B",x"33",x"2D",x"2A",x"39",x"00",x"00", -- 7
|
|
-- x"00",x"00",x"00",x"17"
|
|
-- );
|
|
|
|
-- 7 bits to reduce logic count
|
|
constant kbUnshifted : kbDataArray :=
|
|
(
|
|
-- 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
|
"0000000","0011001","0000000","0000000","0010011","0010001","0010010","0011100","0000000","0011010","0011000","0010110","0000000","0001001","1100000","0000000", -- 0
|
|
"0000000","0000000","0000000","0000000","0000000","1110001","0110001","0000000","0000000","0000000","1111010","1110011","1100001","1110111","0110010","0000000", -- 1
|
|
"0000000","1100011","1111000","1100100","1100101","0110100","0110011","0000000","0000000","0100000","1110110","1100110","1110100","1110010","0110101","0000000", -- 2
|
|
"0000000","1101110","1100010","1101000","1100111","1111001","0110110","0000000","0000000","0000000","1101101","1101010","1110101","0110111","0111000","0000000", -- 3
|
|
"0000000","0101100","1101011","1101001","1101111","0110000","0111001","0000000","0000000","0101110","0101111","1101100","0111011","1110000","0101101","0000000", -- 4
|
|
"0000000","0000000","0100111","0000000","1011011","0111101","0000000","0000000","0000000","0000000","0001101","1011101","0000000","0000000","0000000","0000000", -- 5
|
|
"0000000","0000000","0000000","0000000","0000000","0000000","0001000","0000000","0000000","0110001","0000000","0110100","0110111","0000000","0000000","0000000", -- 6
|
|
"0110000","0101110","0110010","0110101","0110110","0111000","0000011","0000000","0011011","0101011","0110011","0101101","0101010","0111001","0000000","0000000", -- 7
|
|
"0000000","0000000","0000000","0010111"
|
|
);
|
|
constant kbShifted : kbDataArray :=
|
|
(
|
|
-- 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
|
"0000000","0011001","0000000","0000000","0010011","0010001","0010010","0011100","0000000","0011010","0011000","0010110","0000000","0001001","0000000","0000000", -- 0
|
|
"0000000","0000000","0000000","0000000","0000000","1010001","0100001","0000000","0000000","0000000","1011010","1010011","1000001","1010111","0100010","0000000", -- 1
|
|
"0000000","1000011","1011000","1000100","1000101","0100100","0100011","0000000","0000000","0100000","1010110","1000110","1010100","1010010","0100101","0000000", -- 2
|
|
"0000000","1001110","1000010","1001000","1000111","1011001","1011110","0000000","0000000","0000000","1001101","1001010","1010101","0100110","0101010","0000000", -- 3
|
|
"0000000","0111100","1001011","1001001","1001111","0101001","0101000","0000000","0000000","0111110","0111111","1001100","0111010","1010000","1011111","0000000", -- 4
|
|
"0000000","0000000","1000000","0000000","1111011","0101011","0000000","0000000","0000000","0000000","0001101","1111101","0000000","0000000","0000000","0000000", -- 5
|
|
"0000000","0000000","0000000","0000000","0000000","0000000","0001000","0000000","0000000","0110001","0000000","0110100","0110111","0000000","0000000","0000000", -- 6
|
|
"0110000","0101110","0110010","0110101","0110110","0111000","0001100","0000000","0011011","0101011","0110011","0101101","0101010","0111001","0000000","0000000", -- 7
|
|
"0000000","0000000","0000000","0010111"
|
|
);
|
|
|
|
|
|
begin
|
|
|
|
-- DISPLAY ROM AND RAM
|
|
|
|
GEN_EXT_CHARS: if (EXTENDED_CHARSET=1) generate
|
|
begin
|
|
fontRom : entity work.CGABoldRom -- 256 chars (2K)
|
|
port map(
|
|
address => charAddr,
|
|
clock => clk,
|
|
q => charData
|
|
);
|
|
end generate GEN_EXT_CHARS;
|
|
|
|
GEN_REDUCED_CHARS: if (EXTENDED_CHARSET=0) generate
|
|
begin
|
|
fontRom : entity work.CGABoldRomReduced -- 128 chars (1K)
|
|
port map(
|
|
address => charAddr(9 downto 0),
|
|
clock => clk,
|
|
q => charData
|
|
);
|
|
end generate GEN_REDUCED_CHARS;
|
|
|
|
GEN_2KRAM: if (CHARS_PER_SCREEN >1024) generate
|
|
begin
|
|
dispCharRam: entity work.DisplayRam2K -- For 80x25 display character storage
|
|
port map
|
|
(
|
|
clock => clk,
|
|
|
|
address_b => std_logic_vector(to_unsigned(cursAddr,11)),
|
|
data_b => dispCharWRData,
|
|
q_b => dispCharRDData,
|
|
wren_b => dispWR,
|
|
|
|
address_a => std_logic_vector(to_unsigned(dispAddr,11)),
|
|
data_a => (others => '0'),
|
|
q_a => dispCharData,
|
|
wren_a => '0'
|
|
);
|
|
end generate GEN_2KRAM;
|
|
|
|
GEN_2KATTRAM: if (CHARS_PER_SCREEN >1024 and COLOUR_ATTS_ENABLED=1) generate
|
|
begin
|
|
|
|
dispAttRam: entity work.DisplayRam2K -- For 80x25 display attribute storage
|
|
port map
|
|
(
|
|
clock => clk,
|
|
|
|
address_b => std_logic_vector(to_unsigned(cursAddr,11)),
|
|
data_b => dispAttWRData,
|
|
q_b => dispAttRDData,
|
|
wren_b => dispWR,
|
|
|
|
address_a => std_logic_vector(to_unsigned(dispAddr,11)),
|
|
data_a => (others => '0'),
|
|
q_a => dispAttData,
|
|
wren_a => '0'
|
|
);
|
|
|
|
end generate GEN_2KATTRAM;
|
|
|
|
GEN_1KRAM: if (CHARS_PER_SCREEN <1025) generate
|
|
begin
|
|
dispCharRam: entity work.DisplayRam1K -- For 40x25 display character storage
|
|
port map
|
|
(
|
|
clock => clk,
|
|
|
|
address_b => std_logic_vector(to_unsigned(cursAddr,10)),
|
|
data_b => dispCharWRData,
|
|
q_b => dispCharRDData,
|
|
wren_b => dispWR,
|
|
|
|
address_a => std_logic_vector(to_unsigned(dispAddr,10)),
|
|
data_a => (others => '0'),
|
|
q_a => dispCharData,
|
|
wren_a => '0'
|
|
);
|
|
end generate GEN_1KRAM;
|
|
|
|
GEN_1KATTRAM: if (CHARS_PER_SCREEN <1025 and COLOUR_ATTS_ENABLED=1) generate
|
|
dispAttRam: entity work.DisplayRam1K -- For 40x25 display attribute storage
|
|
port map
|
|
(
|
|
clock => clk,
|
|
|
|
address_b => std_logic_vector(to_unsigned(cursAddr,10)),
|
|
data_b => dispAttWRData,
|
|
q_b => dispAttRDData,
|
|
wren_b => dispWR,
|
|
|
|
address_a => std_logic_vector(to_unsigned(dispAddr,10)),
|
|
data_a => (others => '0'),
|
|
q_a => dispAttData,
|
|
wren_a => '0'
|
|
);
|
|
|
|
end generate GEN_1KATTRAM;
|
|
|
|
GEN_NO_ATTRAM: if (COLOUR_ATTS_ENABLED=0) generate
|
|
|
|
dispAttData <= dispAttWRData; -- If no attribute RAM then two colour output on RGB pins as defined by default/esc sequence
|
|
|
|
end generate GEN_NO_ATTRAM;
|
|
|
|
|
|
FNkeys <= FNkeysSig;
|
|
FNtoggledKeys <= FNtoggledKeysSig;
|
|
|
|
charAddr <= dispCharData & charScanLine(VERT_PIXEL_SCANLINES+1 downto VERT_PIXEL_SCANLINES-1);
|
|
|
|
dispAddr <= (startAddr + charHoriz+(charVert * HORIZ_CHARS)) mod CHARS_PER_SCREEN;
|
|
cursAddr <= (startAddr + cursorHoriz+(cursorVert * HORIZ_CHARS)) mod CHARS_PER_SCREEN;
|
|
|
|
sync <= vSync and hSync; -- composite sync for mono video out
|
|
|
|
-- SCREEN RENDERING
|
|
|
|
process (clk)
|
|
begin
|
|
if falling_edge(clk) then
|
|
|
|
cepix <= '0';
|
|
if pixelClockCount < (CLOCKS_PER_PIXEL-1) then
|
|
pixelClockCount <= pixelClockCount+1;
|
|
else
|
|
pixelClockCount <= (others => '0');
|
|
cepix <= '1';
|
|
end if;
|
|
|
|
if horizCount < (CLOCKS_PER_SCANLINE-1) then
|
|
horizCount <= horizCount + 1;
|
|
if (horizCount < DISPLAY_LEFT_CLOCK) or (horizCount >= (DISPLAY_LEFT_CLOCK + HORIZ_CHARS*CLOCKS_PER_PIXEL*8)) then
|
|
hActive <= '0';
|
|
charHoriz <= 0;
|
|
else
|
|
hActive <= '1';
|
|
end if;
|
|
else
|
|
pixelClockCount <= (others => '0');
|
|
horizCount<= (others => '0');
|
|
pixelCount<= (others => '0');
|
|
charHoriz<= 0;
|
|
if vertLineCount > (VERT_SCANLINES-1) then
|
|
vertLineCount <= (others => '0');
|
|
else
|
|
if vertLineCount < DISPLAY_TOP_SCANLINE or vertLineCount > (DISPLAY_TOP_SCANLINE + 8 * VERT_PIXEL_SCANLINES * VERT_CHARS - 1) then
|
|
vActive <= '0';
|
|
charVert <= 0;
|
|
charScanLine <= (others => '0');
|
|
else
|
|
vActive <= '1';
|
|
if charScanLine = (VERT_PIXEL_SCANLINES*8-1) then
|
|
charScanLine <= (others => '0');
|
|
charVert <= charVert+1;
|
|
else
|
|
if vertLineCount /= DISPLAY_TOP_SCANLINE then
|
|
charScanLine <= charScanLine+1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
vertLineCount <=vertLineCount+1;
|
|
end if;
|
|
end if;
|
|
if horizCount < HSYNC_CLOCKS then
|
|
hSync <= H_SYNC_ACTIVE;
|
|
else
|
|
hSync <= not H_SYNC_ACTIVE;
|
|
end if;
|
|
if vertLineCount < VSYNC_SCANLINES then
|
|
vSync <= V_SYNC_ACTIVE;
|
|
else
|
|
vSync <= not V_SYNC_ACTIVE;
|
|
end if;
|
|
|
|
if pixelClockCount = (CLOCKS_PER_PIXEL-1) then
|
|
vBlank <= not vActive;
|
|
hBlank <= not hActive;
|
|
if hActive='1' and vActive = '1' then
|
|
|
|
if cursorOn = '1' and cursorVert = charVert and cursorHoriz = charHoriz and charScanLine = (VERT_PIXEL_SCANLINES*8-1) then
|
|
-- Cursor (use current colour because cursor cell not yet written to)
|
|
if dispAttData(3)='1' then -- BRIGHT
|
|
videoR0 <= dispAttWRData(0);
|
|
videoG0 <= dispAttWRData(1);
|
|
videoB0 <= dispAttWRData(2);
|
|
else
|
|
videoR0 <= '0';
|
|
videoG0 <= '0';
|
|
videoB0 <= '0';
|
|
end if;
|
|
videoR1 <= dispAttWRData(0);
|
|
videoG1 <= dispAttWRData(1);
|
|
videoB1 <= dispAttWRData(2);
|
|
|
|
video <= '1'; -- Monochrome video out
|
|
else
|
|
if charData(7-to_integer(unsigned(pixelCount))) = '1' then
|
|
-- Foreground
|
|
if dispAttData (3 downto 0) = "1000" then -- special case = GREY
|
|
videoR0 <= '1';
|
|
videoG0 <= '1';
|
|
videoB0 <= '1';
|
|
videoR1 <= '0';
|
|
videoG1 <= '0';
|
|
videoB1 <= '0';
|
|
else
|
|
if dispAttData(3)='1' then -- BRIGHT
|
|
videoR0 <= dispAttData(0);
|
|
videoG0 <= dispAttData(1);
|
|
videoB0 <= dispAttData(2);
|
|
else
|
|
videoR0 <= '0';
|
|
videoG0 <= '0';
|
|
videoB0 <= '0';
|
|
end if;
|
|
videoR1 <= dispAttData(0);
|
|
videoG1 <= dispAttData(1);
|
|
videoB1 <= dispAttData(2);
|
|
end if;
|
|
else
|
|
-- Background
|
|
if dispAttData (7 downto 4) = "1000" then -- special case = GREY
|
|
videoR0 <= '1';
|
|
videoG0 <= '1';
|
|
videoB0 <= '1';
|
|
videoR1 <= '0';
|
|
videoG1 <= '0';
|
|
videoB1 <= '0';
|
|
else
|
|
if dispAttData(7)='1' then -- BRIGHT
|
|
videoR0 <= dispAttData(4);
|
|
videoG0 <= dispAttData(5);
|
|
videoB0 <= dispAttData(6);
|
|
else
|
|
videoR0 <= '0';
|
|
videoG0 <= '0';
|
|
videoB0 <= '0';
|
|
end if;
|
|
videoR1 <= dispAttData(4);
|
|
videoG1 <= dispAttData(5);
|
|
videoB1 <= dispAttData(6);
|
|
end if;
|
|
end if;
|
|
video <= charData(7-to_integer(unsigned(pixelCount))); -- Monochrome video out
|
|
end if;
|
|
if pixelCount = 7 then
|
|
charHoriz <= charHoriz+1;
|
|
end if;
|
|
pixelCount <= pixelCount+1;
|
|
else
|
|
videoR0 <= '0';
|
|
videoG0 <= '0';
|
|
videoB0 <= '0';
|
|
videoR1 <= '0';
|
|
videoG1 <= '0';
|
|
videoB1 <= '0';
|
|
|
|
video <= '0'; -- Monochrome video out
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
|
|
-- Hardware cursor blink
|
|
process (clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
if cursBlinkCount < 49999999 then
|
|
cursBlinkCount <= cursBlinkCount + 1;
|
|
else
|
|
cursBlinkCount <= (others=>'0');
|
|
end if;
|
|
if cursBlinkCount < 25000000 then
|
|
cursorOn <= '0';
|
|
else
|
|
cursorOn <= '1';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
|
|
-- minimal 6850 compatibility
|
|
statusReg(0) <= '0' when kbInPointer=kbReadPointer else '1';
|
|
statusReg(1) <= '1' when dispByteWritten=dispByteSent else '0';
|
|
statusReg(2) <= '0'; --n_dcd;
|
|
statusReg(3) <= '0'; --n_cts;
|
|
statusReg(7) <= not(n_int_internal);
|
|
|
|
-- interrupt mask
|
|
n_int <= n_int_internal;
|
|
n_int_internal <= '0' when (kbInPointer /= kbReadPointer) and controlReg(7)='1'
|
|
else '0' when (dispByteWritten=dispByteSent) and controlReg(6)='0' and controlReg(5)='1'
|
|
else '1';
|
|
|
|
kbBuffCount <= 0 + kbInPointer - kbReadPointer when kbInPointer >= kbReadPointer
|
|
else 8 + kbInPointer - kbReadPointer;
|
|
n_rts <= '1' when kbBuffCount > 4 else '0';
|
|
|
|
process( n_rd )
|
|
begin
|
|
if falling_edge(n_rd) then -- Standard CPU - present data on leading edge of rd
|
|
if regSel='1' then
|
|
dataOut <= '0' & kbBuffer(kbReadPointer);
|
|
if kbInPointer /= kbReadPointer then
|
|
if kbReadPointer < 7 then
|
|
kbReadPointer <= kbReadPointer+1;
|
|
else
|
|
kbReadPointer <= 0;
|
|
end if;
|
|
end if;
|
|
else
|
|
dataOut <= statusReg;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
process( n_wr )
|
|
begin
|
|
if rising_edge(n_wr) then -- Standard CPU - capture data on trailing edge of wr
|
|
if regSel='1' then
|
|
if dispByteWritten=dispByteSent then
|
|
dispByteWritten <= not dispByteWritten;
|
|
dispByteLatch <= dataIn;
|
|
end if;
|
|
else
|
|
controlReg <= dataIn;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
|
|
-- PROCESS DATA FROM PS2 KEYBOARD
|
|
|
|
-- ps2Data <= ps2DataOut when ps2DataOut='0' else 'Z';
|
|
-- ps2Clk <= ps2ClkOut when ps2ClkOut='0' else 'Z';
|
|
|
|
-- PS2 clock de-glitcher - important because the FPGA is very sensistive
|
|
-- Filtered clock will not switch low to high until there is 50 more high samples than lows
|
|
-- hysteresis will then not switch high to low until there is 50 more low samples than highs.
|
|
-- Introduces a minor (1uS) delay with 50MHz clock
|
|
|
|
process (clk)
|
|
begin
|
|
if falling_edge(clk) then
|
|
if ps2Clk = '1' and ps2ClkFilter=50 then
|
|
ps2ClkFiltered <= '1';
|
|
end if;
|
|
if ps2Clk = '1' and ps2ClkFilter /= 50 then
|
|
ps2ClkFilter <= ps2ClkFilter+1;
|
|
end if;
|
|
if ps2Clk = '0' and ps2ClkFilter=0 then
|
|
ps2ClkFiltered <= '0';
|
|
end if;
|
|
if ps2Clk = '0' and ps2ClkFilter/=0 then
|
|
ps2ClkFilter <= ps2ClkFilter-1;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
process( clk )
|
|
-- 11 bits
|
|
-- start(0) b0 b1 b2 b3 b4 b5 b6 b7 parity(odd) stop(1)
|
|
begin
|
|
if falling_edge(clk) then
|
|
|
|
ps2PrevClk <= ps2ClkFiltered;
|
|
|
|
if n_kbWR = '0' and kbWriteTimer<25000 then
|
|
ps2WriteClkCount<= 0;
|
|
kbWRParity <= '1';
|
|
kbWriteTimer<=kbWriteTimer+1;
|
|
-- wait
|
|
elsif n_kbWR = '0' and kbWriteTimer<50000 then
|
|
ps2ClkOut <= '0';
|
|
kbWriteTimer<=kbWriteTimer+1;
|
|
elsif n_kbWR = '0' and kbWriteTimer<75000 then
|
|
ps2DataOut <= '0';
|
|
kbWriteTimer<=kbWriteTimer+1;
|
|
elsif n_kbWR = '0' and kbWriteTimer=75000 then
|
|
ps2ClkOut <= '1';
|
|
kbWriteTimer<=kbWriteTimer+1;
|
|
elsif n_kbWR = '0' and kbWriteTimer<76000 then
|
|
kbWriteTimer<=kbWriteTimer+1;
|
|
elsif n_kbWR = '1' and ps2PrevClk = '1' and ps2ClkFiltered='0' then -- start of high-to-low cleaned ps2 clock
|
|
kbWatchdogTimer<=0;
|
|
if ps2ClkCount=0 then -- start
|
|
ps2Byte <= (others =>'0');
|
|
ps2ClkCount<=ps2ClkCount+1;
|
|
elsif ps2ClkCount<9 then -- data
|
|
ps2Byte <= ps2Data & ps2Byte(7 downto 1);
|
|
ps2ClkCount<=ps2ClkCount+1;
|
|
elsif ps2ClkCount=9 then -- parity - use this time to decode
|
|
if (ps2Byte<132) then
|
|
if ps2Shift='0' then
|
|
ps2ConvertedByte <= kbUnshifted (to_integer(unsigned(ps2Byte)));
|
|
else
|
|
ps2ConvertedByte <= kbShifted (to_integer(unsigned(ps2Byte)));
|
|
end if;
|
|
else
|
|
ps2ConvertedByte <= (others => '0');
|
|
end if;
|
|
ps2ClkCount<=ps2ClkCount+1;
|
|
else -- stop bit - use this time to store
|
|
-- F-keys
|
|
if ps2ConvertedByte>x"10" and ps2ConvertedByte<x"1D" then
|
|
if ps2PreviousByte /= x"F0" then
|
|
FNtoggledKeysSig(to_integer(unsigned(ps2ConvertedByte))-16#10#) <= FNtoggledKeysSig(to_integer(unsigned(ps2ConvertedByte))-16#10#);
|
|
FNKeysSig(to_integer(unsigned(ps2ConvertedByte))-16#10#) <= '1';
|
|
else
|
|
FNKeysSig(to_integer(unsigned(ps2ConvertedByte))-16#10#) <= '0';
|
|
end if;
|
|
-- SHIFT
|
|
elsif ps2Byte = x"12" or ps2Byte=x"59" then
|
|
if ps2PreviousByte /= x"F0" then
|
|
ps2Shift <= '1';
|
|
else
|
|
ps2Shift <= '0';
|
|
end if;
|
|
-- CTRL
|
|
elsif ps2Byte = x"14" then
|
|
if ps2PreviousByte /= x"F0" then
|
|
ps2Ctrl <= '1';
|
|
else
|
|
ps2Ctrl <= '0';
|
|
end if;
|
|
-- SCROLL, CAPS AND NUM
|
|
elsif ps2Byte = x"AA" then
|
|
ps2WriteByte <= x"ED";
|
|
ps2WriteByte2(0) <= ps2Scroll;
|
|
ps2WriteByte2(1) <= ps2Num;
|
|
ps2WriteByte2(2) <= ps2Caps;
|
|
ps2WriteByte2(7 downto 3) <= "00000";
|
|
n_kbWR <= '0';
|
|
kbWriteTimer<=0;
|
|
elsif ps2Byte = x"7E" then
|
|
if ps2PreviousByte /= x"F0" then
|
|
ps2Scroll <= not ps2Scroll;
|
|
ps2WriteByte <= x"ED";
|
|
ps2WriteByte2(0) <= not ps2Scroll;
|
|
ps2WriteByte2(1) <= ps2Num;
|
|
ps2WriteByte2(2) <= ps2Caps;
|
|
ps2WriteByte2(7 downto 3) <= "00000";
|
|
n_kbWR <= '0';
|
|
kbWriteTimer<=0;
|
|
end if;
|
|
elsif ps2Byte = x"77" then
|
|
if ps2PreviousByte /= x"F0" then
|
|
ps2Num <= not ps2Num;
|
|
ps2WriteByte <= x"ED";
|
|
ps2WriteByte2(0) <= ps2Scroll;
|
|
ps2WriteByte2(1) <= not ps2Num;
|
|
ps2WriteByte2(2) <= ps2Caps;
|
|
ps2WriteByte2(7 downto 3) <= "00000";
|
|
n_kbWR <= '0';
|
|
kbWriteTimer<=0;
|
|
end if;
|
|
elsif ps2Byte = x"58" then
|
|
if ps2PreviousByte /= x"F0" then
|
|
ps2Caps <= not ps2Caps;
|
|
ps2WriteByte <= x"ED";
|
|
ps2WriteByte2(0) <= ps2Scroll;
|
|
ps2WriteByte2(1) <= ps2Num;
|
|
ps2WriteByte2(2) <= not ps2Caps;
|
|
ps2WriteByte2(7 downto 3) <= "00000";
|
|
n_kbWR <= '0';
|
|
kbWriteTimer<=0;
|
|
end if;
|
|
-- ACK
|
|
elsif ps2Byte = x"FA" then
|
|
if ps2WriteByte /= x"FF" then
|
|
n_kbWR <= '0';
|
|
kbWriteTimer<=0;
|
|
end if;
|
|
-- ASCII CHARACTER
|
|
elsif (ps2PreviousByte /= x"F0") and (ps2ConvertedByte /= x"00") then
|
|
if ps2PreviousByte = x"E0" and ps2Byte = x"71" then -- DELETE
|
|
kbBuffer(kbInPointer) <= "1111111"; -- 7F
|
|
elsif ps2Ctrl = '1' then
|
|
kbBuffer(kbInPointer) <= "00" & ps2ConvertedByte(4 downto 0);
|
|
elsif ps2ConvertedByte > x"40" and ps2ConvertedByte < x"5B" and ps2Caps='1' then
|
|
kbBuffer(kbInPointer) <= ps2ConvertedByte or "0100000";
|
|
elsif ps2ConvertedByte > x"60" and ps2ConvertedByte < x"7B" and ps2Caps='1' then
|
|
kbBuffer(kbInPointer) <= ps2ConvertedByte and "1011111";
|
|
else
|
|
kbBuffer(kbInPointer) <= ps2ConvertedByte;
|
|
end if;
|
|
if kbInPointer < 7 then
|
|
kbInPointer <= kbInPointer+1;
|
|
else
|
|
kbInPointer <= 0;
|
|
end if;
|
|
end if;
|
|
ps2PreviousByte<=ps2Byte;
|
|
ps2ClkCount<=0;
|
|
end if;
|
|
|
|
-- write to keyboard
|
|
elsif n_kbWR = '0' and ps2PrevClk = '1' and ps2ClkFiltered='0' then -- start of high-to-low cleaned ps2 clock
|
|
kbWatchdogTimer<=0;
|
|
if ps2WriteClkCount <8 then
|
|
if (ps2WriteByte(ps2WriteClkCount)='1') then
|
|
ps2DataOut <= '1';
|
|
kbWRParity <= not kbWRParity;
|
|
else
|
|
ps2DataOut <= '0';
|
|
end if;
|
|
ps2WriteClkCount<=ps2WriteClkCount+1;
|
|
elsif ps2WriteClkCount = 8 then
|
|
ps2DataOut <= kbWRParity;
|
|
ps2WriteClkCount<=ps2WriteClkCount+1;
|
|
elsif ps2WriteClkCount = 9 then
|
|
ps2WriteClkCount<=ps2WriteClkCount+1;
|
|
ps2DataOut <= '1';
|
|
elsif ps2WriteClkCount = 10 then
|
|
ps2WriteByte <= ps2WriteByte2;
|
|
ps2WriteByte2 <= x"FF";
|
|
n_kbWR<= '1';
|
|
ps2WriteClkCount <= 0;
|
|
ps2DataOut <= '1';
|
|
|
|
end if;
|
|
else
|
|
-- COMMUNICATION ERROR
|
|
-- if no edge then increment the timer
|
|
-- if a large time has elapsed since the last pulse was read then
|
|
-- re-sync the keyboard
|
|
if kbWatchdogTimer>30000000 then
|
|
kbWatchdogTimer<=0;
|
|
ps2ClkCount<=0;
|
|
if n_kbWR = '0' then
|
|
ps2WriteByte <= x"ED";
|
|
ps2WriteByte2(0) <= ps2Scroll;
|
|
ps2WriteByte2(1) <= ps2Num;
|
|
ps2WriteByte2(2) <= ps2Caps;
|
|
ps2WriteByte2(7 downto 3) <= "00000";
|
|
kbWriteTimer<=0;
|
|
end if;
|
|
else
|
|
kbWatchdogTimer<=kbWatchdogTimer+1;
|
|
end if;
|
|
end if;
|
|
|
|
end if;
|
|
end process;
|
|
|
|
|
|
-- PROCESS DATA WRITTEN TO DISPLAY
|
|
|
|
process( clk , n_reset)
|
|
begin
|
|
|
|
if n_reset='0' then
|
|
dispAttWRData <= DEFAULT_ATT;
|
|
elsif falling_edge(clk) then
|
|
case dispState is
|
|
when idle =>
|
|
if (nextState/=processingAdditionalParams) and (dispByteWritten /= dispByteSent) then
|
|
dispCharWRData <= dispByteLatch;
|
|
dispByteSent <= not dispByteSent;
|
|
end if;
|
|
if (dispByteWritten /= dispByteSent) or (nextState=processingAdditionalParams) then
|
|
if dispByteLatch = x"07" then -- BEEP
|
|
-- do nothing - ignore
|
|
elsif dispByteLatch = x"1B" then -- ESC
|
|
paramCount<=0;
|
|
param1<=0;
|
|
param2<=0;
|
|
param3<=0;
|
|
param4<=0;
|
|
nextState<= waitForLeftBracket;
|
|
elsif nextState=waitForLeftBracket and dispByteLatch=x"5B" then-- ESC[
|
|
nextState<= processingParams;
|
|
paramCount<=1;
|
|
elsif paramCount=1 and dispByteLatch=x"48" and param1=0 then -- ESC[H
|
|
cursorVert <= 0;
|
|
cursorHoriz <= 0;
|
|
paramCount<=0;
|
|
elsif paramCount=1 and dispByteLatch=x"4B" and param1=0 then -- ESC[K - erase EOL
|
|
dispState <= clearLine;
|
|
paramCount<=0;
|
|
elsif paramCount=1 and dispByteLatch=x"73" and param1=0 then -- ESC[s - save cursor pos
|
|
savedCursorHoriz <= cursorHoriz;
|
|
savedCursorVert <= cursorVert;
|
|
paramCount<=0;
|
|
elsif paramCount=1 and dispByteLatch=x"75" and param1=0 then -- ESC[u - restore cursor pos
|
|
cursorHoriz <= savedCursorHoriz;
|
|
cursorVert <= savedCursorVert;
|
|
paramCount<=0;
|
|
elsif paramCount>0 and dispByteLatch=x"3B" then-- ESC[{param1};{param2}...
|
|
paramCount<=paramCount+1;
|
|
elsif paramCount>0 and dispByteLatch>x"2F" and dispByteLatch<x"3A" then -- numeric
|
|
if paramCount=1 then -- ESC[{param1}
|
|
param1 <= param1 * 10 + (to_integer(unsigned(dispByteLatch))-48);
|
|
elsif paramCount=2 then -- ESC[{param1};{param2}
|
|
param2 <= param2 * 10 + (to_integer(unsigned(dispByteLatch))-48);
|
|
elsif paramCount=3 then -- ESC[{param1};{param2};{param3}
|
|
param3 <= param3 * 10 + (to_integer(unsigned(dispByteLatch))-48);
|
|
elsif paramCount=4 then -- ESC[{param1};{param2};{param3};{param4}
|
|
param4 <= param4 * 10 + (to_integer(unsigned(dispByteLatch))-48);
|
|
end if;
|
|
elsif paramCount=1 and param1=2 and dispByteLatch=x"4A" then-- ESC[2J - clear screen
|
|
cursorVert <= 0;
|
|
cursorHoriz <= 0;
|
|
cursorVertRestore <= 0;
|
|
cursorHorizRestore <= 0;
|
|
dispState <= clearScreen;
|
|
paramCount<=0;
|
|
elsif paramCount=1 and param1=0 and dispByteLatch=x"4A" then-- ESC[0J or ESC[J - clear from cursor to end of screen
|
|
cursorVertRestore <= cursorVert;
|
|
cursorHorizRestore <= cursorHoriz;
|
|
dispState <= clearScreen;
|
|
paramCount<=0;
|
|
elsif paramCount =1 and dispByteLatch=x"4C" then-- ESC[L - insert line
|
|
cursorVertRestore <= cursorVert;
|
|
cursorHorizRestore <= cursorHoriz;
|
|
cursorHoriz <= HORIZ_CHAR_MAX;
|
|
cursorVert <= VERT_CHAR_MAX-1;
|
|
dispState <= insertLine;
|
|
paramCount<=0;
|
|
elsif paramCount =1 and dispByteLatch=x"4D" then-- ESC[M - delete line
|
|
cursorVertRestore <= cursorVert;
|
|
cursorHorizRestore <= cursorHoriz;
|
|
cursorHoriz <= 0;
|
|
cursorVert <= cursorVert+1;
|
|
dispState <= deleteLine;
|
|
paramCount<=0;
|
|
elsif paramCount>0 and dispByteLatch=x"6D" then-- ESC[{param1}m or ESC[{param1};{param2}m- set graphics rendition
|
|
if param1 = 0 then
|
|
attInverse <= '0';
|
|
attBold <= ANSI_DEFAULT_ATT(3);
|
|
dispAttWRData <= ANSI_DEFAULT_ATT;
|
|
end if;
|
|
if param1 = 1 then
|
|
attBold <= '1';
|
|
-- if attInverse='0' then
|
|
dispAttWRData(3) <= '1';
|
|
-- else
|
|
-- dispAttWRData(7) <= '1';
|
|
-- end if;
|
|
end if;
|
|
if param1 = 22 then
|
|
attBold <= '0';
|
|
-- if attInverse='0' then
|
|
dispAttWRData(3) <= '0';
|
|
-- else
|
|
-- dispAttWRData(7) <= '0';
|
|
-- end if;
|
|
end if;
|
|
if param1 = 7 then
|
|
if attInverse = '0' then
|
|
attInverse <= '1';
|
|
dispAttWRData(7 downto 4) <= dispAttWRData(3 downto 0);
|
|
dispAttWRData(3 downto 0) <= dispAttWRData(7 downto 4);
|
|
end if;
|
|
end if;
|
|
if param1 = 27 then
|
|
if attInverse = '1' then
|
|
attInverse <= '0';
|
|
dispAttWRData(7 downto 4) <= dispAttWRData(3 downto 0);
|
|
dispAttWRData(3 downto 0) <= dispAttWRData(7 downto 4);
|
|
end if;
|
|
end if;
|
|
if param1 > 29 and param1 < 38 then
|
|
if attInverse = '0' then
|
|
dispAttWRData(2 downto 0) <=std_logic_vector(to_unsigned(param1-30,3));
|
|
dispAttWRData(3) <= attBold;
|
|
else
|
|
dispAttWRData(6 downto 4) <=std_logic_vector(to_unsigned(param1-30,3));
|
|
dispAttWRData(7) <= attBold;
|
|
end if;
|
|
end if;
|
|
if param1 > 39 and param1 < 48 then
|
|
if attInverse = '0' then
|
|
dispAttWRData(6 downto 4) <=std_logic_vector(to_unsigned(param1-40,3));
|
|
dispAttWRData(7) <= attBold;
|
|
else
|
|
dispAttWRData(2 downto 0) <=std_logic_vector(to_unsigned(param1-40,3));
|
|
dispAttWRData(3) <= attBold;
|
|
end if;
|
|
end if;
|
|
if param1 > 89 and param1 < 98 then
|
|
if attInverse = '0' then
|
|
dispAttWRData(2 downto 0) <=std_logic_vector(to_unsigned(param1-90,3));
|
|
dispAttWRData(3) <= '1';
|
|
else
|
|
dispAttWRData(6 downto 4) <=std_logic_vector(to_unsigned(param1-90,3));
|
|
dispAttWRData(7) <= '1';
|
|
end if;
|
|
end if;
|
|
if param1 > 99 and param1 < 108 then
|
|
if attInverse = '0' then
|
|
dispAttWRData(6 downto 4) <=std_logic_vector(to_unsigned(param1-100,3));
|
|
dispAttWRData(7) <= '1';
|
|
else
|
|
dispAttWRData(2 downto 0) <=std_logic_vector(to_unsigned(param1-100,3));
|
|
dispAttWRData(3) <= '1';
|
|
end if;
|
|
end if;
|
|
-- allow for second parameter - must process individually and in sequence
|
|
if paramCount>1 then
|
|
param1 <= param2;
|
|
param2 <= param3;
|
|
param3 <= param4;
|
|
paramCount<=paramCount-1;
|
|
nextState <= processingAdditionalParams;
|
|
else
|
|
paramCount<=0;
|
|
nextState <= none;
|
|
end if;
|
|
elsif paramCount=1 and dispByteLatch=x"41" then-- ESC[{param1}A - Cursor up
|
|
if param1=0 and cursorVert>0 then -- no param to default to 1
|
|
cursorVert<=cursorVert-1;
|
|
elsif param1<cursorVert then
|
|
cursorVert<=cursorVert-param1;
|
|
else
|
|
cursorVert<=0;
|
|
end if;
|
|
paramCount<=0;
|
|
elsif paramCount=1 and dispByteLatch=x"42" then-- ESC[{param1}B - Cursor down
|
|
if param1=0 and cursorVert<VERT_CHAR_MAX then -- no param to default to 1
|
|
cursorVert<=cursorVert+1;
|
|
elsif (cursorVert+param1)<VERT_CHAR_MAX then
|
|
cursorVert<=cursorVert+param1;
|
|
else
|
|
cursorVert<=VERT_CHAR_MAX;
|
|
end if;
|
|
paramCount<=0;
|
|
elsif paramCount=1 and dispByteLatch=x"43" then-- ESC[{param1}C - Cursor forward
|
|
if param1=0 and cursorHoriz<HORIZ_CHAR_MAX then -- no param to default to 1
|
|
cursorHoriz<=cursorHoriz+1;
|
|
elsif (cursorHoriz+param1)<HORIZ_CHAR_MAX then
|
|
cursorHoriz<=cursorHoriz+param1;
|
|
else
|
|
cursorHoriz<=HORIZ_CHAR_MAX;
|
|
end if;
|
|
paramCount<=0;
|
|
elsif paramCount=1 and dispByteLatch=x"44" then-- ESC[{param1}D - Cursor backward
|
|
if param1=0 and cursorHoriz>0 then -- no param to default to 1
|
|
cursorHoriz<=cursorHoriz-1;
|
|
elsif param1<cursorHoriz then
|
|
cursorHoriz<=cursorHoriz-param1;
|
|
else
|
|
cursorHoriz <= 0;
|
|
end if;
|
|
paramCount<=0;
|
|
elsif paramCount=2 and dispByteLatch=x"48" then -- ESC[{param1};{param2}H
|
|
if param1<1 then
|
|
cursorVert <= 0;
|
|
elsif param1>VERT_CHARS then
|
|
cursorVert <= VERT_CHARS-1;
|
|
else
|
|
cursorVert <= param1-1;
|
|
end if;
|
|
if param2<0 then
|
|
cursorHoriz <= 0;
|
|
elsif param2>HORIZ_CHARS then
|
|
cursorHoriz <= HORIZ_CHARS-1;
|
|
else
|
|
cursorHoriz <= param2-1;
|
|
end if;
|
|
paramCount<=0;
|
|
else
|
|
dispState <= dispWrite;
|
|
nextState <= none;
|
|
paramCount<=0;
|
|
end if;
|
|
end if;
|
|
when dispWrite =>
|
|
if dispCharWRData=13 then
|
|
cursorHoriz <= 0;
|
|
dispState<=idle;
|
|
elsif dispCharWRData=10 then
|
|
if cursorVert<VERT_CHAR_MAX then
|
|
cursorVert <= cursorVert+1;
|
|
dispState<=idle;
|
|
else
|
|
if startAddr < (CHARS_PER_SCREEN - HORIZ_CHARS) then
|
|
startAddr <= startAddr + HORIZ_CHARS;
|
|
else
|
|
startAddr <= 0;
|
|
end if;
|
|
cursorHorizRestore <= cursorHoriz;
|
|
cursorVertRestore <= cursorVert;
|
|
dispState<=clearLine;
|
|
end if;
|
|
elsif dispCharWRData=12 then
|
|
cursorVert <= 0;
|
|
cursorHoriz <= 0;
|
|
cursorHorizRestore <= 0;
|
|
cursorVertRestore <= 0;
|
|
dispState<=clearScreen;
|
|
elsif dispCharWRData=8 or dispCharWRData=127 then
|
|
if cursorHoriz>0 then
|
|
cursorHoriz <= cursorHoriz-1;
|
|
elsif cursorHoriz=0 and cursorVert>0 then
|
|
cursorHoriz <=HORIZ_CHAR_MAX;
|
|
cursorVert <= cursorVert-1;
|
|
end if;
|
|
dispState<=clearChar;
|
|
else
|
|
dispWR <= '1';
|
|
dispState<=dispNextLoc;
|
|
end if;
|
|
when dispNextLoc =>
|
|
dispWR <= '0';
|
|
if (cursorHoriz<HORIZ_CHAR_MAX) then
|
|
cursorHoriz<=cursorHoriz+1;
|
|
dispState <=idle;
|
|
else
|
|
cursorHoriz <= 0;
|
|
if cursorVert<VERT_CHAR_MAX then
|
|
cursorVert <= cursorVert+1;
|
|
dispState <=idle;
|
|
else
|
|
if startAddr < (CHARS_PER_SCREEN - HORIZ_CHARS) then
|
|
startAddr <= startAddr + HORIZ_CHARS;
|
|
else
|
|
startAddr <= 0;
|
|
end if;
|
|
cursorHorizRestore <= 0;
|
|
cursorVertRestore <= cursorVert;
|
|
dispState<=clearLine;
|
|
end if;
|
|
end if;
|
|
when clearLine =>
|
|
dispCharWRData <= x"20";
|
|
dispWR <= '1';
|
|
dispState <= clearL2;
|
|
when clearL2 =>
|
|
dispWR <= '0';
|
|
if (cursorHoriz<HORIZ_CHAR_MAX) then
|
|
cursorHoriz<=cursorHoriz+1;
|
|
dispState <= clearLine;
|
|
else
|
|
cursorHoriz<=cursorHorizRestore;
|
|
cursorVert<=cursorVertRestore;
|
|
dispState<=idle;
|
|
end if;
|
|
when clearChar =>
|
|
dispCharWRData <= x"20";
|
|
dispWR <= '1';
|
|
dispState <= clearC2;
|
|
when clearC2 =>
|
|
dispWR <= '0';
|
|
dispState<=idle;
|
|
when clearScreen =>
|
|
dispCharWRData <= x"20";
|
|
dispWR <= '1';
|
|
dispState <= clearS2;
|
|
when clearS2 =>
|
|
dispWR <= '0';
|
|
if (cursorHoriz<HORIZ_CHAR_MAX) then
|
|
cursorHoriz<=cursorHoriz+1;
|
|
dispState <= clearScreen;
|
|
else
|
|
if (cursorVert<VERT_CHAR_MAX) then
|
|
cursorHoriz<=0;
|
|
cursorVert<=cursorVert+1;
|
|
dispState<=clearScreen;
|
|
else
|
|
cursorHoriz<=cursorHorizRestore;
|
|
cursorVert<=cursorVertRestore;
|
|
dispState<=idle;
|
|
end if;
|
|
end if;
|
|
when insertLine =>
|
|
dispCharWRData <= dispCharRDData;
|
|
dispAttWRData <= dispAttRDData;
|
|
cursorVert <= cursorVert+1;
|
|
dispState <= ins2;
|
|
when ins2 =>
|
|
dispWR <= '1';
|
|
dispState <= ins3;
|
|
when ins3 =>
|
|
dispWR <= '0';
|
|
if cursorHoriz = 0 and cursorVert = cursorVertRestore+1 then
|
|
cursorVert <= cursorVertRestore;
|
|
dispState <= clearLine;
|
|
elsif cursorHoriz>0 then
|
|
cursorHoriz <= cursorHoriz-1;
|
|
cursorVert <= cursorVert-1;
|
|
dispState <= insertLine;
|
|
else
|
|
cursorHoriz <= HORIZ_CHAR_MAX;
|
|
cursorVert <= cursorVert-2;
|
|
dispState <= insertLine;
|
|
end if;
|
|
when deleteLine =>
|
|
dispCharWRData <= dispCharRDData;
|
|
dispAttWRData <= dispAttRDData;
|
|
cursorVert <= cursorVert-1;
|
|
dispState <= del2;
|
|
when del2 =>
|
|
dispWR <= '1';
|
|
dispState <= del3;
|
|
when del3 =>
|
|
dispWR <= '0';
|
|
if cursorHoriz = HORIZ_CHAR_MAX and cursorVert = VERT_CHAR_MAX-1 then
|
|
cursorHoriz <= 0;
|
|
cursorVert <= VERT_CHAR_MAX;
|
|
dispState <= clearLine;
|
|
elsif cursorHoriz<HORIZ_CHAR_MAX then
|
|
cursorHoriz <= cursorHoriz+1;
|
|
cursorVert <= cursorVert+1;
|
|
dispState <= deleteLine;
|
|
else
|
|
cursorHoriz <= 0;
|
|
cursorVert <= cursorVert+2;
|
|
dispState <= deleteLine;
|
|
end if;
|
|
end case;
|
|
end if;
|
|
end process;
|
|
|
|
end rtl;
|