mirror of
https://github.com/wfjm/w11.git
synced 2026-05-04 15:16:59 +00:00
168 lines
6.1 KiB
VHDL
168 lines
6.1 KiB
VHDL
-- $Id: sn_7segctl.vhd 984 2018-01-02 20:56:27Z mueller $
|
|
--
|
|
-- Copyright 2007-2015 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
|
|
--
|
|
-- This program is free software; you may redistribute and/or modify it under
|
|
-- the terms of the GNU General Public License as published by the Free
|
|
-- Software Foundation, either version 3, or (at your option) any later version.
|
|
--
|
|
-- This program is distributed in the hope that it will be useful, but
|
|
-- WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
|
|
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
-- for complete details.
|
|
--
|
|
------------------------------------------------------------------------------
|
|
-- Module Name: sn_7segctl - syn
|
|
-- Description: 7 segment display controller (for s3board,nexys,basys)
|
|
--
|
|
-- Dependencies: -
|
|
-- Test bench: -
|
|
-- Target Devices: generic
|
|
-- Tool versions: ise 8.2-14.7; viv 2014.4; ghdl 0.18-0.31
|
|
--
|
|
-- Synthesized (xst):
|
|
-- Date Rev ise Target flop lutl lutm slic t peri
|
|
-- 2015-01-24 637 14.7 131013 xc6slx16-2 9 27 0 16 s 3.1 ns DC=3
|
|
-- 2015-01-24 637 14.7 131013 xc6slx16-2 8 19 0 9 s 3.1 ns DC=2
|
|
-- 2015-01-24 410 14.7 131013 xc6slx16-2 8 19 0 8 s 3.1 ns
|
|
|
|
-- Revision History:
|
|
-- Date Rev Version Comment
|
|
-- 2015-01-24 637 1.3 renamed from sn_4x7segctl; add DCWIDTH,
|
|
-- allow 4(DC=2) or 8(DC=3) digit display
|
|
-- 2011-09-17 410 1.2.1 now numeric_std clean
|
|
-- 2011-07-30 400 1.2 digit dark in last quarter (not 16 clocks)
|
|
-- 2011-07-08 390 1.1.2 renamed from s3_dispdrv
|
|
-- 2010-04-17 278 1.1.1 renamed from dispdrv
|
|
-- 2010-03-29 272 1.1 add all ANO off time to allow to driver turn-off
|
|
-- delay and to avoid cross talk between digits
|
|
-- 2007-12-16 101 1.0.1 use _N for active low
|
|
-- 2007-09-16 83 1.0 Initial version
|
|
------------------------------------------------------------------------------
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
use work.slvtypes.all;
|
|
|
|
entity sn_7segctl is -- 7 segment display controller
|
|
generic (
|
|
DCWIDTH : positive := 2; -- digit counter width (2 or 3)
|
|
CDWIDTH : positive := 6); -- clk divider width (must be >= 5)
|
|
port (
|
|
CLK : in slbit; -- clock
|
|
DIN : in slv(4*(2**DCWIDTH)-1 downto 0); -- data 16 or 32
|
|
DP : in slv((2**DCWIDTH)-1 downto 0); -- decimal points 4 or 8
|
|
ANO_N : out slv((2**DCWIDTH)-1 downto 0); -- anodes (act.low) 4 or 8
|
|
SEG_N : out slv8 -- segements (act.low)
|
|
);
|
|
end sn_7segctl;
|
|
|
|
architecture syn of sn_7segctl is
|
|
type regs_type is record
|
|
cdiv : slv(CDWIDTH-1 downto 0); -- clock divider counter
|
|
dcnt : slv(DCWIDTH-1 downto 0); -- digit counter
|
|
end record regs_type;
|
|
|
|
constant regs_init : regs_type := (
|
|
slv(to_unsigned(0,CDWIDTH)), -- cdiv
|
|
slv(to_unsigned(0,DCWIDTH)) -- dcnt
|
|
);
|
|
|
|
type hex2segtbl_type is array (0 to 15) of slv7;
|
|
|
|
constant hex2segtbl : hex2segtbl_type :=
|
|
("0111111", -- 0: "0000"
|
|
"0000110", -- 1: "0001"
|
|
"1011011", -- 2: "0010"
|
|
"1001111", -- 3: "0011"
|
|
"1100110", -- 4: "0100"
|
|
"1101101", -- 5: "0101"
|
|
"1111101", -- 6: "0110"
|
|
"0000111", -- 7: "0111"
|
|
"1111111", -- 8: "1000"
|
|
"1101111", -- 9: "1001"
|
|
"1110111", -- a: "1010"
|
|
"1111100", -- b: "1011"
|
|
"0111001", -- c: "1100"
|
|
"1011110", -- d: "1101"
|
|
"1111001", -- e: "1110"
|
|
"1110001" -- f: "1111"
|
|
);
|
|
|
|
signal R_REGS : regs_type := regs_init; -- state registers
|
|
signal N_REGS : regs_type := regs_init; -- next value state regs
|
|
signal CHEX : slv4 := (others=>'0'); -- current hex number
|
|
signal CDP : slbit := '0'; -- current decimal point
|
|
|
|
begin
|
|
|
|
assert DCWIDTH=2 or DCWIDTH=3
|
|
report "assert(DCWIDTH=2 or DCWIDTH=3): unsupported DCWIDTH"
|
|
severity failure;
|
|
|
|
assert CDWIDTH >= 5
|
|
report "assert(CDWIDTH >= 5): CDWIDTH too small"
|
|
severity failure;
|
|
|
|
proc_regs: process (CLK)
|
|
begin
|
|
|
|
if rising_edge(CLK) then
|
|
R_REGS <= N_REGS;
|
|
end if;
|
|
|
|
end process proc_regs;
|
|
|
|
|
|
proc_next: process (R_REGS, CHEX, CDP)
|
|
|
|
variable r : regs_type := regs_init;
|
|
variable n : regs_type := regs_init;
|
|
variable cano : slv((2**DCWIDTH)-1 downto 0) := (others=>'0');
|
|
|
|
begin
|
|
|
|
r := R_REGS;
|
|
n := R_REGS;
|
|
|
|
n.cdiv := slv(unsigned(r.cdiv) - 1);
|
|
if unsigned(r.cdiv) = 0 then
|
|
n.dcnt := slv(unsigned(r.dcnt) + 1);
|
|
end if;
|
|
|
|
-- the logic below ensures that the anode PNP driver transistor is switched
|
|
-- off in the last quarter of the digit cycle.This prevents 'cross talk'
|
|
-- between digits due to transistor turn off delays.
|
|
-- For a nexys2 board at 50 MHz observed:
|
|
-- no or 4 cycles gap well visible cross talk
|
|
-- with 8 cycles still some weak cross talk
|
|
-- with 16 cycles none is visible.
|
|
-- --> The turn-off delay of the anode driver PNP's this therefore
|
|
-- larger 160 ns and below 320 ns.
|
|
-- As consquence CDWIDTH should be at least 6 for 50 MHz and 7 for 100 MHz.
|
|
|
|
cano := (others=>'1');
|
|
if r.cdiv(CDWIDTH-1 downto CDWIDTH-2) /= "00" then
|
|
cano(to_integer(unsigned(r.dcnt))) := '0';
|
|
end if;
|
|
|
|
N_REGS <= n;
|
|
|
|
ANO_N <= cano;
|
|
SEG_N <= not (CDP & hex2segtbl(to_integer(unsigned(CHEX))));
|
|
|
|
end process proc_next;
|
|
|
|
proc_mux: process (R_REGS, DIN, DP)
|
|
begin
|
|
CDP <= DP(to_integer(unsigned(R_REGS.dcnt)));
|
|
CHEX(0) <= DIN(0+4*to_integer(unsigned(R_REGS.dcnt)));
|
|
CHEX(1) <= DIN(1+4*to_integer(unsigned(R_REGS.dcnt)));
|
|
CHEX(2) <= DIN(2+4*to_integer(unsigned(R_REGS.dcnt)));
|
|
CHEX(3) <= DIN(3+4*to_integer(unsigned(R_REGS.dcnt)));
|
|
end process proc_mux;
|
|
|
|
end syn;
|