It appears that my proposed SD Card interface is pushing the limits of the small CPLD I am planning to use.
My initial VHDL was:
Code: Select all
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity Z180_EC_Util_CPLD is
port (
data : inout std_logic_vector(7 downto 0);
addr : in std_logic_vector(7 downto 0);
rd, wr, iorq, phi, reset : in std_logic;
cs_fpu, rst_fpu, fpu_clk, cs_rtc, as_rtc : out std_logic;
sd_mosi : out std_logic;
sd_clk, sd_cs, sd_pull : buffer std_logic;
sd_miso : in std_logic
);
end Z180_EC_Util_CPLD;
architecture behaviour of Z180_EC_Util_CPLD is
constant port_rtc_addr : std_logic_vector(7 downto 0) := X"42";
constant port_rtc_data : std_logic_vector(7 downto 0) := X"43";
constant port_fpu_data : std_logic_vector(7 downto 0) := X"44";
constant port_fpu_rst : std_logic_vector(7 downto 0) := X"45";
constant port_sd_data : std_logic_vector(7 downto 0) := X"46";
constant port_sd_ctrl : std_logic_vector(7 downto 0) := X"47";
signal fpu_cnt : std_logic_vector (2 downto 0);
signal sel_sd_data : std_logic;
signal sel_sd_ctrl : std_logic;
signal sd_auto : std_logic := '0';
signal sd_once : std_logic := '0';
signal sd_arm : std_logic := '0';
signal sd_run : std_logic := '0';
signal sd_out : std_logic_vector(7 downto 0);
signal sd_in : std_logic_vector(8 downto 0);
begin
-- IO Decoding
cs_rtc <= iorq when ( addr = port_rtc_data ) else '1';
as_rtc <= ( iorq nor wr ) when ( addr = port_rtc_addr ) else '0';
cs_fpu <= iorq when ( addr = port_fpu_data ) else '1';
process (iorq, wr, addr, data)
begin
if ( ( iorq = '0' ) and ( wr = '0' ) and ( addr = port_fpu_rst ) ) then
rst_fpu <= data(0);
end if;
end process;
-- FPU Clock
process (phi)
begin
if ( falling_edge (phi) ) then
fpu_cnt <= fpu_cnt + 1;
end if;
end process;
fpu_clk <= fpu_cnt(2);
-- SPI control register
sel_sd_data <= iorq when ( addr = port_sd_data ) else '1';
sel_sd_ctrl <= iorq when ( addr = port_sd_ctrl ) else '1';
process (wr, sel_sd_ctrl, data, reset)
begin
if ( reset = '0' ) then
sd_cs <= '0';
sd_pull <= '0';
sd_auto <= '0';
elsif ( ( sel_sd_ctrl = '1' ) and ( wr = '0' ) ) then
sd_cs <= data(0);
sd_pull <= data(1);
sd_auto <= data(2);
end if;
end process;
-- Arm SPI transfer: Always after a write (sd_once) or conditional (sd_auto) after a read
sd_clk <= sd_run and phi;
process (sel_sd_data, wr, sd_clk, reset)
begin
if ( ( sd_clk = '1' ) or ( reset = '0' ) ) then
sd_once <= '0';
elsif ( ( sel_sd_data = '0' ) and ( wr = '0' ) ) then
sd_once <= '1';
end if;
end process;
process (sel_sd_data, sd_clk, reset)
begin
if ( ( sd_clk = '1' ) or ( reset = '0' ) ) then
sd_arm <= '0';
elsif ( rising_edge (sel_sd_data) ) then
sd_arm <= sd_once or sd_auto;
end if;
end process;
-- Run byte transfer from next low clock
process (phi, sd_arm, sd_in, reset)
begin
if ( reset = '0' ) then
sd_run <= '0';
elsif ( falling_edge (phi) ) then
sd_run <= sd_arm or ( not sd_in(8) );
end if;
end process;
-- Output bits on falling clock edge
process (sd_clk, sel_sd_data, wr, data)
begin
if ( ( sel_sd_data = '0' ) and ( wr = '0' ) ) then
sd_out <= data;
elsif ( falling_edge (sd_clk) ) then
sd_out(6 downto 0) <= sd_out(7 downto 1);
sd_out(7) <= '1';
end if;
end process;
sd_mosi <= sd_out(0);
-- Input bits on rising clock edge
process (sd_clk, sd_arm, sd_run, sd_miso)
begin
if ( ( sd_arm = '1' ) and ( sd_run = '0' ) ) then
-- Transfer will stop when '1' is shifted into high bit.
sd_in <= "000000001";
elsif ( rising_edge (sd_clk) ) then
sd_in(8 downto 1) <= sd_in (7 downto 0);
sd_in(0) <= sd_miso;
end if;
end process;
-- Read SPI data and control registers
data <= sd_in(7 downto 0) when ( ( rd = '0' ) and ( sel_sd_data = '0' ) ) else
( 0 => sd_cs, 1 => sd_pull, 2 => sd_auto, 3 => sd_once,
4 => sd_arm, 5 => sd_run, 6 => '0', 7 => sd_miso )
when ( ( rd = '0' ) and ( sel_sd_ctrl = '0' ) ) else
( others => 'Z' );
end behaviour;
However, attempting to compile that fails with:
Code: Select all
Fitter Status Failed
Quartus II 64-Bit Version 13.0.1 Build 232 06/12/2013 SP 1 SJ Web Edition
Revision Name Z180_EC_Util_CPLD
Top-level Entity Name Z180_EC_Util_CPLD
Family MAX7000S
Device EPM7032SLC44-10
Timing Models Final
Total macrocells 42 / 32 ( 131 % )
Total pins 32 / 36 ( 89 % )
Overcommitted by 31%

The obvious first thing to try removing is the divider for the FPU clock. That can be replaced by a single external divide by 8 counter. That gives:
Code: Select all
Flow Status Flow Failed
:
Total macrocells 39 / 32 ( 122 % )
Total pins 31 / 36 ( 86 % )
As is perhaps expected, removing a 3-bit counter saves 3 macrocells. Not enough
The above VHDL includes the ability to read back a number of internal status bits. The only one of these which is essential is the state of the MISO pin. So, simplifying this bit of the VHDL to:
Code: Select all
data <= sd_in(7 downto 0) when ( ( rd = '0' ) and ( sel_sd_data = '0' ) ) else
( 7 => sd_miso, others => 'Z' ) when ( ( rd = '0' ) and ( sel_sd_ctrl = '0' ) ) else
( others => 'Z' );
Gets closer:
Code: Select all
Fitter Status Failed - Sun Oct 06 09:51:43 2019
:
Total macrocells 32 / 32 ( 100 % )
Total pins 34 / 36 ( 94 % )
Error (163105): Cannot route source node "addr[3]" of type max_io to destination node "sd_out[3]" of type max_mcell
Just enough macrocells, but it appears that I cannot order the pins in the way I intended

After some experimentation with the pin assignments:
Code: Select all
Fitter Status Successful
:
Total macrocells 32 / 32 ( 100 % )
Total pins 34 / 36 ( 94 % )
Pin Name/Usage : Location : Dir. : I/O Standard : Voltage : I/O Bank : User Assignment
-------------------------------------------------------------------------------------------------------------
reset : 1 : input : TTL : : : Y
iorq : 2 : input : TTL : : : Y
VCC : 3 : power : : : :
data[0] : 4 : bidir : TTL : : : Y
data[1] : 5 : bidir : TTL : : : Y
data[2] : 6 : bidir : TTL : : : Y
TDI : 7 : input : TTL : : : N
data[3] : 8 : bidir : TTL : : : Y
data[4] : 9 : bidir : TTL : : : Y
GND : 10 : gnd : : : :
data[5] : 11 : bidir : TTL : : : Y
data[6] : 12 : bidir : TTL : : : Y
TMS : 13 : input : TTL : : : N
data[7] : 14 : bidir : TTL : : : Y
VCC : 15 : power : : : :
sd_cs : 16 : output : TTL : : : Y
sd_clk : 17 : output : TTL : : : Y
sd_mosi : 18 : output : TTL : : : Y
RESERVED : 19 : : : : :
sd_pull : 20 : output : TTL : : : Y
rst_fpu : 21 : output : TTL : : : Y
GND : 22 : gnd : : : :
VCC : 23 : power : : : :
addr[0] : 24 : input : TTL : : : Y
addr[1] : 25 : input : TTL : : : Y
addr[2] : 26 : input : TTL : : : Y
addr[3] : 27 : input : TTL : : : Y
addr[4] : 28 : input : TTL : : : Y
addr[5] : 29 : input : TTL : : : Y
GND : 30 : gnd : : : :
addr[6] : 31 : input : TTL : : : Y
TCK : 32 : input : TTL : : : N
addr[7] : 33 : input : TTL : : : Y
sd_miso : 34 : input : TTL : : : Y
VCC : 35 : power : : : :
RESERVED : 36 : : : : :
cs_fpu : 37 : output : TTL : : : Y
TDO : 38 : output : TTL : : : N
as_rtc : 39 : output : TTL : : : Y
cs_rtc : 40 : output : TTL : : : Y
wr : 41 : input : TTL : : : Y
GND : 42 : gnd : : : :
phi : 43 : input : TTL : : : Y
rd : 44 : input : TTL : : : Y
Success
It will be necessary to redo the board design to include a divider chip for the FPU clock, and the revised pin ordering.
The lack of remaining capacity complicates adding anything else to this board. Seperate I/O decoding will probably be required. Of course it would be possible to replace the EPM7032, by a EPM7128, but that seems excessive.
Any comments or sugestions as to how the VHDL or the pin asignments might be improved most welcome.