WonderMadeleine.vhd 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. -------------------------------------------------------------------------------
  2. -- The WonderProject: WonderMadeleine --
  3. -- (c) 2014 986-Studio / Godzil --
  4. -- http://www.986-studio.com <godzil_nospambot at 986 dash studio dot com> --
  5. -- --
  6. -- WonderMadeleine.vhd : TOP implementation --
  7. -- --
  8. -- What this project is about: --
  9. -- --
  10. -- This is a VHDL implementation of the Bandai 2001 / 2003 chip found in all --
  11. -- official WonderSwan Cartridge. It will ultimately provide a fully --
  12. -- functional clone of the Bandai chip. --
  13. -- --
  14. -- Licensed under the the Creative Common BY-NC-ND : --
  15. -- You are free to: --
  16. -- Share — copy and redistribute the material in any medium or format --
  17. -- --
  18. -- The licensor cannot revoke these freedoms as long as you follow the --
  19. -- license terms. --
  20. -- --
  21. -- Under the following terms: --
  22. -- --
  23. -- Attribution — You must give appropriate credit, provide a link to --
  24. -- the license, and indicate if changes were made. You --
  25. -- may do so in any reasonable manner, but not in any way --
  26. -- that suggests the licensor endorses you or your use. --
  27. -- NonCommercial — You may not use the material for commercial purposes. --
  28. -- NoDerivatives — If you remix, transform, or build upon the material, --
  29. -- you may not distribute the modified material. --
  30. -- --
  31. -- No additional restrictions — You may not apply legal terms or --
  32. -- technological measures that legally --
  33. -- restrict others from doing anything the --
  34. -- license permits. --
  35. -- --
  36. -- Notices: --
  37. -- --
  38. -- You do not have to comply with the license for elements of the material --
  39. -- in the public domain or where your use is permitted by an applicable --
  40. -- exception or limitation. --
  41. -- --
  42. -- No warranties are given. The license may not give you all of the --
  43. -- permissions necessary for your intended use. For example, other rights --
  44. -- such as publicity, privacy, or moral rights may limit how you use the --
  45. -- material. --
  46. -- --
  47. -- --
  48. -- What does that mean: --
  49. -- You can use this code to program your own CPLD --
  50. -- You can build your own cartridge that use this CPLD (and you can even --
  51. -- sell them!) --
  52. -- But you can't program CPLD and sell them directly --
  53. -- You are welcome to propose patch for supporting another CPLD or correct --
  54. -- bugs --
  55. -- You can't integrate this code with another CPLD of FPGA project --
  56. -- --
  57. -- If you have any doubt, please contact me I will be happy to help you --
  58. -- --
  59. -- What is currently working: (as of 13 november 2014) --
  60. -- [X] - ROM Banking --
  61. -- [X] - SRAM Banking --
  62. -- [X] - WonderSwan boot unlock --
  63. -- [ ] - EEPROM --
  64. -- [ ] - RTC --
  65. -- [ ] - GPIO --
  66. -- [ ] - All other unknown parts --
  67. -------------------------------------------------------------------------------
  68. library IEEE;
  69. use IEEE.STD_LOGIC_1164.ALL;
  70. --use IEEE.STD_LOGIC_ARITH.ALL;
  71. use IEEE.STD_LOGIC_UNSIGNED.ALL;
  72. use IEEE.NUMERIC_STD.ALL;
  73. entity WonderMadeleine is
  74. port(
  75. D_BUS: inout std_logic_vector( 7 downto 0); -- 16 bit Data bus
  76. A_BUS_H: in std_logic_vector(19 downto 16); -- High part of 20 bit Address bus
  77. A_BUS_L: in std_logic_vector( 3 downto 0); -- Low part of 20 bit Address bus
  78. nRD: in std_logic; -- /RD Signal
  79. nWR: in std_logic; -- /WR Signal
  80. nRESET: in std_logic; -- /Reset signal
  81. SYS_CLK: in std_logic; -- 384Khz system clock
  82. nINT: out std_logic; -- /INT, used mainly by cart RTC
  83. nIO: in std_logic; -- /IO. CPU tell when accessing IOs
  84. nMBC: out std_logic; -- /MBC serial link with MBC. Use for handshake
  85. nSEL: in std_logic; -- /SEL cart sel.
  86. EXT_A: out std_logic_vector( 7 downto 0); -- 8 bit A bus extension from IO page
  87. nSRAM_CS:out std_logic; -- SRAM ChipSelect
  88. nROM_CS: out std_logic; -- ROM ChipSelect
  89. EEP_CS: out std_logic;
  90. EEP_DI: in std_logic;
  91. EEP_DO: out std_logic;
  92. EEP_CK: out std_logic;
  93. RTC_CLK: out std_logic;
  94. RTC_CS: out std_logic;
  95. RTC_DATA:inout std_logic;
  96. GPIO: inout std_logic_vector(1 downto 0)
  97. );
  98. end WonderMadeleine;
  99. architecture Behavioral of WonderMadeleine is
  100. component GpioRegs is
  101. port(
  102. sel: in std_logic;
  103. nRD: in std_logic;
  104. nWR: in std_logic;
  105. regNum: in std_logic;
  106. data: inout std_logic_vector(7 downto 0);
  107. clock: in std_logic;
  108. -- GPIO PINs
  109. GPIO: inout std_logic_vector(1 downto 0)
  110. );
  111. end component;
  112. component EepromRegs
  113. port(
  114. sel: in std_logic;
  115. nRD: in std_logic;
  116. nWR: in std_logic;
  117. regNum: in std_logic_vector(2 downto 0);
  118. data: inout std_logic_vector(7 downto 0);
  119. clock: in std_logic;
  120. -- EEPROM PINs
  121. CS: out std_logic;
  122. CLK: out std_logic;
  123. DI: in std_logic;
  124. DO: out std_logic
  125. );
  126. end component;
  127. component RtcRegs
  128. port(
  129. sel: in std_logic;
  130. nRD: in std_logic;
  131. nWR: in std_logic;
  132. regNum: in std_logic;
  133. data: inout std_logic_vector(7 downto 0);
  134. clock: in std_logic;
  135. -- RTC PINs
  136. SDA: inout std_logic;
  137. CLK: out std_logic;
  138. CS: out std_logic
  139. );
  140. end component;
  141. signal rMBC: std_logic;
  142. signal readD: std_logic_vector(7 downto 0);
  143. signal writeD: std_logic_vector(7 downto 0);
  144. signal nRWTop: std_logic;
  145. signal regC0: std_logic_vector(7 downto 0);
  146. signal regC1: std_logic_vector(7 downto 0);
  147. signal regC2: std_logic_vector(7 downto 0);
  148. signal regC3: std_logic_vector(7 downto 0);
  149. signal eepromRegSel: std_logic;
  150. signal rtcRegSel: std_logic;
  151. signal gpioRegSel: std_logic;
  152. signal ioRegNum: std_logic_vector(7 downto 0);
  153. begin
  154. -- Instantiates all needed components
  155. gpioInst: GpioRegs port map(gpioRegSel, nRd, nWR, ioRegNum(0), D_BUS, SYS_CLK, GPIO);
  156. eepromInst: EepromRegs port map(eepromRegSel, nRd, nWR, ioRegNum(2 downto 0), D_BUS, SYS_CLK, EEP_CS, EEP_CK, EEP_DI, EEP_DO);
  157. rtcInst: RtcRegs port map(rtcRegSel, nRd, nWR, ioRegNum(0), D_BUS, SYS_CLK, RTC_DATA, RTC_CLK, RTC_CS);
  158. nINT <= 'Z';
  159. nMBC <= rMBC;
  160. nRWTop <= nRD and nWR;
  161. d_latches: process (nSEL, nIO, nRD, nWR, D_BUS, writeD, readD)
  162. begin
  163. if (nSEL='0' and nIO = '0' and nRD = '0' and nWR = '1') then
  164. if (nIO = '0') then
  165. D_BUS <= writeD;
  166. else
  167. D_BUS <= "ZZZZZZZZ";
  168. end if;
  169. readD <= D_BUS;
  170. elsif (nSEL='0' and nIO = '0' and nRD = '1' and nWR = '0') then
  171. D_BUS <= "ZZZZZZZZ";
  172. readD <= D_BUS;
  173. else
  174. D_BUS <= "ZZZZZZZZ";
  175. readD <= "11111111";
  176. end if;
  177. end process;
  178. main: process(nSEL, nIO, nRD, nWR, nRWTop, A_BUS_H, A_BUS_L, nRESET, readD, regC0, regC1, regC2, regC3)
  179. variable validRange: std_logic;
  180. begin
  181. ioRegNum(7 downto 4) <= A_BUS_H(19 downto 16);
  182. ioRegNum(3 downto 0) <= A_BUS_L( 3 downto 0);
  183. if (nRESET = '0') then
  184. nSRAM_CS <= '1';
  185. nROM_CS <= '1';
  186. regC0 <= X"FF";
  187. regC1 <= X"FF";
  188. regC2 <= X"FF";
  189. regC3 <= X"FF";
  190. eepromRegSel <= '0';
  191. rtcRegSel <= '0';
  192. gpioRegSel <= '0';
  193. elsif (nSEL = '0' and validRange = '1') then
  194. if(nIO = '0') then
  195. nSRAM_CS <= '1'; nROM_CS <= '1';
  196. if (falling_edge(nRWTop) and nRD = '0' and nWR = '1') then
  197. case ioRegNum is
  198. when X"C0" => writeD <= regC0; eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '0';
  199. when X"C1" => writeD <= regC1; eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '0';
  200. when X"C2" => writeD <= regC2; eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '0';
  201. when X"C3" => writeD <= regC3; eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '0';
  202. when X"C4" => eepromRegSel <= '1'; rtcRegSel <= '0'; gpioRegSel <= '0';
  203. when X"C5" => eepromRegSel <= '1'; rtcRegSel <= '0'; gpioRegSel <= '0';
  204. when X"C6" => eepromRegSel <= '1'; rtcRegSel <= '0'; gpioRegSel <= '0';
  205. when X"C7" => eepromRegSel <= '1'; rtcRegSel <= '0'; gpioRegSel <= '0';
  206. when X"C8" => eepromRegSel <= '1'; rtcRegSel <= '0'; gpioRegSel <= '0';
  207. when X"CA" => eepromRegSel <= '0'; rtcRegSel <= '1'; gpioRegSel <= '0';
  208. when X"CB" => eepromRegSel <= '0'; rtcRegSel <= '1'; gpioRegSel <= '0';
  209. when X"CC" => eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '1';
  210. when X"CD" => eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '1';
  211. when others => writeD <= X"FF"; eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '0';
  212. end case;
  213. elsif (falling_edge(nRWTop) and nRD = '1' and nWR = '0') then
  214. case ioRegNum is
  215. when X"C0" => regC0 <= readD; eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '0';
  216. when X"C1" => regC1 <= readD; eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '0';
  217. when X"C2" => regC2 <= readD; eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '0';
  218. when X"C3" => regC3 <= readD; eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '0';
  219. when X"C4" => eepromRegSel <= '1'; rtcRegSel <= '0'; gpioRegSel <= '0';
  220. when X"C5" => eepromRegSel <= '1'; rtcRegSel <= '0'; gpioRegSel <= '0';
  221. when X"C6" => eepromRegSel <= '1'; rtcRegSel <= '0'; gpioRegSel <= '0';
  222. when X"C7" => eepromRegSel <= '1'; rtcRegSel <= '0'; gpioRegSel <= '0';
  223. when X"C8" => eepromRegSel <= '1'; rtcRegSel <= '0'; gpioRegSel <= '0';
  224. when X"CA" => eepromRegSel <= '0'; rtcRegSel <= '1'; gpioRegSel <= '0';
  225. when X"CB" => eepromRegSel <= '0'; rtcRegSel <= '1'; gpioRegSel <= '0';
  226. when X"CC" => eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '1';
  227. when X"CD" => eepromRegSel <= '0'; rtcRegSel <= '0'; gpioRegSel <= '1';
  228. when others => null;
  229. end case;
  230. end if;
  231. elsif (nRD = '0' or nWR = '0') then
  232. -- Not IO
  233. case A_BUS_H is
  234. when X"0" => nSRAM_CS <= '1'; nROM_CS <= '1';
  235. when X"1" => nSRAM_CS <= '0'; nROM_CS <= '1';
  236. when others => nSRAM_CS <= '1'; nROM_CS <= '0';
  237. end case;
  238. -- Be sure the reg are not sel during non IO
  239. eepromRegSel <= '0';
  240. rtcRegSel <= '0';
  241. gpioRegSel <= '0';
  242. else
  243. -- Be sure the reg are not sel during non IO
  244. eepromRegSel <= '0';
  245. rtcRegSel <= '0';
  246. gpioRegSel <= '0';
  247. -- Not accessing SRAM or ROM mapping
  248. nSRAM_CS <= '1'; nROM_CS <= '1';
  249. end if;
  250. else -- Cart is not sel
  251. nSRAM_CS <= '1'; nROM_CS <= '1';
  252. -- Be sure the reg are not sel during non IO
  253. eepromRegSel <= '0';
  254. rtcRegSel <= '0';
  255. gpioRegSel <= '0';
  256. end if;
  257. case A_BUS_H(19 downto 16) is
  258. when X"0" => validRange := '0'; EXT_A <= X"00";
  259. when X"1" => validRange := '1'; EXT_A <= regC1;
  260. when X"2" => validRange := '1'; EXT_A <= regC2;
  261. when X"3" => validRange := '1'; EXT_A <= regC3;
  262. when others => validRange := '1'; EXT_A(7 downto 4) <= regC0(3 downto 0);
  263. EXT_A(3 downto 0) <= A_BUS_H;
  264. end case;
  265. end process;
  266. mbc_lock: process (SYS_CLK, nRESET, A_BUS_H, A_BUS_L)
  267. type STATE_TYPE is (sWait, sWaitForA5, sA1, SA2, SA3, sA4,
  268. sB1, sB2, sB3, sB4, sB5, sB6, sC, sD,
  269. sE, sF1, sF2, sF3, sG, sH, sI, sJ1, sJ2,
  270. sJ3, sDead);
  271. variable state: STATE_TYPE := sWait;
  272. begin
  273. if (nRESET = '0') then
  274. state := sWaitForA5;
  275. elsif (rising_edge(SYS_CLK) and state = sWaitForA5
  276. and A_BUS_H = X"A"
  277. and A_BUS_L = X"5" ) then
  278. state := sA1;
  279. elsif (rising_edge(SYS_CLK)) then
  280. case state is
  281. when sWait => rMBC <= '1';
  282. when sWaitForA5 => rMBC <= '1';
  283. when sA1 => state := sA2; rMBC <= '1';
  284. when sA2 => state := sA3; rMBC <= '1';
  285. when sA3 => state := sA4; rMBC <= '1';
  286. when sA4 => state := sB1; rMBC <= '1';
  287. when sB1 => state := sB2; rMBC <= '0';
  288. when sB2 => state := sB3; rMBC <= '0';
  289. when sB3 => state := sB4; rMBC <= '0';
  290. when sB4 => state := sB5; rMBC <= '0';
  291. when sB5 => state := sB6; rMBC <= '0';
  292. when sB6 => state := sC; rMBC <= '0';
  293. when sC => state := sD; rMBC <= '1';
  294. when sD => state := sE; rMBC <= '0';
  295. when sE => state := sF1; rMBC <= '1';
  296. when sF1 => state := sF2; rMBC <= '0';
  297. when sF2 => state := sF3; rMBC <= '0';
  298. when sF3 => state := sG; rMBC <= '0';
  299. when sG => state := sH; rMBC <= '1';
  300. when sH => state := sI; rMBC <= '0';
  301. when sI => state := sJ1; rMBC <= '1';
  302. when sJ1 => state := sJ2; rMBC <= '0';
  303. when sJ2 => state := sJ3; rMBC <= '0';
  304. when sJ3 => state := sDead; rMBC <= '0';
  305. when sDead => state := sDead; rMBC <= '1';
  306. end case;
  307. end if;
  308. end process;
  309. end architecture;
  310. -- Test script...
  311. -- restart
  312. -- force -freeze sim:/wondermadeleine/SYS_CLK 1 0, 0 {50 ps} -r 100
  313. -- force -freeze sim:/wondermadeleine/A_BUS_H 1100 0
  314. -- force -freeze sim:/wondermadeleine/A_BUS_L 0011 0
  315. -- force -freeze sim:/wondermadeleine/D_BUS 10101010 0 -cancel 200
  316. -- force -freeze sim:/wondermadeleine/regC0 01011011 0
  317. -- force -freeze sim:/wondermadeleine/regC1 10111101 0
  318. -- force -freeze sim:/wondermadeleine/regC2 00101110 0
  319. -- force -freeze sim:/wondermadeleine/nRD 1 0
  320. -- force -freeze sim:/wondermadeleine/nWR 1 0
  321. -- force -freeze sim:/wondermadeleine/nSEL 1 0
  322. -- force -freeze sim:/wondermadeleine/nIO 1 0
  323. -- force -freeze sim:/wondermadeleine/nRD 1 0
  324. -- force -freeze sim:/wondermadeleine/nRESET 1 0
  325. -- force -freeze sim:/wondermadeleine/nSEL 0 50
  326. -- force -freeze sim:/wondermadeleine/nWR 0 70
  327. -- force -freeze sim:/wondermadeleine/nIO 0 90
  328. -- force -freeze sim:/wondermadeleine/nWR 1 110
  329. -- force -freeze sim:/wondermadeleine/nIO 1 130
  330. -- force -freeze sim:/wondermadeleine/nSEL 1 150
  331. -- force -freeze sim:/wondermadeleine/nSEL 0 250
  332. -- force -freeze sim:/wondermadeleine/nRD 0 270
  333. -- force -freeze sim:/wondermadeleine/nIO 0 290
  334. -- force -freeze sim:/wondermadeleine/nRD 1 310
  335. -- force -freeze sim:/wondermadeleine/nIO 1 330
  336. -- force -freeze sim:/wondermadeleine/nSEL 1 350
  337. -- force -freeze sim:/wondermadeleine/A_BUS_H 0011 400
  338. -- force -freeze sim:/wondermadeleine/A_BUS_L 0000 400
  339. -- force -freeze sim:/wondermadeleine/nRD 0 410
  340. -- force -freeze sim:/wondermadeleine/nRD 1 420
  341. -- force -freeze sim:/wondermadeleine/nSEL 0 430
  342. -- force -freeze sim:/wondermadeleine/nRD 0 440
  343. -- force -freeze sim:/wondermadeleine/nRD 1 450
  344. -- force -freeze sim:/wondermadeleine/nSEL 1 460
  345. -- force -freeze sim:/wondermadeleine/A_BUS_H 1010 500
  346. -- force -freeze sim:/wondermadeleine/nWR 0 510
  347. -- force -freeze sim:/wondermadeleine/nWR 1 520
  348. -- force -freeze sim:/wondermadeleine/nSEL 0 530
  349. -- force -freeze sim:/wondermadeleine/nWR 0 540
  350. -- force -freeze sim:/wondermadeleine/nWR 1 550
  351. -- force -freeze sim:/wondermadeleine/nSEL 1 560
  352. -- force -freeze sim:/wondermadeleine/A_BUS_H 0000 600
  353. -- force -freeze sim:/wondermadeleine/nWR 0 610
  354. -- force -freeze sim:/wondermadeleine/nWR 1 620
  355. -- force -freeze sim:/wondermadeleine/nSEL 0 630
  356. -- force -freeze sim:/wondermadeleine/nWR 0 640
  357. -- force -freeze sim:/wondermadeleine/nWR 1 650
  358. -- force -freeze sim:/wondermadeleine/nSEL 1 660
  359. -- force -freeze sim:/wondermadeleine/A_BUS_H 0001 700
  360. -- force -freeze sim:/wondermadeleine/nRD 0 710
  361. -- force -freeze sim:/wondermadeleine/nRD 1 720
  362. -- force -freeze sim:/wondermadeleine/nSEL 0 730
  363. -- force -freeze sim:/wondermadeleine/nRD 0 740
  364. -- force -freeze sim:/wondermadeleine/nRD 1 750
  365. -- force -freeze sim:/wondermadeleine/nSEL 1 760
  366. -- run