diff --git a/cores/KypSpectrum/clock.vhd b/cores/KypSpectrum/clock.vhd index a5e193d..4fea559 100644 --- a/cores/KypSpectrum/clock.vhd +++ b/cores/KypSpectrum/clock.vhd @@ -7,10 +7,11 @@ library unisim; entity clock is port ( - clock50 : in std_logic; - clock14 : out std_logic; -- 14.000 MHz - clock70 : out std_logic; -- 7.000 MHz - clock35 : out std_logic -- 3.500 Mhz + clock50 : in std_logic; + clock14 : out std_logic; -- 14.000 MHz + clock700 : out std_logic; -- 7.000 MHz + clock350 : out std_logic; -- 3.500 Mhz + clock175 : out std_logic -- 1.750 Mhz ); end; @@ -19,14 +20,16 @@ architecture behavioral of clock is signal cfb : std_logic; signal c50 : std_logic; signal c14 : std_logic; - signal count : std_logic_vector(1 downto 0); + signal count : std_logic_vector(2 downto 0); begin Uibufg : ibufg port map(i => clock50, o => c50); Uclock14 : bufg port map(i => c14, o => clock14); - Uclock70 : bufg port map(i => count(0), o => clock70); - Uclock35 : bufg port map(i => count(1), o => clock35); + Uclock700 : bufg port map(i => count(0), o => clock700); + Uclock350 : bufg port map(i => count(1), o => clock350); + clock175 <= count(2); +-- Uclock175 : bufg port map(i => count(2), o => clock175); uclock : pll_base generic map diff --git a/cores/KypSpectrum/keyboard.vhd b/cores/KypSpectrum/keyboard.vhd index 679fe7a..1d5e5e9 100644 --- a/cores/KypSpectrum/keyboard.vhd +++ b/cores/KypSpectrum/keyboard.vhd @@ -183,7 +183,7 @@ begin ( keys(51) or rows(4) ); -- DOWN(7) nmi <= keys(54); - boot <= keys(57); + boot <= keys(57) and ((keys(40) and keys(47)) or (keys(41) and keys(48)) or (keys(43))); reset <= keys(55) and ((keys(40) and keys(47)) or (keys(41) and keys(48)) or (keys(42) and keys(49))); end; diff --git a/cores/KypSpectrum/mixer.vhd b/cores/KypSpectrum/mixer.vhd index cf1349d..7b615b6 100644 --- a/cores/KypSpectrum/mixer.vhd +++ b/cores/KypSpectrum/mixer.vhd @@ -7,9 +7,12 @@ entity mixer is ( clock : in std_logic; reset : in std_logic; + speaker : in std_logic; ear : in std_logic; mic : in std_logic; - speaker : in std_logic; + a : in std_logic_vector(7 downto 0); + b : in std_logic_vector(7 downto 0); + c : in std_logic_vector(7 downto 0); l : out std_logic; r : out std_logic ); @@ -17,22 +20,13 @@ end; architecture behavioral of mixer is - signal src : std_logic_vector(2 downto 0); - signal ula : std_logic_vector(7 downto 0); - signal mix : std_logic_vector(7 downto 0); + signal src : std_logic_vector(2 downto 0); + signal ula : std_logic_vector(7 downto 0); + signal mixl : std_logic_vector(7 downto 0); + signal mixr : std_logic_vector(7 downto 0); begin - process(clock) - variable tmp : std_logic_vector(3 downto 0) := (others => '0'); - begin - if falling_edge(clock) - then - tmp := tmp+1; - if tmp = 0 then mix <= ula; else mix <= (others => '0'); end if; - end if; - end process; - src <= ear&mic&speaker; ula <= x"11" when src = "000" else x"24" when src = "010" @@ -43,18 +37,35 @@ begin else x"F4" when src = "101" else x"FF"; + process(clock) + variable tmp : std_logic_vector(1 downto 0) := (others => '0'); + begin + if falling_edge(clock) + then + case tmp is + when "00" => mixl <= a; mixr <= b; + when "01" => mixl <= c; mixr <= c; + when "10" => mixl <= a; mixr <= b; + when "11" => mixl <= ula; mixr <= ula; + when others => + end case; + + tmp := tmp+1; + end if; + end process; + UdacL: entity work.dac port map ( clock => clock, reset => reset, - i => mix, + i => mixl, o => l ); UdacR: entity work.dac port map ( clock => clock, reset => reset, - i => mix, + i => mixr, o => r ); diff --git a/cores/KypSpectrum/ula.vhd b/cores/KypSpectrum/ula.vhd index f791c92..3893a8b 100644 --- a/cores/KypSpectrum/ula.vhd +++ b/cores/KypSpectrum/ula.vhd @@ -6,12 +6,15 @@ entity ula is port ( cpuClock : in std_logic; + mreq : in std_logic; iorq : in std_logic; rd : in std_logic; wr : in std_logic; a0 : in std_logic; + aP : in std_logic; di : in std_logic_vector( 7 downto 0); do : out std_logic_vector( 7 downto 0); + cpuEnable : out std_logic; -- vramClock : in std_logic; vramData : in std_logic_vector( 7 downto 0); @@ -55,7 +58,7 @@ architecture behavioral of ula is signal dataOut : std_logic_vector(7 downto 0); signal attrInp : std_logic_vector(7 downto 0); - signal attrMux : std_logic_vector(7 downto 3); + signal attrMux : std_logic_vector(7 downto 0); signal attrOut : std_logic_vector(7 downto 0); signal dataEnable : std_logic; @@ -70,6 +73,11 @@ architecture behavioral of ula is signal dataSelect : std_logic; + signal cancelContention : std_logic := '1'; + signal causeContention : std_logic; + signal mayContend : std_logic; + signal iorequla : std_logic; + begin Ups2 : entity work.ps2 port map @@ -95,23 +103,19 @@ begin begin if falling_edge(cpuClock) then - do <= attrOut; - - if iorq = '0' and a0 = '0' + if iorq = '0' and a0 = '0' and wr = '0' then - if wr = '0' - then - border <= di(2 downto 0); - mic <= di(3); - speaker <= di(4); - elsif rd = '0' - then - do <= '0'&ear&'0'&keys; - end if; + border <= di(2 downto 0); + mic <= di(3); + speaker <= di(4); end if; end if; end process; + do <= '1'&(not ear)&'1'&keys when iorq = '0' and rd = '0' and a0 = '0' + else vramData when iorq = '0' and rd = '0' and (dataInpLoad = '1' or attrInpLoad = '1') + else x"FF"; + process(vramClock) begin if falling_edge(vramClock) @@ -131,42 +135,35 @@ begin end if; end if; - if hCount >= 344 and hCount <= 375 then hSync <= '0'; else hSync <= '1'; end if; - if vCount >= 248 and vCount <= 251 then vSync <= '0'; else vSync <= '1'; end if; + if dataInpLoad = '1' then dataInp <= vramData; end if; + if attrInpLoad = '1' then attrInp <= vramData; end if; + + if dataOutLoad = '1' then dataOut <= dataInp; else dataOut <= dataOut(6 downto 0)&'0'; end if; + if attrOutLoad = '1' then attrOut <= attrMux; end if; + + if hCount(3) = '1' then videoEnable <= dataEnable; end if; if vCount = 248 and hCount >= 2 and hCount <= 65 then int <= '0'; else int <= '1'; end if; end if; end process; - process(vramClock) - begin - if falling_edge(vramClock) - then - dataInpLoad <= hCount(0) and not hCount(1) and hCount(3) and videoEnable; - dataOutLoad <= not hCount(0) and not hCount(1) and hCount(2) and videoEnable; + hSync <= '0' when hCount >= 344 and hCount <= 375 else '1'; + vSync <= '0' when vCount >= 248 and vCount <= 251 else '1'; - attrInpLoad <= hCount(0) and hCount(1) and hCount(3) and videoEnable; - attrOutLoad <= hCount(0) and not hCount(1) and hCount(2); + dataInpLoad <= '1' when videoEnable = '1' and (hCount(3 downto 0) = 9 or hCount(3 downto 0) = 13) else '0'; + attrInpLoad <= '1' when videoEnable = '1' and (hCount(3 downto 0) = 11 or hCount(3 downto 0) = 15) else '0'; - dataSelect <= dataOut(7) xor (fCount(4) and attrOut(7)); + dataOutLoad <= '1' when videoEnable = '1' and hCount(2 downto 0) = 4 else '0'; + attrOutLoad <= '1' when hCount(2 downto 0) = 4 else '0'; - if hCount(3) = '1' then videoEnable <= dataEnable; end if; - if hCount < 256 and vCount < 192 then dataEnable <= '1'; else dataEnable <= '0'; end if; - if (hCount >= 320 and hCount <= 415) or (vCount >= 248 and vCount <= 255) then videoBlank <= '1'; else videoBlank <= '0'; end if; + dataSelect <= dataOut(7) xor (fCount(4) and attrOut(7)); + attrMux <= attrInp when videoEnable = '1' else "00"&border&"000"; - if dataInpLoad = '1' then dataInp <= vramData; end if; - if dataOutLoad = '1' then dataOut <= dataInp; else dataOut <= dataOut(6 downto 0)&'0'; end if; + dataEnable <= '1' when hCount < 256 and vCount < 192 else '0'; + videoBlank <= '1' when (hCount >= 320 and hCount <= 415) or (vCount >= 248 and vCount <= 255) else '0'; - if attrInpLoad = '1' then attrInp <= vramData; end if; - if attrOutLoad = '1' then attrOut <= attrMux&attrInp(2 downto 0); end if; - - if videoEnable = '1' then attrMux(7 downto 3) <= attrInp(7 downto 3); else attrMux(7 downto 3) <= "00"&border; end if; - - vramAddr( 7 downto 0) <= vCount(5 downto 3)&hCount(7 downto 4)&hCount(2); - if hCount(1) = '0' then vramAddr(12 downto 8) <= vCount(7 downto 6)&vCount(2 downto 0); else vramAddr(12 downto 8) <= "110"&vCount(7 downto 6); end if; - - end if; - end process; + vramAddr( 7 downto 0) <= vCount(5 downto 3)&hCount(7 downto 4)&hCount(2); + vramAddr(12 downto 8) <= vCount(7 downto 6)&vCount(2 downto 0) when hCount(1) = '0' else "110"&vCount(7 downto 6); v <= vSync; h <= hSync; @@ -175,4 +172,17 @@ begin b <= '0' when videoBlank = '1' else attrOut(0) when dataSelect = '1' else attrOut(3); i <= '0' when videoBlank = '1' else attrOut(6); + process(cpuClock) + begin + if falling_edge(cpuClock) + then + if mreq = '0' or iorequla = '0' then cancelContention <= '0'; else cancelContention <= '1'; end if; + end if; + end process; + + causeContention <= '0' when aP = '1' or iorequla = '0' else '1'; + mayContend <= '0' when hCount(3 downto 0) > 3 and dataEnable = '1' else '1'; + iorequla <= iorq or a0; + cpuEnable <= mayContend or causeContention or cancelContention; + end; diff --git a/cores/KypSpectrum/zxkyp.ucf b/cores/KypSpectrum/zxkyp.ucf new file mode 100644 index 0000000..724f571 --- /dev/null +++ b/cores/KypSpectrum/zxkyp.ucf @@ -0,0 +1,93 @@ +# +# +# + +# LED ######################################################################### + +NET "led" LOC="P11" | IOSTANDARD = LVCMOS33; + +# Clock ####################################################################### + +NET "clock50" LOC="P55" | IOSTANDARD = LVCMOS33 | PERIOD=20ns; + +# SRAM ######################################################################## + +NET "sramWr" LOC="P121" | IOSTANDARD = LVCMOS33 | SLEW=FAST; + +NET "sramData<7>" LOC="P126" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramData<6>" LOC="P119" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramData<5>" LOC="P117" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramData<4>" LOC="P115" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramData<3>" LOC="P123" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramData<2>" LOC="P124" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramData<1>" LOC="P127" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramData<0>" LOC="P132" | IOSTANDARD = LVCMOS33 | SLEW=FAST; + +#NET "sramAddr<20>" LOC="P143" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +#NET "sramAddr<19>" LOC="P105" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<18>" LOC="P142" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<17>" LOC="P140" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<16>" LOC="P138" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<15>" LOC="P131" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<14>" LOC="P111" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<13>" LOC="P100" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<12>" LOC="P101" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<11>" LOC="P102" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<10>" LOC="P104" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<9>" LOC="P112" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<8>" LOC="P114" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<7>" LOC="P116" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<6>" LOC="P118" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<5>" LOC="P120" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<4>" LOC="P133" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<3>" LOC="P134" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<2>" LOC="P137" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<1>" LOC="P139" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +NET "sramAddr<0>" LOC="P141" | IOSTANDARD = LVCMOS33 | SLEW=FAST; + +# Video ####################################################################### + +NET "videoRgb<8>" LOC="P81" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # R<2> +NET "videoRgb<7>" LOC="P80" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # R<1> +NET "videoRgb<6>" LOC="P79" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # R<0> +NET "videoRgb<5>" LOC="P84" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # G<2> +NET "videoRgb<4>" LOC="P83" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # G<1> +NET "videoRgb<3>" LOC="P82" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # G<0> +NET "videoRgb<2>" LOC="P93" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # B<2> +NET "videoRgb<1>" LOC="P92" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # B<1> +NET "videoRgb<0>" LOC="P88" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # B<0> + +NET "videoSync<1>" LOC="P85" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # vs +NET "videoSync<0>" LOC="P87" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # hs + +NET "videoStdn<1>" LOC="P66" | IOSTANDARD = LVCMOS33; # stdn <= "10" NTSC +NET "videoStdn<0>" LOC="P67" | IOSTANDARD = LVCMOS33; # stdn <= "01" PAL + +# Audio ####################################################################### + +NET "ear" LOC="P94" | IOSTANDARD = LVCMOS33 | SLEW=FAST; + +NET "audio<0>" LOC="P10" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # left +NET "audio<1>" LOC="P9" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # right + +# PS/2 ######################################################################## + +NET "ps2<0>" LOC="P99" | IOSTANDARD = LVCMOS33 | SLEW=FAST | PULLUP; # keyboard clock +NET "ps2<1>" LOC="P98" | IOSTANDARD = LVCMOS33 | SLEW=FAST | PULLUP; # keyboard data + +# SD/MMC ###################################################################### + +NET "sdClock" LOC="P75" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # clock +NET "sdCs" LOC="P59" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # cs +NET "sdDi" LOC="P74" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # di +NET "sdDo" LOC="P78" | IOSTANDARD = LVCMOS33 | SLEW=FAST; # do + +# SPI Flash ################################################################### + +#NET "flash_clk" LOC="P70" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +#NET "flash_cs" LOC="P38" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +#NET "flash_si" LOC="P64" | IOSTANDARD = LVCMOS33 | SLEW=FAST; +#NET "flash_so" LOC="P65" | IOSTANDARD = LVCMOS33 | SLEW=FAST; + +#NET "flash_ext1" LOC="P62" | IOSTANDARD = LVCMOS33; +#NET "flash_ext2" LOC="P61" | IOSTANDARD = LVCMOS33; diff --git a/cores/KypSpectrum/zxkyp.vhd b/cores/KypSpectrum/zxkyp.vhd index 0d52846..16d4d25 100644 --- a/cores/KypSpectrum/zxkyp.vhd +++ b/cores/KypSpectrum/zxkyp.vhd @@ -1,6 +1,8 @@ library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; +library unisim; + use unisim.vcomponents.all; entity zxkyp is port @@ -31,8 +33,9 @@ end; architecture structural of zxkyp is signal clock14 : std_logic; - signal clock70 : std_logic; - signal clock35 : std_logic; + signal clock700 : std_logic; + signal clock350 : std_logic; + signal clock175 : std_logic; signal boot : std_logic; @@ -48,6 +51,10 @@ architecture structural of zxkyp is signal data : std_logic_vector( 7 downto 0); signal addr : std_logic_vector(15 downto 0); + signal aP : std_logic; + signal cpuEnable : std_logic; + signal cpuClock : std_logic; + signal v : std_logic; signal h : std_logic; signal r : std_logic; @@ -85,6 +92,14 @@ architecture structural of zxkyp is signal sdAc : std_logic; signal sdData : std_logic_vector( 7 downto 0); + signal ayCs : std_logic; + signal ayBc : std_logic; + signal ayBdir : std_logic; + signal ayData : std_logic_vector( 7 downto 0); + signal ayA : std_logic_vector( 7 downto 0); + signal ayB : std_logic_vector( 7 downto 0); + signal ayC : std_logic_vector( 7 downto 0); + begin Umultiboot : entity work.multiboot port map @@ -96,12 +111,13 @@ begin ( clock50 => clock50, clock14 => clock14, - clock70 => clock70, - clock35 => clock35 + clock700 => clock700, + clock350 => clock350, + clock175 => clock175 ); Ucpu : entity work.tv80n port map ( - clk => clock35, + clk => cpuClock, reset_n => reset, wait_n => pause, mreq_n => mreq, @@ -121,15 +137,18 @@ begin ); Uula : entity work.ula port map ( - cpuClock => clock35, + cpuClock => clock350, + mreq => mreq, iorq => iorq, rd => rd, wr => wr, a0 => addr(0), + aP => aP, di => cpuData, do => ulaData, + cpuEnable => cpuEnable, -- - vramClock => clock70, + vramClock => clock700, vramData => vramData, vramAddr => vramAddr, int => int, @@ -152,7 +171,7 @@ begin ); Udiv : entity work.div port map ( - clock => clock35, + clock => clock350, reset => reset, mreq => mreq, iorq => iorq, @@ -169,24 +188,27 @@ begin ); Umixer: entity work.mixer port map ( - clock => clock35, + clock => clock350, reset => reset, speaker => speaker, ear => ear, mic => mic, + a => ayA, + b => ayB, + c => ayC, l => audio(0), r => audio(1) ); Urom : entity work.rom port map ( - clka => clock35, + clka => clock350, ena => romCs, douta => romData, addra => addr(13 downto 0) ); Udrom : entity work.drom port map ( - clka => clock35, + clka => clock350, ena => dromCs, douta => dromData, addra => addr(12 downto 0) @@ -204,13 +226,13 @@ begin ); Uvram : entity work.vram port map ( - clka => clock35, + clka => clock350, ena => vramCs, wea(0) => vramWe, dina => cpuData, addra => addr(12 downto 0), -- - clkb => clock70, + clkb => clock700, doutb => vramData, addrb => vramAddr ); @@ -231,18 +253,43 @@ begin sdDi => sdDi, sdDo => sdDo ); + Uay8910 : entity work.ay8910 port map + ( + CLK => clock350, + CLC => clock175, + RESET => reset, + BDIR => ayBdir, + CS => ayCs, + BC => addr(14), + DI => cpuData, + DO => ayData, + OUT_A => ayA, + OUT_B => ayB, + OUT_C => ayC + ); + Ubuggce : BUFGCE_1 port map + ( + I => clock350, + O => cpuClock, + CE => cpuEnable + ); sdCs <= sdAc; led <= not sdAc; + aP <= '1' when addr(15 downto 14) = "01" else '0'; + vramCs <= '1' when mreq = '0' and addr(15 downto 13) = "010" else '0'; dromCs <= '1' when mreq = '0' and addr(15 downto 13) = "000" and (conmem = '1' or automap = '1') and mapram = '0' else '0'; - romCs <= '1' when mreq = '0' and addr(15 downto 14) = "00" and conmem = '0' and automap = '0' else '0'; - ramCs <= '1' when (mreq = '0' and addr(15 downto 13) = "000" and (conmem = '1' or automap = '1') and mapram = '1') - or (mreq = '0' and addr(15 downto 13) = "001" and (conmem = '1' or automap = '1')) - or (mreq = '0' and addr(15 downto 14) = "01") - or (mreq = '0' and addr(15) = '1') - else '0'; + romCs <= '1' when mreq = '0' and addr(15 downto 14) = "00" and conmem = '0' and automap = '0' else '0'; + ramCs <= '1' when (mreq = '0' and addr(15 downto 13) = "000" and (conmem = '1' or automap = '1') and mapram = '1') + or (mreq = '0' and addr(15 downto 13) = "001" and (conmem = '1' or automap = '1')) + or (mreq = '0' and addr(15 downto 14) = "01") + or (mreq = '0' and addr(15) = '1') + else '0'; + + ayBdir <= not wr; + ayCs <= '0' when iorq = '0' and m1 = '1' and addr(15) = '1' and addr(13) = '1' and addr(1) = '0' else '1'; vramWe <= not (mreq or wr) when addr(15 downto 13) = "010" else '0'; ramWr <= mreq or wr; @@ -255,6 +302,7 @@ begin else ramData when ramCs = '1' else romData when romCs = '1' else dromData when dromCs = '1' + else ayData when ayCs = '0' else ulaData; videoRgb <= (r&'0'&r)&(g&'0'&g)&(b&'0'&b) when i = '0' else (r&r&r)&(g&g&g)&(b&b&b);