MEGA65 is an open-source new and open C65-like computer.
Hardware designs and software are open-source (LGPL).
Source: MEGA65 Computer
Nice ๐
Everything related to the good old computer times
MEGA65 is an open-source new and open C65-like computer.
Hardware designs and software are open-source (LGPL).
Source: MEGA65 Computer
Nice ๐
I fixed the scanlines for vga output. Since its done in the scandoubler its vga only.
RGB output is working fine (mist.ini, tested with my new cable I got from Till).
Also the keys are remapped:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
-- Astrocade maps to pc key -- 0..9 0..9 -- x keypad x -- - keypad - -- + keypad + -- = keypad enter -- . keypad . or , -- c c -- v v -- ce delete -- mr x -- ms s -- ch w -- ^ a -- % p |
The binary and source can be found at the usual places.
I’ve ported another classic console to the MiST resurrected by MikeJ from www.fpgaarcade.com: The Bally Astrocade.
There’re still some todo’s left as I didn’t got the joystick working yet and I’m thinking of redo the key mapping. The current key mapping:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
-- bit console maps to pc key -- -- 0 c ^ v % z a q 1 -- 1 mr ms ch / x s w 2 -- 2 7 8 9 x c d e 3 -- 3 4 5 6 - v f r 4 -- 4 1 2 3 + b g t 5 -- 5 ce 0 . = n h y 6 Player 1 - Arrow keys and space for fire Player 2 - Numkeys and Num0 for fire |
Below a video of the “top 20” games for the Astrocade:
The original source can be obtained from the pacedev repository:
https://svn.pacedev.net/repos/pace/sw/src/platform/astrocade/
The MiST source is here:
https://github.com/wsoltys/mist-cores/tree/master/Astrocade
And the binary can be downloaded here:
https://code.google.com/p/mist-board/source/browse/trunk/bin/cores/astrocade
I’ve moved the colecovision MiST port from the pacedev repository into its own repository to be independent from the pacedev framework. While touching the code I’ve added the possibility to load files with the .bin extension and to disable the scan doubler.
Latter option is untested as I don’t own a capable monitor.
The binaries are at the usual place and the new source home is here:
https://github.com/wsoltys/mist-cores/tree/master/fpga_colecovision
Current FPGA boards have support for a sdcard but not all cores support it. There’re some classic cores (like Acorn Atom or the Spectrum) which do it with an extension ROM. But often the sdcard needs to be in a special format not readable by a PC which is also a problem for the MiST because it needs to load the core from a FAT filesystem and currently its not supported to change the sd card during runtime.
Another solution is to instantiate a second CPU which does the FAT reading and injects the code into RAM addressable by the core. But this comes with extra code because its like a second machine with own bios inside the fpga. Examples for that are the MSX and PC Engine port for the MiST.
Wouldn’t it be nice to keep requirements small and read a FAT filesystem directly in the core?
The FPGAmstrad core from Renaud Hรฉlias raised the idea but I wanted to code my own module for learning purpose. But where to start? First I needed a library to easily read the sdcard block by block. I found code from XESS which was a good start (https://github.com/xesscorp/VHDL_Lib/blob/master/SDCard.vhd).
Next was a comprehend guide to understand FAT. A good summary with the most important bits are Paul’s 8051 Code Library.
The code is written around a FSM (finite state machine). I started with reading the first sector of the sdcard to determine the first partition. Before reading the first sector of the first partition the code checks if its a valid FAT filesystem and what type it is. The current code supports only FAT32 and one partition. But this should cope with most situations as today you can only buy SDHC cards but even SD cards can be formatted with FAT32.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
when FAT_CHECK => if block_mem(SIGNATURE_POSITION) = x"55" and block_mem(SIGNATURE_POSITION+1) = x"AA" then state <= PARTITION_TYPE; end if; when PARTITION_TYPE => -- we only support fat32 here case block_mem(PARTITION1_TYPECODE_LOCATION) is when x"0B" => valid_partition <= '1'; state <= CHECK_LBA; when x"0C" => valid_partition <= '1'; state <= CHECK_LBA; when x"00" => valid_partition <= '0'; state <= CHECK_LBA; when others => state <= ERROR; end case; |
Once we have the LBA of the first partition we read the first sector and derive some important values from there:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
when CHECK_PARTITION => -- check for a valid partition if block_mem(11) = x"00" and block_mem(12) = x"02" and block_mem(16) = x"02" and block_mem(SIGNATURE_POSITION) = x"55" and block_mem(SIGNATURE_POSITION+1) = x"AA" then sectors_per_cluster <= block_mem(13); fat_begin_lba <= resize(lba_begin + (block_mem(15) & block_mem(14)), fat_begin_lba'length); cluster_begin_lba <= resize(lba_begin + (block_mem(15) & block_mem(14)) + (block_mem(16)*(block_mem(39) & block_mem(38) & block_mem(37) & block_mem(36))), cluster_begin_lba'length); root_dir_first_cluster <= block_mem(47) & block_mem(46) & block_mem(45) & block_mem(44); -- compute block address: addr = (cluster_begin_lba + (root_dir_first_cluster-2)*sectors_per_cluster)*FAT_SECTOR_SIZE block_addr <= resize((lba_begin + (block_mem(15) & block_mem(14)) + (block_mem(16)*(block_mem(39) & block_mem(38) & block_mem(37) & block_mem(36))) + ((block_mem(47) & block_mem(46) & block_mem(45) & block_mem(44))-2) * block_mem(13))*sd_factor, block_addr'length); state <= READ_BLOCK1; return_state <= READ_DIR1; else state <= ERROR; end if; |
sd_factor is 512 for SD cards (byte addressing) and 1 for SDHC cards (block addressing).
With those values we know where to start reading the root directory and can search for the file we want to load. Subdirectories are also located here but the current code only supports reading from the root directory and from small directories as FAT reading for dirs isn’t supported yet ๐
For FAT32 the directory entries are 32 bytes long and we jump from entry to entry until we’ve found our file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
when COMPARE1 => if block_mem(sector_cnt + entry_cnt) = filename(87-(entry_cnt*8) downto 80-(entry_cnt*8)) then if entry_cnt = 10 then -- filename found file_size <= block_mem(sector_cnt+31) & block_mem(sector_cnt+30) & block_mem(sector_cnt+29) & block_mem(sector_cnt+28); next_cluster <= block_mem(sector_cnt+21) & block_mem(sector_cnt+20) & block_mem(sector_cnt+27) & block_mem(sector_cnt+26); ram_addr_o <= unsigned(file_ram_a); state <= READ_FILE1; else entry_cnt <= entry_cnt + 1; state <= READ_DIR1; end if; else -- next entry sector_cnt <= sector_cnt + 32; entry_cnt <= 0; if block_mem(sector_cnt) = x"00" then -- file not found state <= ERROR; else state <= READ_DIR1; end if; end if; |
Once found the entry contains the file size and the starting cluster. From there we can read the file sector by sector and cluster by cluster. For my 4GB SDHC card the cluster size was 4KB (8 sectors * 512byte). After reading a full cluster we need to find the next cluster via the FAT and so on.
The current code is still work in progress as it contains a lot of debug stuff and is missing some important bits:
– Reading longer directories via FAT
– Optimize code as it currently takes up to 12.000 LE’s on a Cyclone III (and I have no idea why)
– Support subdirectories
– Support writing would be nice but I don’t think that I get to it soon
At least it works which was a good start for me ๐
The code is in my github repo as usual if you want to give it a try.
https://github.com/wsoltys/mist-cores/tree/master/misc/sdcard
Disclaimer: The code was written for learning purpose and might be highly inefficient. I’m open for any suggestions to optimize the code.