|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
在下面这个程序里,只有2个命令 Clear(CL)和Load(LD),如何才能实现Set Address命令 使得可以下载数据到任意一个想要的地址呀? 还有怎么才能实现Left Shift(LT)和Right Shift(RT)呢??
初学VHDL实在是不会
-------------------------------------------------------------------------------
-- MessageReceiver.vhd
-------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
entity MessageReceiver is
port (
Clock: in std_logic; -- Synchronous system clock, 50MHz
Reset: in std_logic; -- Synchronous system reset, active high
RXD: in std_logic; -- RS232 serial receive signal
usr_data: out std_logic_vector(7 downto 0); -- 8-bit data to send to the LCD driver
usr_data_ncmd: out std_logic; -- = '1' if usr_data carries a character, '0' if command
usr_write: out std_logic; -- LCD write enable signal, active high, one clock cycle in width
usr_busy: in std_logic -- Busy signal from the LCD driver, active high
);
end MessageReceiver;
architecture MessageReceiver_arch of MessageReceiver is
-- component declarations
component dpram128x8
port (
addra: IN std_logic_VECTOR(6 downto 0);
addrb: IN std_logic_VECTOR(6 downto 0);
clka: IN std_logic;
clkb: IN std_logic;
dina: IN std_logic_VECTOR(7 downto 0);
doutb: OUT std_logic_VECTOR(7 downto 0);
enb: IN std_logic;
wea: IN std_logic);
end component;
component Rs232Rxd
port(
Reset, Clk, Rxd: in std_logic;
DataEn: out std_logic;
Data: out std_logic_vector (7 downto 0));
end component;
-- Internal signals
-- DPRAM interface signals
signal iBufWriteAddress, iBufReadAddress: std_logic_vector (6 downto 0);
signal iBufReadData: std_logic_vector (7 downto 0);
signal iBufReadEnable: std_logic;
-- 8-bit array signal of size 3 to detect a valid message header
type LcdActionType is array(2 downto 0) of std_logic_vector(7 downto 0);
signal iLcdOperation: LcdActionType;
signal iRs232DataEnable, iCmdEnd: std_logic;
signal iRs232Data: std_logic_vector (7 downto 0);
-- State definition for the state machine of the message pre-processing
type stateTypeMSG is (stIdleMSG, stReadBufMSG, stLoadDataMSG);
signal presStateMSG: stateTypeMSG;
signal nextStateMSG: stateTypeMSG;
signal iBufReadEnableMSG: std_logic;
signal iClearMSG, iLoadDataMSG: std_logic;
signal iBufReadAddressMSG: std_logic_vector (6 downto 0);
-- State definition for the 'Clear' state machine
type stateTypeCL is (stIdleCL, stClearWaitCL, stCursorCL, stCursorWaitCL);
signal presStateCL: stateTypeCL;
signal nextStateCL: stateTypeCL;
signal iLcdDataCL: std_logic_vector (7 downto 0);
signal iLcdDataValidCL, iLcdWriteCL: std_logic;
-- State definition for the 'Load' state machine
type stateTypeLD is (stIdleLD, stLocateSpaceLD, stSendCmdLD, stWaitLD);
signal presStateLD: stateTypeLD;
signal nextStateLD: stateTypeLD;
signal iLcdDataLD: std_logic_vector (7 downto 0);
signal iLcdDataValidLD, iLcdWriteLD, iBufReadEnableLD, iRstBufReadAddressLD, iIncBufReadAddressLD: std_logic;
signal iBufReadAddressLD: std_logic_vector (6 downto 0);
begin
-- RS232 Receiver
Rs232Receiver: RS232Rxd
port map (
Reset => Reset,
Clk => Clock,
Rxd => RXD,
DataEn => iRs232DataEnable,
Data => iRs232Data);
-- Generate write address to write received RS232RxD data to the dual-port RAM
-- The address is increased by one every cycle while the RS232 data enable signal is valid
-- and reset when an <Enter> character is received.
PROC_WRITE_ADDRESS: process (Clock)
begin
if rising_edge(Clock) then
if (Reset = '1' or iCmdEnd = '1') then
iBufWriteAddress <= (others=>'0');
elsif iRs232DataEnable = '1' then
iBufWriteAddress <= iBufWriteAddress + 1;
end if;
end if;
end process;
-- Instance of the Dual-Port RAM(DPRAM) component created from Xilinx core generator
-- Port A: Write the data received from RS232RxD
-- Port B: Read out the data for message processing
--
-- Data written to the DPRAM is in ASCII coding
-- Two Message commands have been defined and implemented in the basic message display design:
-- 'CL<Enter>' - to clear the LCD screen
-- 'LD xyz<Enter>' - to display string 'xyz' from the current position
-- of the cursor on the LCD screen.
-- Messages are always terminated by a <Enter> (or X"0D") character.
-- Only one message can be stored in the DPRAM.
--
RxdBuffer: dpram128x8
port map (
addra => iBufWriteAddress,
addrb => iBufReadAddress,
clka => Clock,
clkb => Clock,
dina => iRs232Data,
doutb => iBufReadData,
enb => iBufReadEnable,
wea => iRs232DataEnable);
-- A multiplexer for the read address of the DPRAM.
-- In the basic message display design, the read address is routed to
-- the read address generated in the 'MSG' state machine
-- when the 'message' state machine takes control of reading the DPRAM, otherwise,
-- it is routed to the read address generated in in the 'LOAD' state machine
iBufReadAddress <= iBufReadAddressMSG when (iBufReadEnableMSG = '1') else
iBufReadAddressLD;
-- The DPRAM read enable signls will be valid whenver any state machine needs to read the DPRAM.
-- In the basic message display design, only two state machines of 'MSG' and 'LOAD' needs to access the DPRAM
iBufReadEnable <= iBufReadEnableMSG or iBufReadEnableLD;
-- A process to detect the end of a message or when received an <Enter> character
PROC_CMD_END: process (Clock)
begin
if rising_edge(Clock) then
if iRs232Data = x"0D" and iRs232DataEnable = '1' then
iCmdEnd <= '1';
else
iCmdEnd <= '0';
end if;
end if;
end process;
-- MSG state machine to pre-process the message read out from the DPRAM,
SM_MSG_SYNC: process (Clock)
begin
if rising_edge(Clock) then
-- State transaction
if Reset = '1' then
presStateMSG <= stIdleMSG;
else
presStateMSG <= nextStateMSG;
end if;
-- The DPRAM read address generation
if (Reset= '1' or iCmdEnd = '1') then
iBufReadAddressMSG <= (others => '0');
elsif iBufReadEnableMSG = '1' then
iBufReadAddressMSG <= iBufReadAddressMSG + 1;
end if;
-- A shifter to remember 3 last characters (used to detect a valid message header)
if iBufReadEnableMSG = '1' then
iLcdOperation <= iLcdOperation(1 downto 0) & iBufReadData;
end if;
end if;
end process;
SM_MSG_ASYNC: process (presStateMSG, iCmdEnd, iLcdOperation, iBufReadData)
begin
-- Signal defaults
iBufReadEnableMSG <= '0';
iClearMSG <= '0';
iLoadDataMSG <= '0';
-- State actions
case presStateMSG is
-- IDLE -> wait until a whole message is written to the DPRAM (ended with <Enter>)
when stIdleMSG =>
if iCmdEnd = '1' then
nextStateMSG <= stReadBufMSG;
else
nextStateMSG <= stIdleMSG;
end if;
-- Read the DPRAM until three continual characters match the pre-defined message header
when stReadBufMSG =>
iBufReadEnableMSG <= '1';
-- Test if they match 'CL<Enter>'
if iLcdOperation = (x"43", x"4C", x"0D") then
iClearMSG <= '1'; -- Issue 'Clear' pulse
nextStateMSG <= stIdleMSG;
-- Test if they match 'LD '
elsif iLcdOperation = (x"4C", x"44", x"20") then
nextStateMSG <= stLoadDataMSG;
else
nextStateMSG <= stReadBufMSG;
end if;
-- Keep reading the DPRAM until it reaches <enter>
when stLoadDataMSG =>
iBufReadEnableMSG <= '1';
if iBufReadData = x"0D" then
iLoadDataMSG <= '1'; -- Issue 'Load' pulse
nextStateMSG <= stIdleMSG;
else
nextStateMSG <= stLoadDataMSG;
end if;
end case;
end process;
-- CLEAR State machine for Clear operation
SM_CLEAR_SYNC: process (Clock)
begin
if rising_edge(Clock) then
-- State transaction
if Reset = '1' then
presStateCL <= stIdleCL;
else
presStateCL <= nextStateCL;
end if;
end if;
end process;
SM_CLEAR_ASYNC: process (presStateCL, iClearMSG, usr_busy)
begin
-- Signal defaults
iLcdDataValidCL <= '0';
iLcdDataCL <= x"00";
iLcdWriteCL <= '0';
-- State actions
case presStateCL is
-- Wait for a 'Clear' pulse from MSG state machine
when stIdleCL =>
if iClearMSG = '1' then
iLcdDataValidCL <= '1'; -- Take control of the LCD data bus
iLcdDataCL <= x"01"; -- Output "Clear Display" command to the LCD data bus
iLcdWriteCL <= '1'; -- Set LCD Write signal
nextStateCL <= stClearWaitCL;
else
nextStateCL <= stIdleCL;
end if;
-- Wait while the LCD driver is busy
when stClearWaitCL =>
if usr_busy = '0' then
nextStateCL <= stCursorCL;
else
nextStateCL <= stClearWaitCL;
end if;
-- Set "Display On/Off" to:
-- (1) "Display character stored in DD RAM"
-- (2) "Display cursor"
-- (3) "Cursor blinks on and off approximately every half second"
when stCursorCL =>
iLcdDataValidCL <= '1'; -- Take control of the LCD data bus
iLcdDataCL <= x"0F"; -- Output "Display On/Off" command to the LCD data bus
iLcdWriteCL <= '1'; -- Set LCD Write signal
nextStateCL <= stCursorWaitCL;
-- Wait while the LCD driver is busy
when stCursorWaitCL =>
if usr_busy = '0' then
nextStateCL <= stIdleCL;
else
nextStateCL <= stCursorWaitCL;
end if;
end case;
end process;
-- LOAD state machine for Load Data operation
-- to read data from the DPRAM and then
-- send them to the LCD driver.
SM_LOAD_SYNC: process (Clock)
begin
if rising_edge(Clock) then
-- State transaction
if Reset = '1' then
presStateLD <= stIdleLD;
else
presStateLD <= nextStateLD;
end if;
-- Read address counter
if iRstBufReadAddressLD = '1' then
iBufReadAddressLD <= (others=>'0');
elsif iIncBufReadAddressLD = '1' then
iBufReadAddressLD <= iBufReadAddressLD + 1;
end if;
end if;
end process;
SM_LOAD_DATA_ASYNC: process (presStateLD, iLoadDataMSG, iBufReadData, usr_busy)
begin
-- Signal defaults
iLcdDataValidLD <= '0';
iRstBufReadAddressLD <= '0';
iIncBufReadAddressLD <= '0';
iLcdDataLD <= x"00";
iLcdWriteLD <= '0';
iBufReadEnableLD <= '0';
-- State actions
case presStateLD is
-- Wait for a 'Load' pulse from MSG state machine
when stIdleLD =>
if iLoadDataMSG = '1' then
iLcdDataValidLD <= '1';
iBufReadEnableLD <= '1'; -- Read the first character (should be 'L')
iIncBufReadAddressLD <= '1'; -- Reset read address to the DPRAM
nextStateLD <= stLocateSpaceLD;
else
iRstBufReadAddressLD <= '1';
nextStateLD <= stIdleLD;
end if;
-- Skip the message header ('LD ')
when stLocateSpaceLD =>
iLcdDataValidLD <= '1';
iBufReadEnableLD <= '1'; -- Read out next character from the DPRAM
iIncBufReadAddressLD <= '1'; -- Increase address to next memory location
if iBufReadData = x"20" then
nextStateLD <= stSendCmdLD;
else
nextStateLD <= stLocateSpaceLD;
end if;
-- Send read data to the LCD driver
when stSendCmdLD =>
iLcdDataValidLD <= '1';
iBufReadEnableLD <= '1';
iLcdDataLD <= iBufReadData;
iLcdWriteLD <= '1';
nextStateLD <= stWaitLD;
-- Wait while the LCD driver is busy and
-- then read out next character from the DPRAM until reaching an <Enter>
when stWaitLD =>
iLcdDataValidLD <= '1';
iBufReadEnableLD <= '1';
if usr_busy = '0' then
iIncBufReadAddressLD <= '1';
nextStateLD <= stSendCmdLD;
if iBufReadData = x"0D" then
nextStateLD <= stIdleLD;
end if;
else
nextStateLD <= stWaitLD;
end if;
end case;
end process;
-- Only LOAD state machine needs to set usr_data_ncmd to HIGH to indicate that
-- it is a data session NOT a command session, in other words, so it is simply driven by LOAD state machine only.
usr_data_ncmd <= iLcdDataValidLD;
-- Any state machine that needs to control the LCD driver can produce
-- its own LCD write signal to access the LCD driver.
-- In the basic message display design, the LCD write signals generated from
-- both 'CLEAR' state machine and 'LOAD' state machine are or-ed and routed to usr_write
usr_write <= iLcdWriteCL or iLcdWriteLD;
-- A multiplexer for usr_data of the LCD driver.
-- In the basic message display design, usr_data is routed to
-- the LCD data generated in the 'CLEAR' state machine
-- when the 'CLEAR' state machine takes control of the LCD driver, otherwise,
-- it is routed to the LCD data generated in in the 'LOAD' state machine
usr_data <= iLcdDataCL when (iLcdDataValidCL = '1') else
iLcdDataLD;
end MessageReceiver_arch; |
|