--pinchy library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; -- Uncomment the following lines to use the declarations that are -- provided for instantiating Xilinx primitive components. --library UNISIM; --use UNISIM.VComponents.all; entity CD_EMU is Port ( --FX2 PD : in std_logic_vector(3 downto 0); PB : inout std_logic_vector(7 downto 0); PA : in std_logic_vector(1 downto 0); RDY0 : out std_logic; RDY1 : out std_logic; CTL0 : in std_logic; CTL1 : in std_logic; CTL2 : in std_logic; FX2_CLK : in std_logic; IFCLK : in std_logic; --SATURN side SAT_MPU_RESET_INV : in std_logic; --inverted SAT_LED : out std_logic; SAT_DAT_DATA : out std_logic; SAT_CLK_DATA_INV : out std_logic; --inverted SAT_MPX_DATA : out std_logic; SAT_UNKNOWN : out std_logic; SAT_MPX_AUD : out std_logic; SAT_CLK_AUD_INV : out std_logic; --inverted SAT_DAT_AUD : out std_logic; SAT_CLK_8MHZ : out std_logic; SAT_START_STROBE : out std_logic; SAT_OE : out std_logic; SAT_STATUS_DATA : out std_logic; SAT_COM_DATA_INV : in std_logic; --inverted SAT_COM_CLK_INV : in std_logic; --inverted --CD side CD_MPU_RESET : out std_logic; CD_STATUS_DATA : in std_logic; CD_COM_DATA : out std_logic; CD_OE : in std_logic; CD_COM_CLK : out std_logic; CD_START_STROBE : in std_logic; CD_CLK_8MHZ : in std_logic; CD_DAT_AUD : in std_logic; CD_CLK_AUD : in std_logic; CD_MPX_AUD : in std_logic; CD_UNKNOWN : in std_logic; CD_MPX_DATA : in std_logic; CD_CLK_DATA : in std_logic; CD_DAT_DATA : in std_logic; CD_LED : in std_logic ); end CD_EMU; architecture Behavioral of CD_EMU is COMPONENT IBUF PORT(i: IN STD_LOGIC; o: OUT STD_LOGIC); END COMPONENT; COMPONENT BUFG PORT(i: IN STD_LOGIC; o: OUT STD_LOGIC); END COMPONENT; type memory is array(integer range 0 to 12) of std_logic_vector(7 downto 0); type memory2 is array(integer range 0 to 3) of std_logic_vector(7 downto 0); signal commands : memory; signal cd_status : memory; signal status_data : memory; signal msf_data : memory2; signal SAT_MPU_RESET : std_logic; signal SAT_COM_DATA : std_logic; signal SAT_COM_CLK : std_logic; signal SAT_COM_CLK1 : std_logic; signal SAT_COM_CLK2 : std_logic; signal command_byte : std_logic_vector(7 downto 0); signal status_byte : std_logic_vector(7 downto 0); signal data1_out_count : integer range 0 to 12; signal data1_in_count : integer range 0 to 12; signal data2_out_count : integer range 0 to 12; signal data2_in_count : integer range 0 to 12; signal WEA_RAM1 : std_logic; signal WEA_RAM2 : std_logic; signal WEB_RAM1 : std_logic; signal WEB_RAM2 : std_logic; signal RAM1_DO : std_logic_vector(7 downto 0); signal RAM2_DO : std_logic_vector(7 downto 0); signal CLKA_RAM : std_logic; signal CLKB_RAM : std_logic; signal bit_count : integer range 0 to 7:=0; signal command_parity : std_logic_vector(7 downto 0); signal fake_command_bit : std_logic; signal fake_status_bit : std_logic; signal marker_status_bit : std_logic; signal fake_sector_bit : std_logic; signal command_count : integer range 0 to 12:=0; signal FX2_CONTROL : std_logic:='0'; signal FX2_CONTROL_DATA : std_logic:='0'; signal fx2_byte : std_logic_vector(7 downto 0); signal CD_CLK_DATA_l : std_logic; signal CD_CLK_DATA_t : std_logic; begin --these connect clocks to buffers so we can actaully drive flip flops and stuph (fpga normally requires clocks connected to dedicated pins) u1: IBUF port map(I=>SAT_COM_CLK_INV,O=>SAT_COM_CLK1); u2: BUFG port map(I=>SAT_COM_CLK1,O=>SAT_COM_CLK2); u3: IBUF port map(I=>CD_CLK_DATA, O=>CD_CLK_DATA_t); u4: BUFG port map(I=>CD_CLK_DATA_t,O=>CD_CLK_DATA_l); CLKA_RAM<=FX2_CLK; CLKB_RAM<=FX2_CLK; --invert these signals for sanitys sake SAT_MPU_RESET<=not SAT_MPU_RESET_INV; SAT_COM_DATA<=not SAT_COM_DATA_INV; SAT_COM_CLK<=not SAT_COM_CLK2; --pass thru stuff CD_MPU_RESET<=SAT_MPU_RESET; SAT_CLK_8MHZ<=CD_CLK_8MHZ; SAT_UNKNOWN<=CD_UNKNOWN; --command interface SAT_START_STROBE<=CD_START_STROBE; CD_COM_CLK<=SAT_COM_CLK; SAT_OE<=CD_OE; --sector data SAT_CLK_DATA_INV<=not CD_CLK_DATA_t; SAT_MPX_DATA<=CD_MPX_DATA; --audio data SAT_MPX_AUD<=CD_MPX_AUD; SAT_CLK_AUD_INV<=not CD_CLK_AUD; SAT_DAT_AUD<=CD_DAT_AUD; process(FX2_CLK,SAT_COM_CLK) variable cd_oe1 : std_logic; variable cd_oe2 : std_logic; variable cd_start1 : std_logic; variable cd_start2 : std_logic; variable fx2_port2 : std_logic; variable last_rdy1 : std_logic:='0'; begin ----grab command data from saturn if(SAT_COM_CLK'Event and SAT_COM_CLK='1')then command_byte<=SAT_COM_DATA & command_byte(7 downto 1); status_byte<=CD_STATUS_DATA & status_byte(7 downto 1); end if; --keep count of bit if(CD_START_STROBE='0' and CD_OE='1')then bit_count<=7; elsif(SAT_COM_CLK'Event and SAT_COM_CLK='0')then if(bit_count=7)then bit_count<=0; else bit_count<=bit_count+1; end if; end if; if(command_count/=11)then fake_command_bit<=SAT_COM_DATA; else fake_command_bit<=command_parity(bit_count); --this will be incorrect party since its not NOT'ed ;) end if; fake_status_bit<=status_data(command_count)(bit_count); if(PD(2)='1')then PB<=fx2_byte; else PB<=(others=>'Z'); end if; -------------------------------------FX2 CLK---------------------------------------------- if(FX2_CLK'Event and FX2_CLK='0')then if(cd_start1='1' and cd_start2='0')then --reset on falling edge of START command_count<=0; command_parity<=X"00"; end if; if(cd_oe1='0' and cd_oe2='1')then --sync to rising edge of OE commands(command_count)<=command_byte; cd_status(command_count)<=status_byte; if(command_count/=11)then command_parity<=command_parity+commands(command_count); end if; if(command_count=11)then last_rdy1:=last_rdy1 xor '1'; --let fx2 know end of command sequence end if; command_count<=command_count+1; end if; cd_oe1:=cd_oe2; cd_oe2:=CD_OE; cd_start1:=cd_start2; cd_start2:=CD_START_STROBE; --yea we got crazy port assignments but hey what can i say;) --PD.2 1=read 0=write if(PD(2)='1')then --read from FPGA --read commands and status and cd_status and msf_data only --PA.0 inc read pointer / --PA.1 reset other pointer --PD.1 select which data if(PA(1)='0')then data2_out_count<=0; --reset read pointer for other side if(PD(1)='1')then fx2_byte<=commands(data1_out_count); --commands: PD.2=1,PD.1=1,PA.1=0 else fx2_byte<=status_data(data1_out_count); --status: PD.2=1,PD.1=0,PA.1=0 end if; if(PA(0)='1' and fx2_port2='0')then --rising edge data1_out_count<=data1_out_count+1; end if; else data1_out_count<=0; --reset read pointer for other side if(PD(1)='1')then fx2_byte<=cd_status(data2_out_count); --cd_status:PD.2=1,PD.1=1,PA.1=1 else fx2_byte<=msf_data(data2_out_count); --msf_data: PD.2=1,PD.1=0,PA.1=1 end if; if(PA(0)='1' and fx2_port2='0')then --rising edge data2_out_count<=data2_out_count+1; end if; end if; else --write to FPGA (make sure PA.0=1 before PD.2=0) --write status and sector data only --PD.1 select 1=msf or 0=status --PA.0 validate data low, increment pointer on rise/ --PA.1 0=reset pointer if(PD(1)='1')then --msf data if(PA(0)='0')then msf_data(data1_in_count)<=PB; --msf_data: PA.0=0,PA.1=1,PD.1=1 end if; else --status if(PA(0)='0')then status_data(data1_in_count)<=PB; --status_data: PA.0=0,PA.1=1,PD.1=0 end if; end if; if(PA(0)='1' and fx2_port2='0')then --rising edge data1_in_count<=data1_in_count+1; end if; if(PA(1)='0')then --reset pointer data1_in_count<=0; end if; end if; fx2_port2:=PA(0); if(PD(0)='1')then --fx2 take over commands if(commands(0)/=X"00" and commands(1)&commands(2)>=X"03A0" and command_count>2)then --disable when it actaully seeks to ring FX2_CONTROL<='1'; end if; else -- if(commands(0)/=X"00" and commands(1)&commands(2)>=X"03D0" and command_count>2)then --disable reads to high LBA anyway -- FX2_CONTROL<='1'; -- else FX2_CONTROL<='0'; -- end if; end if; if(PD(3)='1')then --fx2 take over sector data FX2_CONTROL_DATA<='1'; else FX2_CONTROL_DATA<='0'; end if; end if; ----end FX2 CLK------------------------------------------------------------------ if(FX2_CONTROL_DATA='1')then --FX2 in control of sector data SAT_DAT_DATA<=fake_sector_bit; SAT_LED<='1'; else -- SAT_DAT_DATA<=marker_status_bit; SAT_DAT_DATA<=CD_DAT_DATA; SAT_LED<=CD_LED; end if; if(FX2_CONTROL='1')then --FX2 in control command interface SAT_STATUS_DATA<=fake_status_bit; CD_COM_DATA<=fake_command_bit; else SAT_STATUS_DATA<=CD_STATUS_DATA; CD_COM_DATA<=SAT_COM_DATA; end if; RDY1<=last_rdy1; end process; --manage the fake security ring sector data process(CD_CLK_DATA_l) variable i: integer range 0 to 7:=7; --some bit shift register variable j: integer range 0 to 47:=0; --bit variable k: integer range 0 to 587:=0; --sample counter in one sector variable min: std_logic_vector(7 downto 0); variable sec: std_logic_vector(7 downto 0); variable frm: std_logic_vector(7 downto 0); variable a: std_logic:='0'; variable b: std_logic:='0'; variable sectorBYTE : std_logic_vector(7 downto 0); variable reset_counter:std_logic:='0'; variable last_rdy0 : std_logic:='0'; variable sync_l : std_logic_vector(15 downto 0); variable sync_count : integer range 0 to 2:=0; begin RDY0<=last_rdy0; --let fx2 sync to commands --bunch of counters that are synchronized to the sector data clocks (should be bullet proof at this point) if(CD_CLK_DATA_l'Event and CD_CLK_DATA_l='0')then --\falling edge if(reset_counter='1')then --MPX edge / i:=6; j:=1; else if(i=0)then i:=7; else i:=i-1; end if; if(j=23 or j=47)then if(sync_l=X"FFFF")then if(sync_count=1)then -- k:=1; --sync to the real cd sector data , used for debuggin and marking in ya logic analyzer end if; sync_count:=sync_count+1; else sync_count:=0; end if; end if; if(j=47)then if(k=587)then if(command_count=12)then --its gonna be like this: sync sector data to the last byte of the command transaction k:=0; --and signal the fx2 after its passed the MSF part of the sector data end if; -- last_rdy0:=last_rdy0 xor '1'; --let the fx2 know when its time to update its lba else if(k=6)then last_rdy0:=last_rdy0 xor '1'; --let the fx2 know when its time to update its lba end if; k:=k+1; end if; j:=0; else j:=j+1; end if; end if; end if; if(CD_CLK_DATA_l'Event and CD_CLK_DATA_l='1')then --/rising edge sync_l:=sync_l(14 downto 0) & CD_DAT_DATA; if(CD_MPX_DATA='1' and b='0')then reset_counter:='1'; else reset_counter:='0'; end if; b:=CD_MPX_DATA; end if; --MASK OUT WHAT EVER PARTS OF SECTOR DATA FOR FLAGGING --if( ((j>=0 and j<=7) or (j>=24 and j<=31)) )then -- fake_sector_bit<='1'; -- if(k>=0 and k<=2)then -- marker_status_bit<='1'; -- else -- marker_status_bit<='0'; -- end if; --else fake_sector_bit<=sectorBYTE(i); -- marker_status_bit<=CD_DAT_DATA; --end if; --else -- fake_sector_bit<=CD_DAT_DATA; --end if; ----------------------------------------- --stuff that you can remove if you want: --FRAME: -- 3(mode 2 byte 0x62) -- 4,5,587 ----------------------------------------- case(k) is --sample counter 0 to 587 when 0=> case(j) is --bit counter 0 to 47 when 8 to 15=> sectorBYTE:=X"FF"; when 16 to 23=> sectorBYTE:=X"00"; when others=> sectorBYTE:=X"FF"; end case; when 1=> case(j) is when others=> sectorBYTE:=X"FF"; end case; when 2=> case(j) is when 8 to 23=> sectorBYTE:=X"FF"; when 32 to 39=> sectorBYTE:=X"00"; when others=> sectorBYTE:=X"FF"; end case; when 3=> case(j) is --S M x F -- min,sec ,frm,mode when 8 to 15=> --xor 1 ,0x80,0 ,0x60 sectorBYTE:=msf_data(1) xor X"80" ; --seconds when 16 to 23=> sectorBYTE:=msf_data(0) xor X"01"; --minutes when 32 to 39=> sectorBYTE:=X"62"; --mode 2 XOR 0x60 when 40 to 47=> sectorBYTE:=msf_data(2); --frames when others=> sectorBYTE:=X"FF"; end case; when 4=> case(j) is when 8 to 15=> sectorBYTE:=X"28"; when 16 to 23=> sectorBYTE:=X"00"; when 32 to 39=> sectorBYTE:=X"1E"; when 40 to 47=> sectorBYTE:=X"28"; when others=> sectorBYTE:=X"00"; end case; when 5=> case(j) is when 8 to 15=> sectorBYTE:=X"08"; when 16 to 23=> sectorBYTE:=X"80"; when 32 to 39=> sectorBYTE:=X"06"; when 40 to 47=> sectorBYTE:=X"48"; when others=> sectorBYTE:=X"00"; end case; when 6 to 586=> case(j) is when 8 to 15=> sectorBYTE:=X"59"; when 16 to 23=> sectorBYTE:=X"A8"; when 32 to 39=> sectorBYTE:=X"59"; when 40 to 47=> sectorBYTE:=X"A8"; when others=> sectorBYTE:=X"00"; end case; when 587=> case(j) is when 8 to 15=> sectorBYTE:=X"DD"; when 16 to 23=> sectorBYTE:=X"72"; when 32 to 39=> sectorBYTE:=X"99"; when 40 to 47=> sectorBYTE:=X"E5"; when others=> sectorBYTE:=X"00"; end case; when others=> sectorBYTE:=X"00"; end case; end process; end Behavioral; --rooster