-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbitio_ipop.vhd
151 lines (126 loc) · 4.4 KB
/
bitio_ipop.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
-------------------------------------------------------------------------------
--
-- Title Modular VHDL peripheral
-- https://github.com/the-moog/vhdl_modular_blocks
-- File bitio_ipop.vhd
-- Author Jason Morgan
--
-- Copyright © Jason Morgan 2018
-- License This work is licensed under a Creative Commons Attribution-NoDerivatives 4.0 International License.
-- CC-BY-ND, see LICENSE.TXT
--
-------------------------------------------------------------------------------
--
-- Date 17/7/2018
-- Version 2
--
-- ChangeLog
-- =========
-- Version By Date Change
--
-- 1 J A Morgan 2009 Initial version
-- 2 J A Morgan 17/7/18 Updated to VHDL2008
--
-------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_lOGIC_ARITH.all;
use work.utils.setall;
use work.utils.log2;
use work.types.all;
use work.modules.all;
/*!
@brief MODULAR PERIPHERAL: An arbitrary input and output register bank.
@details This is an example of a typical modular bus peripheral<BR>
Implements a bank of registered inputs and outputs
<BR>
All peripherals have the same bus interface, but an atbitrary bus size
*/
entity bitio_ipop is
generic (npins : integer := 16);
port (
clk : in std_logic;
rst : in std_logic;
module : in module_t;
addr : in std_logic_vector;
data : inout std_logic_vector; --Sampled on the rising edge of clk
ip_pins : in std_logic_vector(npins - 1 downto 0);
op_pins : out std_logic_vector(npins - 1 downto 0);
size : out positive;
cs : in std_logic; --Module enable active high, sampled on the rising edge of clk
rd_nwr : in std_logic); --Read/not Write
end entity;
/*!
@brief Typical implementation of a modular bus peripheral
@details Note now the data bus and address bus are of arbitrary size
*/
architecture behavior of bitio_ipop is
type std_lv_array is array (natural range <>) of std_logic_vector(data'length - 1 downto 0);
constant ZZZ : std_logic_vector(data'length - 1 downto 0) := (others => 'Z');
constant nbanks : integer := log2(npins / data'length);
signal rd_data : std_logic_vector(data'length - 1 downto 0);
signal ip_reg : std_lv_array(0 to nbanks - 1);
signal op_reg : std_lv_array(0 to nbanks - 1);
constant sizei : positive := nbanks; --need to use an intermediate constant here to keep synplicity happy
constant addrbits : positive := log2(sizei);
begin
data <= rd_data when rd_nwr = '1' and cs = '1' else ZZZ;
size <= sizei;
do_read : process (all) is
variable address : unsigned(addrbits - 1 downto 0);
variable bank : integer;
variable nbit : integer;
begin
address := unsigned(addr(address'range)) - module.base;
bank := conv_integer(address);
rd_data <= (others => '0');
if bank < nbanks then
rd_data <= ip_reg(bank);
end if;
end process;
do_write : process(all) is
variable address : unsigned(addrbits - 1 downto 0);
variable bank : integer;
variable nbit : integer;
begin
address := unsigned(addr(address'range)) - module.base;
if rst = '1' then
for bank in 0 to nbanks - 1 loop
--TODO: Reset value
op_reg(bank) <= (others => '0');
end loop;
elsif rising_edge(clk) then --Process regs on rising edge
--Handle write
bank := conv_integer(address);
if cs = '1' and bank < nbanks and rd_nwr = '0' then
op_reg(bank) <= data;
end if;
end if;
end process;
do_op : process (all)
variable bank : integer;
variable nbit : integer;
begin
for pin in op_pins'range loop
bank := pin / data'length;
nbit := pin mod data'length;
op_pins(pin) <= op_reg(bank)(nbit);
end loop;
end process;
do_input : process(clk, rst, ip_pins)
variable bank : integer;
variable nbit : integer;
begin
if rst = '1' then
for bank in 0 to nbanks - 1 loop
ip_reg(bank) <= (others => '0');
end loop;
elsif falling_edge(clk) then --Process pins on falling
for pin in ip_pins'range loop
bank := pin / data'length;
nbit := pin mod data'length;
ip_reg(bank)(nbit) <= ip_pins(pin);
end loop;
end if;
end process;
end architecture;