├── LICENSE ├── README.md ├── mesa_bus3.txt ├── python ├── README.txt ├── bd_server.ini ├── bd_server.py ├── bd_shell.ini ├── bd_shell.py ├── class_cmd_proc.py ├── class_lb_link.py ├── class_lb_tcp_link.py ├── class_mesa_bus.py ├── class_spi_prom.py ├── class_uart_usb_link.py ├── class_user.py ├── common_functions.py ├── ico_gpio.py ├── mesa_bus_ex.ini └── mesa_bus_ex.py ├── verilog ├── README.txt ├── ft232_xface.v ├── hlist.txt ├── iob_bidi.v ├── mesa2ctrl.v ├── mesa2lb.v ├── mesa2spi.v ├── mesa_ascii2nibble.v ├── mesa_byte2ascii.v ├── mesa_core.v ├── mesa_decode.v ├── mesa_id.v ├── mesa_phy.v ├── mesa_pi_spi.v ├── mesa_rx_uart.v ├── mesa_tx_uart.v ├── mesa_uart.v ├── mesa_uart_phy.v ├── spi_byte2bit.v ├── spi_prom.v └── top.v └── vivado ├── go.sh ├── go.tcl ├── time_stamp.py ├── top_physical.xdc ├── top_rtl_list.tcl └── top_timing.xdc /README.md: -------------------------------------------------------------------------------- 1 | # MesaBusProtocol 2 | Flexible Byte transport protocol for bus bridging CPUs to FPGAs over UART,SPI,SERDES physical interfaces 3 | 4 | Mesa Bus Protocol is intended to transfer data between 50 Kbps up to 10 Gbps over UART to SERDES links with just a few wires and very little hardware overhead. It is a very small gate foot print byte transport protocol for encapsulating and transferring payloads of higher protocols (0-255 bytes per payload). Think of it like a cross between Ethernet and USB 3.1. The advantages Mesa Bus Protocol has over USB, Ethernet and PCI is that it fits easily within a $3 FPGA and may be bus mastered either by a PC with a FTDI cable or any old ARM/AVR Arduino CPU (or RPi) with just two standard UART serial port pins. As it is ASCII based, Mesa Bus Protocol is also very portable to wireless devices such as Bluetooth SPP and the RockBLOCK satellite modem for the Iridium network . MBP supports daisy chaining of up to 250 devices, allowing a single CPU bus master to communicate ( with latency ) to multiple FPGAs using a single serial interface. 5 | 6 | This Repo is a misc collection of Python and Verilog examples for using Mesa Bus Protocol. 7 | 8 | For complete actual designs, see the TARball of these projects ( reside on my public Dropbox ) 9 | 10 | FTDI UART Example : https://blackmesalabs.wordpress.com/2016/10/24/sump2-96-msps-logic-analyzer-for-22/ 11 | 12 | SPI Example : https://blackmesalabs.wordpress.com/2016/12/22/sump2-100-msps-32bit-logic-analyzer-for-icoboardraspberrypi/ 13 | 14 | 15 | [ Files ] 16 | 17 | mesa_bus3.txt : Detailed description of the protocol and how used. 18 | 19 | bd_server.py : Python Example of FTDI UART for Mesa Bus access. 20 | 21 | bd_server.ini : Example config file for bd_server.py. 22 | 23 | ico_gpio.py : Python example of Pi SPI for Mesa Bus access. 24 | 25 | hlist.txt : ChipVault hierarchy file for Verilog files. 26 | 27 | top.v : Top level FPGA for MesaBus on Digilent BASYS3 Artix7 board. 28 | 29 | mesa2ctrl.v : Decodes the 0xF subslot controls. 30 | 31 | mesa2lb.v : Decodes subslot-0 bus cycles to 32bit Local Bus ( virtual PCI ). 32 | 33 | mesa_ascii2nibble.v : Used by UART designs, converts ASCII hex to binary nibbles. 34 | 35 | mesa_byte2ascii.v : Used by UART designs, converts binary bytes to ASCII nibble pairs. 36 | 37 | mesa_core.v : Wrapper around a bunch of Mesa Bus verilog files for SPI. 38 | 39 | mesa_decode.v : Main serial bus decoder. Also does daisy chain enumeration. 40 | 41 | mesa_id.v : Reports things like Manufacture ID, Device ID, Build Timestamp. 42 | 43 | mesa_phy.v : Wrapper around the UART blocks. 44 | 45 | mesa_pi_spi.v : SPI interface for RaspPi. 46 | 47 | mesa_tx_uart.v : UART TX only. 48 | 49 | mesa_uart.v : UART RX and TX. 50 | 51 | spi_byte2bit.v : Generic SPI serializer. 52 | 53 | spi_prom.v : SPI interface to FPGA PROMs ( Micron ). 54 | 55 | -------------------------------------------------------------------------------- /python/README.txt: -------------------------------------------------------------------------------- 1 | bd_shell.py : "Backdoor Shell" a CLI for reading and writing registers over Mesa Bus. 2 | mesa_bus_ex.py : Example Python script for reading and writing Mesa Bus registers. 3 | -------------------------------------------------------------------------------- /python/bd_server.ini: -------------------------------------------------------------------------------- 1 | bd_connection = usb # usb,pi_spi 2 | bd_protocol = mesa # mesa,poke 3 | usb_port = COM4 # ie COM4 4 | tcp_port = 21567 # ie 21567 5 | baudrate = 921600 # ie 921600 6 | mesa_slot = 00 # ie 00 7 | mesa_subslot = 0 # ie 0 8 | debug_bd_en = 1 # ie 0,1 9 | debug_tcp_en = 0 # ie 0,1 10 | aes_authentication = 0 # ie 1 11 | aes_e2e_encryption = 0 # ie 1 12 | aes_key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f # AES-256 Key 13 | -------------------------------------------------------------------------------- /python/bd_shell.ini: -------------------------------------------------------------------------------- 1 | bd_connection = tcp 2 | bd_protocol = mesa 3 | deep_sump_auto_vcd = 0 4 | deep_sump_fov = wide 5 | deep_sump_fov_event_en = FFFFFFFF 6 | deep_sump_fov_narrow = 04100000 7 | deep_sump_fov_off = 00000000 8 | deep_sump_fov_wide = FF010000 9 | deep_sump_post_trig_percent = 50 10 | deep_sump_pre_trig_percent = 50 11 | deep_sump_unique_vcd_en = 1 12 | deep_sump_user_cfg = 00000000 13 | deep_sump_user_ctrl = 00000004 14 | deep_sump_user_mask = 000003ff 15 | mesa_slot = 00 16 | mesa_subslot = 0 17 | scripts_path = .,sump2_scripts,bd_scripts 18 | sump_acquisition_len = 44 19 | sump_addr = 00000090 20 | sump_data_enable = 00000000 21 | sump_debug_en = 0 22 | sump_doubleclick = mask 23 | sump_path_bmp = sump2_bmp 24 | sump_path_jpg = sump2_jpg 25 | sump_path_png = sump2_png 26 | sump_path_scripts = sump2_scripts 27 | sump_path_txt = sump2_txt 28 | sump_path_vcd = sump2_vcd 29 | sump_preview_auto = 1 30 | sump_preview_dwords = 1 31 | sump_preview_events = 1 32 | sump_preview_offset = 0 33 | sump_preview_width = 100 34 | sump_preview_zoom = 1 35 | sump_rle_autocull = 0 36 | sump_rle_autoset_en = 1 37 | sump_rle_autoset_limit = 10 38 | sump_rle_autoset_period = 10 39 | sump_rle_event_en = fffffc00 40 | sump_rle_mask_hidden_en = 1 41 | sump_script_shutdown = shutdown.txt 42 | sump_script_startup = startup.txt 43 | sump_trigger_delay = 0000 44 | sump_trigger_delay_24b_en = 0 45 | sump_trigger_field = 00000100 46 | sump_trigger_nth = 0001 47 | sump_trigger_type = or_rising 48 | sump_user_ctrl = 00000005 49 | sump_user_pattern0 = 00000000 50 | sump_user_pattern1 = 00000000 51 | sump_user_stim = 0000AAAA 52 | sump_user_stimulus = 0000 53 | sump_watchdog_time = 00000000 54 | tcp_ip_addr = 127.0.0.1 55 | tcp_port = 21567 56 | usb_baudrate = 921600 57 | usb_port = COM4 58 | uut_name = FOO 59 | vcd_viewer_en = 1 60 | vcd_viewer_gtkw_en = 1 61 | vcd_viewer_path = C:\Users\Kevin\Desktop\gtkwave\bin\gtkwave.exe 62 | -------------------------------------------------------------------------------- /python/bd_shell.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | ################################################################################################### 3 | # Source file : bd_shell.py 4 | # Language : Python 3.7 - may work with earlier and later 3.x versions. 5 | # Author : Kevin Hubbard 6 | # Description : Backdoor Shell, a UNIX shell like interface for writing and reading FPGA and ASIC 7 | # registers sitting on a 32bit Local Bus. 8 | # License : GPLv3 9 | # This program is free software: you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation, either version 3 of the License, or 12 | # (at your option) any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | # Notes : PySerial for Python3 from https://pypi.python.org/pypi/pyserial/ 22 | # ------------------------------------------------------------------------------------------------- 23 | # History : 24 | # 01.01.2018 : khubbard : Created. Offshoot from original .NET Powershell 25 | # TODO: Need to figure out clean way to get slot and subslot working over TCP 26 | ################################################################################################### 27 | from common_functions import file2list; 28 | from common_functions import list2file; 29 | 30 | import sys; 31 | import select; 32 | import socket; 33 | import time; 34 | import os; 35 | import random; 36 | from time import sleep; 37 | from os import path; 38 | 39 | import class_cmd_proc; 40 | 41 | import class_spi_prom; # Access to spi_prom.v over LocalBus 42 | import class_lb_link; # Access to LocalBus over MesaBus over serial 43 | import class_lb_tcp_link; # Access to LocalBus over TCP link to bd_server.py 44 | import class_mesa_bus; # Access to MesaBus over serial 45 | import class_uart_usb_link; # Access to serial over USB COM type connection 46 | #import class_ft600_usb_link;# Access to serial over USB3 FT600 type connection 47 | #import class_sump2; # Access to sump2.v logic analyzer engine in HW 48 | import class_user; # Example of user defined add on functions 49 | 50 | 51 | def main(): 52 | args = sys.argv + [None]*3;# args[0] is bd_shell.py 53 | title = "bd_shell 2019.11.05 - Black Mesa Labs - GPLv3"; 54 | var_dict = {}; 55 | cmd_history = []; 56 | 57 | import platform,os; 58 | os_sys = platform.system(); # Windows vs Linux 59 | if ( os_sys == "Windows" ): 60 | os.system("title "+title );# Give DOS-Box a snazzy title 61 | print("Welcome to "+title); 62 | 63 | 64 | # If INI file exists, load it, otherwise create a default one and use it 65 | file_name = path.join( os.getcwd(), "bd_shell.ini"); 66 | if ( ( path.exists( file_name ) ) == False ): 67 | ini_list = ["bd_connection = usb # usb,usb3,pi_spi,tcp", 68 | "bd_protocol = mesa # mesa,poke", 69 | "tcp_port = 21567 # 21567 ", 70 | "tcp_ip_addr = 127.0.0.1 # 127.0.0.1", 71 | "usb_port = COM4 # ie COM4", 72 | "usb_baudrate = 921600 # ie 921600", 73 | # "search_path = .,search_dir", 74 | "scripts_path = .,sump2_scripts,bd_scripts", 75 | "mesa_slot = 00 # ie 00", 76 | "mesa_subslot = 0 # ie 0", ]; 77 | ini_file = open ( file_name, 'w' ); 78 | for each in ini_list: 79 | ini_file.write( each + "\n" ); 80 | ini_file.close(); 81 | 82 | if ( ( path.exists( file_name ) ) == True ): 83 | ini_file = open ( file_name, 'r' ); 84 | ini_list = ini_file.readlines(); 85 | for each in ini_list: 86 | words = " ".join(each.split()).split(' ') + [None] * 4; 87 | if ( words[1] == "=" ): 88 | var_dict[ words[0] ] = words[2]; 89 | 90 | # Assign var_dict values to legacy variables. Error checking would be nice. 91 | bd_connection = var_dict["bd_connection"]; 92 | com_port = var_dict["usb_port"]; 93 | baudrate = int(var_dict["usb_baudrate"],10); 94 | mesa_slot = int(var_dict["mesa_slot"],16); 95 | mesa_subslot = int(var_dict["mesa_subslot"],16); 96 | tcp_ip_addr = var_dict["tcp_ip_addr"]; 97 | tcp_port = int(var_dict["tcp_port"],10); 98 | 99 | # See if the search path directories exist, create if they don't 100 | search_path = var_dict["scripts_path"]; 101 | paths = search_path.split(','); 102 | for each_path in paths: 103 | if ( not os.path.exists( each_path ) ): 104 | print("Note: Creating %s" % each_path ); 105 | os.makedirs( each_path ); 106 | 107 | # Establish connection to Backdoor Hardware 108 | try: 109 | if ( bd_connection == "tcp" ): 110 | bd = class_lb_tcp_link.lb_tcp_link( ip = tcp_ip_addr, port = tcp_port ); 111 | if ( bd.sock == None ): 112 | bd = None; 113 | elif ( bd_connection == "usb" ): 114 | usb = class_uart_usb_link.uart_usb_link( port_name=com_port, 115 | baudrate=baudrate ); 116 | mb = class_mesa_bus.mesa_bus( phy_link=usb ); 117 | bd = class_lb_link.lb_link( mesa_bus=mb, slot=mesa_slot, 118 | subslot=mesa_subslot ); 119 | except: 120 | print("ERROR: Backdoor connection failed. Check hardware and bd_shell.ini"); 121 | # Save variables sorted alphabetically by name to bd_shell.ini file 122 | rts = []; 123 | for (key,val) in sorted( var_dict.items() ): 124 | rts += ["%-30s = %s" % ( key, val ) ]; 125 | list2file( "bd_shell.ini", rts ); 126 | bd = None; # Support running CLI w/o hardware present 127 | # sys.exit(); 128 | 129 | # Now load Plugin classes for PROM, SUMP2, Command Processing and User Code 130 | prom = class_spi_prom.spi_prom( lb_link = bd ); 131 | user = class_user.user( lb_link = bd ); 132 | 133 | # sump2 = class_sump2.sump2( lb_link=bd, var_dict=var_dict ); 134 | sump2 = None; 135 | 136 | # cmd = class_cmd_proc.cmd_proc( bd,prom,sump2,user,var_dict,sump2.wave_dict); 137 | cmd = class_cmd_proc.cmd_proc( bd,prom,sump2,user,var_dict, None ); 138 | 139 | # Other modules have their own help text which gets appended to the main cmd.help 140 | # help is a brief one line. Detailed help can be a paragraph and is brought up 141 | # with 'help foo' versus just 'help' for displaying brief help for all. 142 | # cmd.help += sump2.help; 143 | # cmd.detailed_help += sump2.detailed_help; 144 | cmd.help += user.help; 145 | cmd.detailed_help += user.detailed_help; 146 | cmd.help += prom.help; 147 | 148 | # Look for mesa_slot and mesa_subslot vars and issue as commands for bd_server 149 | mesa_list = [ "mesa_slot", "mesa_subslot" ]; 150 | for each_key in mesa_list: 151 | if ( var_dict.get(each_key) != None ): 152 | value = var_dict[each_key]; 153 | cmd_str = "%s %s" % ( each_key, value ); 154 | if ( bd != None ): 155 | rts = cmd.proc( cmd_str ); 156 | 157 | # Assign the sump2 defaults as bd_shell variables if unassigned 158 | # for key in sump2.var_dflt: 159 | # if ( var_dict.get(key) == None ): 160 | # cmd_str = "%s = %s" % ( key, sump2.var_dflt[key] ); 161 | # rts = cmd.proc( cmd_str ); 162 | 163 | # If sump2.ini exists, use it in place of any bd_shell.ini defaults 164 | # if ( os.path.exists( sump2.sump2_ini ) ): 165 | # print("Found %s - sourcing it " % sump2.sump2_ini ); 166 | # cmd_list = file2list( sump2.sump2_ini ); 167 | # for cmd_str in cmd_list: 168 | # words = " ".join(cmd_str.split()).split(' ') + [None] * 4; 169 | # # Filter out any GUI specific variables as to not clutter up env 170 | # if not any( each in words[0] for each in sump2.sump_cull_list ): 171 | # rts = cmd.proc( cmd_str ); 172 | 173 | # If sump2_wave.txt exists, use it 174 | # if ( os.path.exists( sump2.sump2_wave ) ): 175 | # print("Found %s - sourcing it " % sump2.sump2_wave ); 176 | # cmd_list = file2list( sump2.sump2_wave ); 177 | # for cmd_str in cmd_list: 178 | # if not ( "-bundle" in cmd_str ): 179 | # rts = cmd.proc( cmd_str ); 180 | 181 | # Look for sump startup script 182 | if ( var_dict.get("sump_script_startup") != None ): 183 | sump_script_startup = var_dict.get("sump_script_startup"); 184 | if ( os.path.isfile(sump_script_startup) ): 185 | print("Found %s - sourcing it " % sump_script_startup ); 186 | cmd_list = file2list( sump_script_startup ); 187 | for cmd_str in cmd_list: 188 | rts = cmd.proc( cmd_str ); 189 | 190 | # # Look for sump shutdown script 191 | # if ( var_dict.get("sump_script_shutdown") != None ): 192 | # sump_script_shutdown = var_dict.get("sump_script_shutdown"); 193 | # if ( os.path.isfile(sump_script_shutdown) ): 194 | # cmd_list = file2list( sump_script_shutdown ); 195 | # for cmd_str in cmd_list: 196 | # rts = cmd.proc( cmd_str ); 197 | 198 | # import curses; 199 | # screen = curses.initscr(); 200 | # curses.noecho(); 201 | # curses.cbreak(); # Don't wait for ENTER 202 | # screen.keypad(True); # Map arrow keys to special values 203 | # try: 204 | # while ( True ): 205 | # char = screen.getch(); 206 | # if ( char == ord('q') ): 207 | # break; 208 | # elif ( char == curses.KEY_LEFT ): 209 | # print("Left"); 210 | # elif ( char == curses.KEY_RIGHT ): 211 | # print("Right"); 212 | # finally: 213 | # curses.nocbreak(); screen.keypad(0); curses.echo(); 214 | # curses.endwin(); 215 | # import sys 216 | # for line in sys.stdin.readlines(): 217 | # print( ord(line) ); 218 | 219 | 220 | # If there is no argument, then sit in a loop CLI style 221 | if ( args[1] == None ): 222 | cmd_str = None; 223 | # while ( cmd_str != "" ): 224 | while ( True ): 225 | print("bd>",end=""); 226 | cmd_str = input(); 227 | rts = cmd.proc( cmd_str ); 228 | if ( rts != None ): 229 | for each in rts: 230 | print("%s" % each ); 231 | return; 232 | # If args[1] is a file, open it and process one line at a time 233 | elif ( path.exists( args[1] ) ): 234 | cmd_list = file2list( args[1] ); 235 | for cmd_str in cmd_list: 236 | rts = cmd.proc( cmd_str ); 237 | if ( rts != None ): 238 | for each in rts: 239 | print("%s" % each ); 240 | else: 241 | # If args[1] is not a file, just process the single command line args 242 | arg_str = filter( None, args[1:] ); 243 | cmd_str = ""; 244 | for each in arg_str: 245 | cmd_str += each + " "; 246 | rts = cmd.proc( cmd_str ); 247 | if ( rts != None ): 248 | for each in rts: 249 | print("%s" % each ); 250 | return; 251 | 252 | 253 | ############################################################################### 254 | try: 255 | if __name__=='__main__': main() 256 | except KeyboardInterrupt: 257 | print('Break!') 258 | # EOF 259 | -------------------------------------------------------------------------------- /python/class_lb_link.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | ############################################################################### 3 | # Source file : class_lb_link.py 4 | # Language : Python 3.3 or Python 3.5 5 | # Author : Kevin Hubbard 6 | # Description : 32bit Local Bus access using MesaBus 7 | # License : GPLv3 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | # ----------------------------------------------------------------------------- 21 | # History : 22 | # 01.01.2018 : khubbard : Created 23 | ############################################################################### 24 | 25 | 26 | 27 | ############################################################################### 28 | # Protocol interface for MesaBus over a FTDI USB3 connection. 29 | class lb_link: 30 | def __init__ ( self, mesa_bus, slot, subslot ): 31 | self.mesa_bus = mesa_bus; 32 | self.slot = slot; 33 | self.subslot = subslot; 34 | self.dbg_flag = False; 35 | 36 | def wr_repeat(self, addr, data_list ): 37 | self.wr( addr, data_list, repeat = True ); 38 | 39 | def wr(self, addr, data_list, repeat = False ): 40 | # LocalBus WR cycle is a Addr+Data payload 41 | # Mesabus has maximum payload of 255 bytes, or 63 DWORDs. 42 | # 1 DWORD is LB Addr, leaving 62 DWORDs available for data bursts 43 | # if data is more than 62 dwords, parse it down into multiple bursts 44 | each_addr = addr; 45 | if ( repeat == False ): 46 | mb_cmd = 0x0;# Burst Write 47 | else: 48 | mb_cmd = 0x2;# Write Repeat ( Multiple data to same address - FIFO like ) 49 | 50 | while ( len( data_list ) > 0 ): 51 | if ( len( data_list ) > 62 ): 52 | data_payload = data_list[0:62]; 53 | data_list = data_list[62:]; 54 | else: 55 | data_payload = data_list[0:]; 56 | data_list = []; 57 | payload = ( "%08x" % each_addr ); 58 | for each_data in data_payload: 59 | payload += ( "%08x" % each_data ); 60 | if ( repeat == False ): 61 | each_addr +=4;# maintain address for splitting into 62 DWORD bursts 62 | # print("MB.wr :" + payload ); 63 | self.mesa_bus.wr( self.slot, self.subslot, mb_cmd, payload ); 64 | return; 65 | 66 | def wr_packet(self, addr_data_list ): 67 | # FT600 has a 1024 byte limit. My 8bit interface halves that to 512 bytes 68 | # and send ASCII instead of binary, so 256 69 | max_packet_len = 30; 70 | while ( len( addr_data_list ) > 0 ): 71 | if ( len( addr_data_list ) > max_packet_len ): 72 | data_payload = addr_data_list[0:max_packet_len]; 73 | addr_data_list = addr_data_list[max_packet_len:]; 74 | else: 75 | data_payload = addr_data_list[0:]; 76 | addr_data_list = []; 77 | payload = ""; 78 | for each_data in data_payload: 79 | payload += ( "%08x" % each_data ); 80 | mb_cmd = 0x4;# Write Packet 81 | # print("MB.wr :" + payload ); 82 | self.mesa_bus.wr( self.slot, self.subslot, mb_cmd, payload ); 83 | return; 84 | 85 | def rd_repeat(self, addr, num_dwords ): 86 | rts = self.rd( addr = addr, num_dwords=num_dwords , repeat = True ); 87 | return rts; 88 | 89 | def rd(self, addr, num_dwords, repeat = False ): 90 | max_payload = 31; 91 | if ( num_dwords <= max_payload ): 92 | rts = self.rd_raw( addr, num_dwords, repeat ); 93 | else: 94 | # MesaBus has 63 DWORD payload limit, so split up into multiple reads 95 | dwords_remaining = num_dwords; 96 | rts = []; 97 | while( dwords_remaining > 0 ): 98 | if ( dwords_remaining <= max_payload ): 99 | rts += self.rd_raw( addr, dwords_remaining, repeat ); 100 | dwords_remaining = 0; 101 | else: 102 | rts += self.rd_raw( addr, max_payload, repeat ); 103 | dwords_remaining -= max_payload; 104 | if ( repeat == False ): 105 | addr += max_payload*4;# Note Byte Addressing 106 | return rts; 107 | 108 | def rd_raw(self, addr, num_dwords, repeat = False ): 109 | dwords_remaining = num_dwords; 110 | each_addr = addr; 111 | if ( repeat == False ): 112 | mb_cmd = 0x1;# Normal Read 113 | else: 114 | mb_cmd = 0x3;# Read Repeat ( Multiple data to same address ) 115 | 116 | # LocalBus RD cycle is a Addr+Len 8byte payload to 0x00,0x0,0x1 117 | payload = ( "%08x" % each_addr ) + ( "%08x" % num_dwords ); 118 | # print("MB.wr :" + payload ); 119 | self.mesa_bus.wr( self.slot, self.subslot, mb_cmd, payload ); 120 | rts_str = self.mesa_bus.rd( num_dwords = num_dwords ); 121 | # print("MB.rd :" + rts_str ); 122 | 123 | rts = []; 124 | if ( len( rts_str ) >= 8 ): 125 | while ( len( rts_str ) >= 8 ): 126 | rts_dword = rts_str[0:8]; 127 | rts_str = rts_str[8:]; 128 | try: 129 | rts += [ int( rts_dword, 16 ) ]; 130 | except: 131 | addr_str = "%08x" % each_addr; 132 | print("ERROR: Invalid LocalBus Read >" + 133 | addr_str + "< >" + rts_mesa + "< >" + rts_dword + "<"); 134 | if ( self.dbg_flag == "debug" ): 135 | sys.exit(); 136 | rts += [ 0xdeadbeef ]; 137 | else: 138 | print("ERROR: Invalid LocalBus Read >" + rts_str + "<"); 139 | rts += [ 0xdeadbeef ]; 140 | return rts; 141 | -------------------------------------------------------------------------------- /python/class_lb_tcp_link.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | ############################################################################### 3 | # Source file : class_lb_tcp_link.py 4 | # Language : Python 3.3 or Python 3.5 5 | # Author : Kevin Hubbard 6 | # Description : 32bit Local Bus access using MesaBus 7 | # License : GPLv3 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | # ----------------------------------------------------------------------------- 21 | # History : 22 | # 01.01.2018 : khubbard : Created 23 | ############################################################################### 24 | 25 | 26 | 27 | ############################################################################### 28 | # Protocol interface for MesaBus over a FTDI USB3 connection. 29 | class lb_tcp_link: 30 | # def __init__ ( self, mesa_bus, slot, subslot ): 31 | def __init__ ( self, ip, port ): 32 | # self.mesa_bus = mesa_bus; 33 | # self.slot = slot; 34 | # self.subslot = subslot; 35 | self.dbg_flag = False; 36 | 37 | try: 38 | import socket; 39 | except: 40 | raise RuntimeError("ERROR: socket is required"); 41 | try: 42 | self.sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM); 43 | self.sock.connect( ( ip, port ) );# "localhost", 21567 44 | self.sock.settimeout(5); # Dont wait forever 45 | except: 46 | self.sock = None; 47 | return; 48 | def close ( self ): 49 | self.sock.close(); 50 | 51 | def set_slot(self, addr): 52 | payload = "mesa_slot %02x\n" % addr; 53 | self.tx_tcp_packet( payload ); 54 | self.rx_tcp_packet(); 55 | return; 56 | 57 | def set_subslot(self, addr): 58 | payload = "mesa_subslot %02x\n" % addr; 59 | self.tx_tcp_packet( payload ); 60 | self.rx_tcp_packet(); 61 | return; 62 | 63 | def wr_repeat(self, addr, data_list ): 64 | self.wr( addr, data_list, repeat = True ); 65 | return; 66 | 67 | def wr(self, addr, data, repeat = False ): 68 | if ( repeat == False ): 69 | cmd = "w";# Normal Write : Single or Burst with incrementing address 70 | else: 71 | cmd = "W";# Write Multiple DWORDs to same address 72 | payload = "".join( [cmd + " %08x" % addr] + 73 | [" %08x" % int(d) for d in data] + 74 | ["\n"] ); 75 | self.tx_tcp_packet( payload ); 76 | self.rx_tcp_packet(); 77 | return; 78 | 79 | def wr_packet(self, addr_data_list ): 80 | return; 81 | 82 | def rd( self, addr, num_dwords=1, repeat = False ): 83 | if ( repeat == False ): 84 | cmd = "r";# Normal Read : Single or Burst with incrementing address 85 | else: 86 | cmd = "k";# Read Multiple DWORDs from single address 87 | payload = cmd + " %08x %08x\n" % (addr,(num_dwords-1));# 0=1DWORD,1=2DWORDs 88 | self.tx_tcp_packet( payload ); 89 | payload = self.rx_tcp_packet().rstrip(); 90 | dwords = payload.split(' '); 91 | rts = []; 92 | for dword in dwords: 93 | rts += [int( dword, 16 )]; 94 | return rts; 95 | 96 | def rd_repeat(self, addr, num_dwords ): 97 | rts = self.rd( addr, num_dwords, repeat = True ); 98 | return rts; 99 | 100 | def tx_tcp_packet( self, payload ): 101 | # A Packet is a 8char hexadecimal header followed by the payload. 102 | # The header is the number of bytes in the payload. 103 | header = "%08x" % len(payload); 104 | bin_data = (header+payload).encode("utf-8");# String to ByteArray 105 | self.sock.send( bin_data ); 106 | 107 | def rx_tcp_packet( self ): 108 | # Receive 1+ Packets of response. 1st Packet will start with header that 109 | # indicates how big the entire Backdoor payload is. Sit in a loop 110 | # receiving 1+ TCP packets until the entire payload is received. 111 | bin_data = self.sock.recv(1024); 112 | rts = bin_data.decode("utf-8");# ByteArray to String 113 | header = rts[0:8]; # Remove the header, Example "00000004" 114 | payload_len = int(header,16);# The Payload Length in Bytes, Example 0x4 115 | payload = rts[8:]; # Start of Payload is everything after header 116 | # 1st packet may not be entire payload so loop until we have it all 117 | while ( len(payload) < payload_len ): 118 | bin_data = self.sock.recv(1024); 119 | payload += bin_data.decode("utf-8");# ByteArray to String 120 | return payload; 121 | -------------------------------------------------------------------------------- /python/class_mesa_bus.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | ############################################################################### 3 | # Source file : class_mesa_bus.py 4 | # Language : Python 3.3 or Python 3.5 5 | # Author : Kevin Hubbard 6 | # Description : Access hardware over MesaBus 7 | # License : GPLv3 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | # ----------------------------------------------------------------------------- 21 | # History : 22 | # 01.01.2018 : khubbard : Created 23 | ############################################################################### 24 | 25 | 26 | 27 | ############################################################################### 28 | # Routines for Reading and Writing Payloads over MesaBus 29 | # A payload is a series of bytes in hexadecimal string format. A typical use 30 | # for MesaBus is to transport a higher level Local Bus protocol for 32bit 31 | # writes and reads. MesaBus is lower level and transports payloads to a 32 | # specific device on a serial chained bus based on the Slot Number. 33 | # More info at : https://blackmesalabs.wordpress.com/2016/03/04/mesa-bus/ 34 | # 0x0 : Write Cycle : Payload of ... 35 | # 0x1 : Read Cycle : Payload of 36 | # 0x2 : Write Repeat : Write burst data to single address : ... 37 | # 0x3 : Read Repeat : Read burst data from single address : 38 | # 0x4 : Write Multiple : Payload of .. 39 | class mesa_bus: 40 | def __init__ ( self, phy_link ): 41 | self.phy_link = phy_link; 42 | # if ( type( phy_link ) == uart_usb_link ): 43 | # self.lf = "\n"; 44 | # else: 45 | # self.lf = ""; 46 | self.lf = "\n"; 47 | # self.phy_link.wr( self.lf );# 48 | self.phy_link.wr( 256*"FF" + self.lf );# 49 | 50 | 51 | def wr( self, slot, subslot, cmd, payload ): 52 | preamble = "FFF0";# Establish nibble-byte ordering "F0" is 1st Byte 53 | slot = "%02x" % slot; 54 | subslot = "%01x" % subslot; 55 | cmd = "%01x" % cmd; 56 | num_bytes = "%02x" % int( len( payload ) / 2 ); 57 | mesa_str = preamble + slot + subslot + cmd + num_bytes + payload + self.lf; 58 | self.phy_link.wr( mesa_str ); 59 | return; 60 | 61 | def rd( self, num_dwords ): 62 | # "F0FE0004"+"12345678" 63 | # "04" is num payload bytes and "12345678" is the read payload 64 | rts = self.phy_link.rd( bytes_to_read = (1+num_dwords)*4 ); 65 | if ( len( rts ) > 8 ): 66 | rts = rts[8:];# Strip the "FOFE0004" header 67 | return rts; 68 | -------------------------------------------------------------------------------- /python/class_spi_prom.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | ############################################################################### 3 | # Source file : class_spi_prom.py 4 | # Language : Python 3.7 5 | # Author : Kevin Hubbard 6 | # Description : Access SPI PROM via MesaBus and spi_prom.v 7 | # License : GPLv3 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | # ----------------------------------------------------------------------------- 21 | # History : 22 | # 01.01.2018 : khubbard : Created 23 | ############################################################################### 24 | from common_functions import file2list; 25 | from common_functions import list2file; 26 | 27 | 28 | ############################################################################### 29 | # Software Interface layer to spi_prom.v. This IP block is two registers, a 30 | # control register and a data streaming register that connects to a small FSM 31 | # and Block RAM for writing 256 bytes at a time to a SPI PROM. 32 | # These spi_* functions interface via Backdoor to 2 LocalBus mapped registers 33 | # connected to spi_prom.v that then interfaces via SPI to a SPI PROM. 34 | # Interface is a 32bit LB Command Register and a 32bit LB Streaming Data Reg 35 | class spi_prom: 36 | def __init__ ( self, lb_link ): 37 | self.bd = lb_link; 38 | # These are some constants from spi_prom.v 39 | self.prom_stat_spi_busy = 0x80; 40 | self.prom_stat_mosi_polling_reqd = 0x40; 41 | self.prom_stat_mosi_rdy = 0x20; 42 | self.prom_stat_miso_rdy = 0x10; 43 | self.prom_stat_state_wr = 0x08; 44 | self.prom_stat_unlocked = 0x04; 45 | self.prom_stat_prom_wip = 0x02; 46 | self.prom_stat_spi_busy = 0x01; 47 | self.prom_cmd_erase_bulk = 0x05; 48 | self.prom_cmd_erase_sector = 0x06; 49 | self.prom_cmd_wr_prom = 0x07; 50 | self.prom_cmd_boot = 0x08; 51 | self.prom_cmd_rd_prom = 0x03; 52 | self.prom_cmd_rd_timestamp = 0x02; 53 | self.prom_cmd_id = 0x01; 54 | self.prom_cmd_root = 0x05aaa504; 55 | self.prom_cmd_boot_unlock = 0x055a5504; 56 | self.prom_cmd_wr_enable = 0x0aa5aa04; 57 | self.prom_cmd_wr_disable = 0x00000004; 58 | self.prom_ctrl_addr = 0x20; 59 | self.prom_data_addr = self.prom_ctrl_addr + 0x04; 60 | self.prom_id_list = ( (0x01,"Spansion"), \ 61 | (0x20,"Micron"), \ 62 | (0xC2,"Macronix"), \ 63 | ); 64 | self.cmd_list= ["prom_dump","prom_load","prom_root","prom_boot","prom_id"]; 65 | self.help = []; 66 | h = self.help; 67 | h+=["# PROM Access commands "]; 68 | h+=["# prom_root : Unlock slot-0 if locked "]; 69 | h+=["# prom_boot addr : Reboot FPGA from PROM addr "]; 70 | h+=["# prom_dump addr : Dump sector at addr "]; 71 | h+=["# prom_load file addr : Load PROM from top.bin file to addr "]; 72 | h+=["# Note: addr may also be slot0 or slot1 "]; 73 | 74 | def proc_cmd( self, cmd_txt, cmd_str ): 75 | if ( cmd_txt == "prom_dump" ): return self.cmd_prom_dump( cmd_str ); 76 | if ( cmd_txt == "prom_load" ): return self.cmd_prom_load( cmd_str ); 77 | if ( cmd_txt == "prom_root" ): return self.cmd_prom_root( cmd_str ); 78 | if ( cmd_txt == "prom_boot" ): return self.cmd_prom_boot( cmd_str ); 79 | if ( cmd_txt == "prom_id" ): return self.cmd_prom_id( cmd_str ); 80 | 81 | def cmd_prom_id( self, cmd_str ): 82 | try: 83 | rts = []; 84 | (vendor_id, prom_size_mb ) = self.prom_id(); 85 | timestamp = self.prom_timestamp(); 86 | slot_size = self.prom_slotsize(); 87 | import time; 88 | means = time.ctime(timestamp) 89 | 90 | rts += [ ("Manufacturer: %s" % vendor_id ) ]; 91 | rts += [ ("Size: %d Mb" % prom_size_mb ) ]; 92 | rts += [ ("Slot_Size: %08x" % slot_size ) ]; 93 | rts += [ ("Timestamp: %08x : %s " % (timestamp,means) ) ]; 94 | except: 95 | rts = ["ERROR: cmd_prom_id() unable to communicate with Hardware"]; 96 | return rts; 97 | 98 | def cmd_prom_boot( self, cmd_str ): 99 | words = " ".join(cmd_str.split()).split(' ') + [None] * 4; 100 | addr = int(words[1],16); 101 | try: 102 | rts = self.prom_boot( addr ); 103 | except: 104 | rts = ["ERROR: cmd_prom_boot() unable to communicate with Hardware"]; 105 | return rts; 106 | 107 | def cmd_prom_dump( self, cmd_str ): 108 | try: 109 | words = " ".join(cmd_str.split()).split(' ') + [None] * 4; 110 | addr = int(words[1],16); 111 | rts = self.prom_dump( addr = addr ); 112 | txt_rts = [ "%08x" % each for each in rts ];# list comprehension 113 | except: 114 | txt_rts = ["ERROR: cmd_prom_dump() unable to communicate with Hardware"]; 115 | return txt_rts; 116 | 117 | # "prom_load top.bin slot1" or "prom_load top.bin 00200000" 118 | def cmd_prom_load( self, cmd_str ): 119 | try: 120 | words = " ".join(cmd_str.split()).split(' ') + [None] * 4; 121 | if ( words[2][0:4] == "slot" ): 122 | slot_size = self.prom_slotsize(); 123 | addr = slot_size * int(words[2][4], 10 ); 124 | else: 125 | addr = int( words[2], 16 ); 126 | bitstream = file2list( words[1], binary = True ); 127 | print("Loading %s to address %08x" % ( words[1], addr ) ); 128 | rts = self.prom_load( addr, bitstream ); 129 | except: 130 | rts = ["ERROR: cmd_prom_load() unable to communicate with Hardware"]; 131 | return rts; 132 | 133 | def cmd_prom_root( self, cmd_str ): 134 | try: 135 | rts = self.prom_root(); 136 | except: 137 | rts = ["ERROR: cmd_prom_root() unable to communicate with Hardware"]; 138 | return rts; 139 | 140 | 141 | def prom_id( self ): 142 | self.spi_tx_ctrl( self.prom_cmd_id ); 143 | rts = self.spi_rx_data( 1 ); 144 | vendor_id = "unknown"; 145 | for ( id_hex, id_str ) in self.prom_id_list: 146 | if ( id_hex == ( rts[0] & 0x000000FF ) ): 147 | vendor_id = id_str; 148 | prom_size_mb = 2**((rts[0] & 0x00FF0000)>>16)/131072; 149 | return ( vendor_id, prom_size_mb ); 150 | 151 | def prom_timestamp( self ): 152 | self.spi_tx_ctrl( self.prom_cmd_rd_timestamp ); 153 | rts = self.spi_rx_data( num_dwords = 2 ); 154 | return rts[0]; 155 | 156 | def prom_slotsize( self ): 157 | self.spi_tx_ctrl( self.prom_cmd_rd_timestamp ); 158 | rts = self.spi_rx_data( num_dwords = 2 ); 159 | return rts[1]; 160 | 161 | def prom_root( self ): 162 | self.spi_tx_ctrl( self.prom_cmd_root ); 163 | return; 164 | 165 | def prom_boot( self, addr ): 166 | dword = self.prom_cmd_boot_unlock; 167 | self.spi_tx_ctrl( dword ); 168 | dword = (addr & 0xFFFFFF00 ) | self.prom_cmd_boot; 169 | self.spi_tx_ctrl( dword ); 170 | return; 171 | 172 | def prom_erase( self, addr ): 173 | dword = (addr & 0xFFFFFF00 ) | self.prom_cmd_erase_sector; 174 | self.spi_tx_ctrl( dword );# Address+Sector Erase Command 175 | bit_status = self.prom_stat_prom_wip; i = 0; 176 | while ( bit_status == self.prom_stat_prom_wip and i < 1000 ): 177 | rts = self.bd.rd( self.prom_ctrl_addr,1 )[0]; 178 | bit_status = rts & self.prom_stat_prom_wip; 179 | i +=1; 180 | return; 181 | 182 | def prom_dump( self, addr ): 183 | dword = (addr & 0xFFFFFF00 ) | self.prom_cmd_rd_prom; 184 | self.spi_tx_ctrl( dword );# Address+Sector Read Command 185 | rts = self.spi_rx_data( num_dwords = 64 );# 64 DWORDs = 256 Bytes 186 | return rts; 187 | 188 | def prom_load( self, addr, data_byte_list ): 189 | import time; 190 | t0 = time.time(); 191 | 192 | self.spi_tx_ctrl( self.prom_cmd_wr_enable );# Unlock for Writing 193 | # A sector is 64K, or 256 pages of 256 bytes. 194 | page_cnt = 0; 195 | bytes_remaining = len( data_byte_list ); 196 | bits_total = bytes_remaining * 8; 197 | while( bytes_remaining > 0 ): 198 | if ( page_cnt == 0 ): 199 | print("Erasing sector at %08x" % addr ); 200 | t1 = time.time(); 201 | self.prom_erase( addr );# Erase this sector 202 | # t2 = time.time(); 203 | # print(" %d Seconds" % ( t2-t1 ) ); 204 | print("Writing sector"); 205 | dword = ( addr & 0xFFFFFF00 ) | self.prom_cmd_wr_prom; 206 | self.spi_tx_ctrl( dword );# Write Command 207 | page_cnt += 1; 208 | if ( page_cnt == 256 ): 209 | page_cnt = 0; 210 | t3 = time.time(); 211 | print(" %d Seconds" % ( t3-t1 ) ); 212 | 213 | # Extract 256 bytes from entire byte list 214 | if ( bytes_remaining > 256 ): 215 | write_bytes = data_byte_list[0:256]; 216 | else: 217 | write_bytes = (data_byte_list + [0x00]*256)[0:256];# Pad 00s 218 | data_byte_list = data_byte_list[256:]; 219 | data_dword_list = []; 220 | for i in range (0,64): 221 | dword = 0; 222 | for j in range (0,4,+1): 223 | dword = dword << 8; 224 | dword = dword | write_bytes[(i*4)+j]; 225 | data_dword_list += [ dword ]; 226 | # Send payload if the MOSI Buffer is Free 227 | self.spi_wait_for_mosi_free(); 228 | self.spi_tx_data( data_dword_list ); 229 | addr += 256; 230 | bytes_remaining = len( data_byte_list ); 231 | self.spi_wait_for_mosi_free(); 232 | self.spi_tx_ctrl( self.prom_cmd_wr_disable );# lock back up 233 | t4 = time.time(); 234 | bits_total = int( bits_total / ( 1024 * 1024 )); 235 | print(" %d Seconds for %d Mbits" % ( ( t4-t0 ), bits_total ) ); 236 | return; 237 | 238 | def spi_tx_ctrl( self, byte_cmd ): 239 | # Sit in a loop until SPI_BUSY is cleared 240 | bit_status = 0x1; i = 0; 241 | while ( bit_status == 0x1 and i < 1000 ): 242 | rts = self.bd.rd( self.prom_ctrl_addr,1 )[0]; 243 | bit_status = rts & self.prom_stat_spi_busy; # SPI_BUSY Bit 244 | i +=1; 245 | if ( i == 1000 ): 246 | print("ERROR: spi_tx_ctrl() Timeout Abort"); 247 | # print("w %08x %08x" % ( self.prom_ctrl_addr, byte_cmd ) ); 248 | self.bd.wr( self.prom_ctrl_addr, [ byte_cmd ] ); 249 | return; 250 | 251 | def spi_wait_for_mosi_free( self ): 252 | bit_status = 0x0; i = 0; 253 | while ( bit_status == 0x0 and i < 1000 ): 254 | rts = self.bd.rd( self.prom_ctrl_addr,1 )[0]; 255 | bit_status = rts & self.prom_stat_mosi_rdy; # 256 | i +=1; 257 | if ( i == 1000 ): 258 | print("ERROR: spi_tx_ctrl() Timeout Abort"); 259 | return; 260 | 261 | def spi_tx_data( self, data_payload ): 262 | self.bd.wr_repeat( addr=self.prom_data_addr, data_list=data_payload ); 263 | return; 264 | 265 | def spi_rx_data( self, num_dwords ): 266 | rts = self.bd.rd_repeat( addr=self.prom_data_addr, num_dwords=num_dwords ); 267 | return rts; 268 | -------------------------------------------------------------------------------- /python/class_uart_usb_link.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | ############################################################################### 3 | # Source file : class_uart_usb_link.py 4 | # Language : Python 3.3 or Python 3.5 5 | # Author : Kevin Hubbard 6 | # Description : Access to HW via FT232 like standard serial port 7 | # License : GPLv3 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | # ----------------------------------------------------------------------------- 21 | # History : 22 | # 01.01.2018 : khubbard : Created 23 | ############################################################################### 24 | 25 | 26 | ############################################################################### 27 | # Serial port class for sending and receiving ASCII strings to FT232RL UART 28 | class uart_usb_link(object): 29 | def __init__ ( self, port_name, baudrate ): 30 | try: 31 | import serial; 32 | except: 33 | raise RuntimeError("ERROR: PySerial from sourceforge.net is required"); 34 | raise RuntimeError( 35 | "ERROR: Unable to import serial\n"+ 36 | "PySerial from sourceforge.net is required for Serial Port access."); 37 | try: 38 | self.ser = serial.Serial( port=port_name, baudrate=baudrate, 39 | bytesize=8, parity='N', stopbits=1, 40 | timeout=1, xonxoff=0, rtscts=0,dsrdtr=0); 41 | self.port = port_name; 42 | self.baud = baudrate; 43 | self.ser.flushOutput(); 44 | self.ser.flushInput(); 45 | self.ack_state = True; 46 | except: 47 | raise RuntimeError("ERROR: Unable to open USB COM Port "+port_name) 48 | 49 | def rd( self, bytes_to_read ): 50 | rts = self.ser.readline(); 51 | return rts; 52 | 53 | def wr( self, str ): 54 | self.ser.write( str.encode("utf-8") ); 55 | return; 56 | 57 | def close(self): 58 | self.ser.close(); 59 | return; 60 | -------------------------------------------------------------------------------- /python/class_user.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | ############################################################################### 3 | # Source file : class_user.py 4 | # Language : Python 3.7 5 | # Author : Kevin Hubbard 6 | # Description : Example class for user defined add-on functions. 7 | # License : GPLv3 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | # 21 | # Note: cmd_str is a text string from the command line "user1 foo" for example. 22 | # rts is a list of text strings that the CLI will display on completion. 23 | # ----------------------------------------------------------------------------- 24 | # History : 25 | # 01.01.2018 : khubbard : Created 26 | ############################################################################### 27 | from common_functions import file2list; 28 | from common_functions import list2file; 29 | 30 | 31 | 32 | ############################################################################### 33 | # Example user class and methods. 34 | # user1 writes and reads a value from register 0x00 35 | # user2 reads value at register 0x04, increments it by +1 then reads again 36 | class user: 37 | def __init__ ( self, lb_link ): 38 | self.bd = lb_link; 39 | # These are some constants from spi_prom.v 40 | # self.user_reg_00 = 0x00000000; 41 | # self.user_reg_04 = 0x00000004; 42 | # self.dram_start_addr = 0x00000004; 43 | # self.dram_len_dwords = 0x00000002; 44 | self.cmd_list= ["user1","user2","user3","dram_write","dram_read","dram_test"]; 45 | ( self.help, self.detailed_help ) = self.init_help(); 46 | 47 | 48 | def proc_cmd( self, cmd_txt, cmd_str ): 49 | if ( cmd_txt == "user1" ) : return self.user1( cmd_str ); 50 | if ( cmd_txt == "user2" ) : return self.user2( cmd_str ); 51 | if ( cmd_txt == "user3" ) : return self.user3( cmd_str ); 52 | if ( cmd_txt == "dram_write" ) : return self.dram_write( cmd_str ); 53 | if ( cmd_txt == "dram_read" ) : return self.dram_read( cmd_str ); 54 | if ( cmd_txt == "dram_test" ) : return self.dram_test( cmd_str ); 55 | 56 | 57 | def user1( self, cmd_str ): 58 | self.bd.wr( self.user_reg_00, [ 0x11223344 ] ); 59 | rts = ["%08x" % ( self.bd.rd( self.user_reg_00,1 )[0] ) ]; 60 | return rts; 61 | 62 | 63 | def user2( self, cmd_str ): 64 | rts = self.bd.rd( self.user_reg_04,1 ); 65 | val = rts[0]; 66 | val +=1; 67 | self.bd.wr( self.user_reg_04, [ val ] ); 68 | rts = ["%08x" % ( self.bd.rd( self.user_reg_04,1 )[0] ) ]; 69 | return rts; 70 | 71 | 72 | def user3( self, cmd_str ): 73 | rts = self.bd.rd( self.user_reg_00,2 ); 74 | txt_rts = [ "%08x" % each for each in rts ];# list comprehension 75 | list2file( "bar.txt", txt_rts ); 76 | rts = ["File bar.txt written"]; 77 | return rts; 78 | 79 | 80 | def dram_write( self, cmd_str ): 81 | words = " ".join(cmd_str.split()).split(' ') + [None] * 4; 82 | if ( words[1] == None ): 83 | rts = []; 84 | rts += ["dram_write start_addr num_dwords data_dword"]; 85 | rts += [" start_addr : Hex start address, example 01000000"]; 86 | rts += [" num_dwords : Hex length in dwords, example 100"]; 87 | rts += [" data_dword : Hex data pattern, example 12345678"]; 88 | else: 89 | start_addr = int( words[1], 16 ); 90 | num_dwords = int( words[2], 16 ); 91 | data_dword = int( words[3], 16 ); 92 | data_list = [ data_dword ] * num_dwords; 93 | self.bd.wr( start_addr, data_list ); 94 | # rts = [ "%08x" % each for each in data_list ];# list comprehension 95 | rts = []; 96 | return rts; 97 | 98 | 99 | def dram_read( self, cmd_str ): 100 | words = " ".join(cmd_str.split()).split(' ') + [None] * 4; 101 | if ( words[1] == None ): 102 | rts = []; 103 | rts += ["dram_read start_addr num_dwords filename"]; 104 | rts += [" start_addr : Hex start address, example 01000000"]; 105 | rts += [" num_dwords : Hex length in dwords, example 100"]; 106 | rts += [" filename : Optional. Dump to file instead of console"]; 107 | else: 108 | start_addr = int( words[1], 16 ); 109 | num_dwords = int( words[2], 16 ); 110 | filename = words[3]; 111 | hex_rts = self.bd.rd( start_addr, num_dwords ); 112 | rts = [ "%08x" % each for each in hex_rts ];# list comprehension 113 | if ( filename != None ): 114 | list2file( filename, rts ); 115 | rts = ["%s written" % filename ]; 116 | return rts; 117 | 118 | 119 | def dram_test( self, cmd_str ): 120 | words = " ".join(cmd_str.split()).split(' ') + [None] * 4; 121 | if ( words[1] == None ): 122 | rts = []; 123 | rts += ["dram_test start_addr num_dwords data_dword read_iters filename"]; 124 | rts += [" start_addr : Hex start address, example 01000000"]; 125 | rts += [" num_dwords : Hex length in dwords, example 100"]; 126 | rts += [" data_dword : Hex data pattern, example 12345678"]; 127 | rts += [" read_iters : Optional Hex read iterations example 2" ]; 128 | rts += [" filename : Optional. Dump to file instead of console"]; 129 | else: 130 | start_addr = int( words[1], 16 ); 131 | num_dwords = int( words[2], 16 ); 132 | data_dword = int( words[3], 16 ); 133 | if ( words[4] == None ): 134 | read_iters = 1; 135 | else: 136 | read_iters = int( words[4], 16 ); 137 | filename = words[5]; 138 | data_list = [ data_dword ] * num_dwords; 139 | self.bd.wr( start_addr, data_list ); 140 | rts = []; 141 | for i in range(0,read_iters ): 142 | rd_list = self.bd.rd( start_addr, num_dwords ); 143 | for ( j, rd_dword ) in enumerate( rd_list ): 144 | if ( rd_dword != data_list[j] ): 145 | addr = start_addr + 4*j;# Note DWORD to Byte Addr Translation 146 | rts += ["%04x %08x : %08x != %08x" % ( i, addr, rd_dword, data_list[j])]; 147 | if ( filename != None ): 148 | list2file( filename, rts ); 149 | rts = ["%s written" % filename ]; 150 | return rts; 151 | 152 | 153 | def init_help( self ): 154 | h= []; 155 | dh= []; 156 | h+=["# DRAM Access commands "]; 157 | h+=["# dram_write : Write a pattern to DRAM "]; 158 | h+=["# dram_read : Read data from DRAM "]; 159 | h+=["# dram_test : Write then Readback a pattern to DRAM "]; 160 | dh+=[("dram_write", 161 | "dram_write start_addr num_dwords data_dword\n" +\ 162 | " start_addr : Hex start address, example 01000000\n" +\ 163 | " num_dwords : Hex length in dwords, example 100\n" +\ 164 | " data_dword : Hex data pattern, example 12345678\n" )]; 165 | dh+=[("dram_read", 166 | "dram_read start_addr num_dwords filename\n" +\ 167 | " start_addr : Hex start address, example 01000000\n" +\ 168 | " num_dwords : Hex length in dwords, example 100\n" +\ 169 | " filename : Optional dump to file \n" )]; 170 | dh+=[("dram_test", 171 | "dram_test start_addr num_dwords data_dword read_iters filename\n" +\ 172 | " start_addr : Hex start address, example 01000000\n" +\ 173 | " num_dwords : Hex length in dwords, example 100\n" +\ 174 | " data_dword : Hex data pattern, example 12345678\n" +\ 175 | " read_iters : Hex read iterations, example 2\n" +\ 176 | " filename : Optional dump to file \n" )]; 177 | return (h,dh); 178 | 179 | # EOF 180 | -------------------------------------------------------------------------------- /python/common_functions.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | ############################################################################### 3 | # Source file : common_functions.py 4 | # Language : Python 3.3 or Python 3.5 5 | # Author : Kevin Hubbard 6 | # Description : Commonly used functions 7 | # License : GPLv3 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | # ----------------------------------------------------------------------------- 21 | # History : 22 | # 08.28.2018 : khubbard : Created 23 | ############################################################################### 24 | # Example for referencing from other file: 25 | # from common_functions import file2list; 26 | # from common_functions import list2file; 27 | 28 | 29 | def list2file( file_name, my_list, concat = False ): 30 | if ( concat ): 31 | type = 'a'; 32 | else: 33 | type = 'w'; 34 | 35 | file_out = open( file_name, type ); 36 | for each in my_list: 37 | file_out.write( each + "\n" ); 38 | file_out.close(); 39 | return; 40 | 41 | 42 | def file2list( file_name, binary = False ): 43 | if ( binary == False ): 44 | file_in = open ( file_name, 'r' ); 45 | file_list = file_in.readlines(); 46 | file_list = [ each.strip('\n') for each in file_list ];# list comprehension 47 | return file_list; 48 | else: 49 | # See https://stackoverflow.com/questions/1035340/ 50 | # reading-binary-file-and-looping-over-each-byte 51 | byte_list = []; 52 | file_in = open ( file_name, 'rb' ); 53 | try: 54 | byte = file_in.read(1); 55 | while ( byte ): 56 | byte_list += [ord(byte)]; 57 | byte = file_in.read(1); 58 | finally: 59 | file_in.close(); 60 | return byte_list; 61 | 62 | 63 | ############################################################################### 64 | # Given a file_header ( like foo_ ), check for foo_0000, then foo_0001, etc 65 | # and return 1st available name. 66 | def make_unique_filename( self, file_header, file_ext ): 67 | import os; 68 | num = 0; 69 | while ( True ): 70 | file_name = file_header + ( "%04d" % num ) + file_ext; 71 | if ( os.path.exists( file_name ) == False ): 72 | return file_name; 73 | else: 74 | num +=1; 75 | return None; 76 | -------------------------------------------------------------------------------- /python/ico_gpio.py: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # (C) Copyright 2016 Kevin M. Hubbard, Black Mesa Labs 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program. If not, see . 14 | # 15 | # 11.25.2016 : Kevin M. Hubbard created 16 | # 17 | # Installing spidev for RaspberryPi for SPI communications 18 | # sudo apt-get install python-dev 19 | # sudo apt-get install git 20 | # git clone git://github.com/doceme/py-spidev 21 | # cd py-spidev 22 | # sudo python setup.py install 23 | ############################################################################## 24 | #import os.path; 25 | #from pygame.locals import * 26 | #import array; 27 | #import random; 28 | 29 | import time; 30 | import sys; 31 | import datetime; 32 | from time import sleep; 33 | import spidev; 34 | 35 | class App (): 36 | def __init__(self): 37 | return; 38 | 39 | def main(self): 40 | self.main_init(); 41 | self.main_loop(); 42 | 43 | def main_init( self ): 44 | args = sys.argv + [None]*5;# args[0] is this scripts name 45 | self.dbg_flag = args[1];# ie debug or display or pi etc 46 | 47 | # use SPI for MesaBus instead of UART 48 | self.spi_port = spidev.SpiDev(); 49 | self.spi_port.open(0,1);# Note: icoboard uses CE0 for Mach, CE1 for Ice 50 | # Note: SPI rate works up to 32 MHz, but the CS_L time is software 51 | # controlled and the gap between 2 byte cycles is always about 300us 52 | # Low Level SPI Timing 53 | # 1 MHz : Write = 200uS, Read = 127uS 54 | # 32 MHz : Write = 20uS, Read = 12uS 55 | # LocalBus Timing 56 | # Write : 800uS ( two back to back ) 57 | # Read : 400uS 58 | self.spi_port.max_speed_hz = 32000000;# 1-32 MHz typical 59 | self.mb = mesa_bus( self.spi_port);# Establish a MesaBus link 60 | self.lb = local_bus( self.mb, self.dbg_flag );# Establish a LocalBus link 61 | self.define_reg_space(); 62 | 63 | 64 | # print("Sleeping 5sec to allow for SUMP2 Arm"); 65 | # sleep(5.0); 66 | # # On PMOD P2, drive a 8bit binary counter to LEDs 67 | # for i in range( 0,256,1 ): 68 | # self.lb.wr( self.reg_pmod_p2_ctrl, [ i ] ); 69 | # data = self.lb.rd( self.reg_pmod_p2_ctrl, 1 )[0]; 70 | # sleep(0.02); 71 | # self.lb.wr( self.reg_pmod_p2_ctrl, [0x55] ); 72 | # print("READ %08X" % data ); 73 | # sys.exit(); 74 | 75 | # Read MesaBus ID information from this FPGA 76 | ( id_mfr, id_dev, id_snum, id_timestamp, english_time ) = self.mesa_id(); 77 | print( id_mfr ); 78 | print( id_dev ); 79 | print( id_snum ); 80 | print( id_timestamp ); 81 | print( english_time ); 82 | 83 | # Read some registers 84 | data = self.lb.rd( 0x00000000, 1 )[0]; 85 | print("READ %08X" % data ); 86 | data = self.lb.rd( 0x00000004, 1 )[0]; 87 | print("READ %08X" % data ); 88 | data = self.lb.rd( 0x00000008, 1 )[0]; 89 | print("READ %08X" % data ); 90 | 91 | # Configure GPIO Pins on the 4 PMOD connectors P1,P2,P3,P4 92 | # Note: see source/reg_space.txt for bitfield definitions 93 | self.lb.wr( self.reg_pmod_p1_cfg , [ 0x77777777 ] );# Watch SPI Traffic 94 | # self.lb.wr( self.reg_pmod_p2_cfg , [ 0x11111111 ] ); 95 | # self.lb.wr( self.reg_pmod_p3_cfg , [ 0x11111111 ] ); 96 | # self.lb.wr( self.reg_pmod_p4_cfg , [ 0x11111111 ] ); 97 | # sys.exit(); 98 | 99 | # self.lb.wr( self.reg_pmod_p1_ctrl, [ 0x00000001 ] ); 100 | # self.lb.wr( self.reg_pmod_p2_ctrl, [ 0x00000003 ] ); 101 | # self.lb.wr( self.reg_pmod_p3_ctrl, [ 0x00000007 ] ); 102 | # self.lb.wr( self.reg_pmod_p4_ctrl, [ 0x0000000f ] ); 103 | 104 | # self.lb.wr( self.reg_pmod_p1_cfg , [ 0x00000a98 ] );# PWM0,1 and 2 105 | self.lb.wr( self.reg_pmod_p2_cfg , [ 0xfedcba98 ] );# PWM0,1 and 2 106 | self.lb.wr( self.reg_pmod_p3_cfg , [ 0xfedcba98 ] );# PWM0,1 and 2 107 | self.lb.wr( self.reg_pmod_p4_cfg , [ 0xfedcba98 ] );# PWM0,1 and 2 108 | self.lb.wr( self.reg_pwm0_cfg, [ 0x01001013 ] ); 109 | self.lb.wr( self.reg_pwm1_cfg, [ 0x01002013 ] ); 110 | self.lb.wr( self.reg_pwm2_cfg, [ 0x01004013 ] ); 111 | self.lb.wr( self.reg_pwm3_cfg, [ 0x01008013 ] ); 112 | self.lb.wr( self.reg_pwm4_cfg, [ 0x01001023 ] ); 113 | self.lb.wr( self.reg_pwm5_cfg, [ 0x02001023 ] ); 114 | self.lb.wr( self.reg_pwm6_cfg, [ 0x04001023 ] ); 115 | self.lb.wr( self.reg_pwm7_cfg, [ 0x08001023 ] ); 116 | 117 | # On PMOD P2, drive a 8bit binary counter to LEDs 118 | # for i in range( 0,256,1 ): 119 | # self.lb.wr( self.reg_pmod_p2_ctrl, [ i ] ); 120 | # sleep(0.02); 121 | # self.lb.wr( self.reg_pmod_p2_ctrl, [0x55] ); 122 | sys.exit(); 123 | 124 | # if ( self.platform == "pi" ): 125 | # import os; 126 | # os.system("sudo shutdown -h now"); 127 | 128 | def main_loop( self ): 129 | self.test = False; 130 | while (True): 131 | sleep(1); 132 | print("Looping"); 133 | 134 | def mesa_id( self ): 135 | # Issue a low level MesaBus ID Request and make sure FPGA responds 136 | try: 137 | self.mb.wr( slot = 0x00, subslot = 0xF, cmd = 0xA, payload = "" ); 138 | rts = self.mb.port.xfer2(20*[0xFF]); 139 | hex_str = ""; 140 | for each in rts: 141 | hex_str += ("%02x" % each ); 142 | rts = hex_str; 143 | if ( len( rts ) == 40 ): 144 | mesa_header = rts[0:8]; 145 | id_mfr = rts[8:16]; 146 | id_dev = rts[16:24]; 147 | id_snum = rts[24:32]; 148 | id_time = rts[32:40]; 149 | english_time = datetime.datetime.fromtimestamp(int( \ 150 | id_time,16)).strftime('%Y-%m-%d %H:%M:%S'); 151 | return ( id_mfr, id_dev, id_snum, id_time,english_time ); 152 | else: 153 | return False; 154 | except: 155 | return False; 156 | 157 | def define_reg_space(self): 158 | self.reg_id = 0x00000000; 159 | self.reg_version = 0x00000004; 160 | self.reg_timestamp = 0x00000008; 161 | self.reg_chip_ctrl = 0x0000000c; 162 | self.reg_sump2_ctrl = 0x00000010; 163 | self.reg_sump2_data = 0x00000014; 164 | self.reg_pmod_p1_cfg = 0x00000020; 165 | self.reg_pmod_p2_cfg = 0x00000024; 166 | self.reg_pmod_p3_cfg = 0x00000028; 167 | self.reg_pmod_p4_cfg = 0x0000002c; 168 | self.reg_pmod_p1_ctrl = 0x00000030; 169 | self.reg_pmod_p2_ctrl = 0x00000034; 170 | self.reg_pmod_p3_ctrl = 0x00000038; 171 | self.reg_pmod_p4_ctrl = 0x0000003c; 172 | self.reg_pwm0_cfg = 0x00000080; 173 | self.reg_pwm1_cfg = 0x00000084; 174 | self.reg_pwm2_cfg = 0x00000088; 175 | self.reg_pwm3_cfg = 0x0000008c; 176 | self.reg_pwm4_cfg = 0x00000090; 177 | self.reg_pwm5_cfg = 0x00000094; 178 | self.reg_pwm6_cfg = 0x00000098; 179 | self.reg_pwm7_cfg = 0x0000009c; 180 | return; 181 | 182 | def quit(self): 183 | pygame.display.quit(); 184 | 185 | 186 | ############################################################################### 187 | # Routines for Reading and Writing a remote 32bit LocalBus over MesaBus 188 | # A local bus cycle is a pre-determined payload transported over the MesaBus 189 | # LocalBus is mapped to SubSlot 0x0 190 | # 0x0 : Write DWORD or Burst starting at Address 191 | # 0x1 : Read DWORD or Burst starting at Address 192 | # 0x2 : Write Multiple DWORDs to same Address 193 | # 0x3 : Read Multiple DWORDs from same Address 194 | class local_bus: 195 | def __init__ ( self, mesa_bus, dbg_flag ): 196 | self.mesa_bus = mesa_bus; 197 | self.dbg_flag = dbg_flag; 198 | 199 | def wr( self, addr, data ): 200 | # LocalBus WR cycle is a Addr+Data 8byte payload 201 | # Mesabus has maximum payload of 255 bytes, or 63 DWORDs. 202 | # 1 DWORD is LB Addr, leaving 62 DWORDs available for data bursts 203 | # if data is more than 62 dwords, parse it into multiple bursts 204 | each_addr = addr; 205 | data_list = data; 206 | while ( len( data_list ) > 0 ): 207 | if ( len( data_list ) > 62 ): 208 | data_payload = data_list[0:62]; 209 | data_list = data_list[62:]; 210 | else: 211 | data_payload = data_list[0:]; 212 | data_list = []; 213 | payload = ( "%08x" % each_addr ); 214 | for each_data in data_payload: 215 | payload += ( "%08x" % each_data ); 216 | each_addr +=4; 217 | # print(payload); 218 | self.mesa_bus.wr( 0x00, 0x0, 0x0, payload ); 219 | return; 220 | 221 | def rd( self, addr, num_dwords ): 222 | dwords_remaining = num_dwords; 223 | each_addr = addr; 224 | rts = []; 225 | rts_dword = "00000000"; 226 | while ( dwords_remaining > 0 ): 227 | if ( dwords_remaining > 62 ): 228 | n_dwords = 62; 229 | dwords_remaining -= 62; 230 | else: 231 | n_dwords = dwords_remaining; 232 | dwords_remaining = 0; 233 | 234 | # LocalBus RD cycle is a Addr+Len 8byte payload to 0x00,0x0,0x1 235 | payload = ( "%08x" % each_addr ) + ( "%08x" % n_dwords ); 236 | self.mesa_bus.wr( 0x00, 0x0, 0x1, payload ); 237 | rts_mesa = self.mesa_bus.rd(); 238 | # The Mesa Readback Ro packet resembles a Wi Write packet from slot 0xFE 239 | # This is to support a synchronous bus that clocks 0xFFs for idle 240 | # This only handles single DWORD reads and checks for: 241 | # "F0FE0004"+"12345678" + "\n" 242 | # "04" is num payload bytes and "12345678" is the read payload 243 | if ( len( rts_mesa ) > 8 ): 244 | rts_str = rts_mesa[8:];# Strip the FOFE0004 header 245 | while ( len( rts_str ) >= 8 ): 246 | rts_dword = rts_str[0:8]; 247 | rts_str = rts_str[8:]; 248 | try: 249 | rts += [ int( rts_dword, 16 ) ]; 250 | except: 251 | # print("ERROR:Invalid LocalBus Read "+rts_mesa+" "+rts_dword); 252 | if ( self.dbg_flag == "debug" ): 253 | sys.exit(); 254 | # rts += [ 0xdeadbeef ]; 255 | rts += [ 0x00000000 ]; 256 | else: 257 | # print("ERROR: Invalid LocalBus Read " + rts_mesa + " " + rts_dword); 258 | if ( self.dbg_flag == "debug" ): 259 | sys.exit(); 260 | # rts += [ 0xdeadbeef ]; 261 | rts += [ 0x00000000 ]; 262 | each_addr += ( 4 * n_dwords ); 263 | return rts; 264 | 265 | 266 | ############################################################################### 267 | # Routines for Reading and Writing Payloads over MesaBus 268 | # A payload is a series of bytes in hexadecimal string format. A typical use 269 | # for MesaBus is to transport a higher level Local Bus protocol for 32bit 270 | # writes and reads. MesaBus is lower level and transports payloads to a 271 | # specific device on a serial chained bus based on the Slot Number. 272 | # More info at : https://blackmesalabs.wordpress.com/2016/03/04/mesa-bus/ 273 | class mesa_bus: 274 | def __init__ ( self, port ): 275 | self.port = port; 276 | 277 | def wr( self, slot, subslot, cmd, payload ): 278 | preamble = "FFF0"; 279 | slot = "%02x" % slot; 280 | subslot = "%01x" % subslot; 281 | cmd = "%01x" % cmd; 282 | num_bytes = "%02x" % ( len( payload ) / 2 ); 283 | mesa_str = preamble + slot + subslot + cmd + num_bytes + payload; 284 | # print( mesa_str ); 285 | if ( type( self.port ) == spidev.SpiDev ): 286 | mesa_hex_list = []; 287 | for i in range( 0, len(mesa_str)/2 ): 288 | mesa_hex = int(mesa_str[i*2:i*2+2],16); 289 | mesa_hex_list += [mesa_hex]; 290 | # print("%02x" % mesa_hex ); 291 | rts = self.port.xfer2( mesa_hex_list ); 292 | # print( rts); 293 | else: 294 | self.port.wr( mesa_str ); 295 | return; 296 | 297 | def rd( self ): 298 | if ( type( self.port ) == spidev.SpiDev ): 299 | hex_str = ""; 300 | rts = self.port.xfer2(8*[0xFF]); 301 | for each in rts: 302 | hex_str += ("%02x" % each ); 303 | rts = hex_str; 304 | # print rts; 305 | else: 306 | rts = self.port.rd(); 307 | # print( rts ); 308 | return rts; 309 | 310 | ############################################################################### 311 | app = App(); 312 | app.main(); 313 | -------------------------------------------------------------------------------- /python/mesa_bus_ex.ini: -------------------------------------------------------------------------------- 1 | bd_connection = tcp 2 | #bd_connection = usb 3 | bd_protocol = mesa 4 | tcp_ip_addr = 127.0.0.1 5 | tcp_port = 21567 6 | usb_baudrate = 921600 7 | usb_port = COM4 8 | mesa_slot = 00 9 | mesa_subslot = 0 10 | -------------------------------------------------------------------------------- /python/mesa_bus_ex.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | ################################################################################################### 3 | # Source file : mesa_bus_ex.py 4 | # Language : Python 3.7 - may work with earlier and later 3.x versions. 5 | # Author : Kevin Hubbard 6 | # Description : Example Python to talke to bd_server and Mesa Bus. 7 | # License : GPLv3 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | # Notes : PySerial for Python3 from https://pypi.python.org/pypi/pyserial/ 21 | # ------------------------------------------------------------------------------------------------- 22 | # History : 23 | # 11.29.2024 : khubbard : Created. Forked from bd_shell.py 24 | ################################################################################################### 25 | from common_functions import file2list; 26 | from common_functions import list2file; 27 | 28 | import sys; 29 | import select; 30 | import socket; 31 | import time; 32 | import os; 33 | import random; 34 | from time import sleep; 35 | from os import path; 36 | 37 | 38 | import class_lb_link; # Access to LocalBus over MesaBus over serial 39 | import class_lb_tcp_link; # Access to LocalBus over TCP link to bd_server.py 40 | import class_mesa_bus; # Access to MesaBus over serial 41 | import class_uart_usb_link; # Access to serial over USB COM type connection 42 | #import class_cmd_proc; 43 | #import class_spi_prom; # Access to spi_prom.v over LocalBus 44 | #import class_user; # Example of user defined add on functions 45 | #import class_ft600_usb_link;# Access to serial over USB3 FT600 type connection 46 | #import class_sump2; # Access to sump2.v logic analyzer engine in HW 47 | 48 | def main(): 49 | args = sys.argv + [None]*3;# args[0] is mesa_bus_ex.py 50 | var_dict = {}; 51 | 52 | # If INI file exists, load it, otherwise create a default one and use it 53 | file_name = path.join( os.getcwd(), "mesa_bus_ex.ini"); 54 | if ( ( path.exists( file_name ) ) == False ): 55 | ini_list = ["bd_connection = usb # usb,usb3,pi_spi,tcp", 56 | "bd_protocol = mesa # mesa,poke", 57 | "tcp_port = 21567 # 21567 ", 58 | "tcp_ip_addr = 127.0.0.1 # 127.0.0.1", 59 | "usb_port = COM4 # ie COM4", 60 | "usb_baudrate = 921600 # ie 921600", 61 | "mesa_slot = 00 # ie 00", 62 | "mesa_subslot = 0 # ie 0", ]; 63 | ini_file = open ( file_name, 'w' ); 64 | for each in ini_list: 65 | ini_file.write( each + "\n" ); 66 | ini_file.close(); 67 | 68 | if ( ( path.exists( file_name ) ) == True ): 69 | ini_file = open ( file_name, 'r' ); 70 | ini_list = ini_file.readlines(); 71 | for each in ini_list: 72 | words = " ".join(each.split()).split(' ') + [None] * 4; 73 | if ( words[1] == "=" ): 74 | var_dict[ words[0] ] = words[2]; 75 | 76 | # Assign var_dict values to legacy variables. Error checking would be nice. 77 | bd_connection = var_dict["bd_connection"]; 78 | com_port = var_dict["usb_port"]; 79 | baudrate = int(var_dict["usb_baudrate"],10); 80 | mesa_slot = int(var_dict["mesa_slot"],16); 81 | mesa_subslot = int(var_dict["mesa_subslot"],16); 82 | tcp_ip_addr = var_dict["tcp_ip_addr"]; 83 | tcp_port = int(var_dict["tcp_port"],10); 84 | 85 | # Establish connection to Backdoor Hardware 86 | try: 87 | if ( bd_connection == "tcp" ): 88 | bd = class_lb_tcp_link.lb_tcp_link( ip = tcp_ip_addr, port = tcp_port ); 89 | if ( bd.sock == None ): 90 | bd = None; 91 | elif ( bd_connection == "usb" ): 92 | usb = class_uart_usb_link.uart_usb_link( port_name=com_port, 93 | baudrate=baudrate ); 94 | mb = class_mesa_bus.mesa_bus( phy_link=usb ); 95 | bd = class_lb_link.lb_link( mesa_bus=mb, slot=mesa_slot, 96 | subslot=mesa_subslot ); 97 | except: 98 | print("ERROR: Backdoor connection failed. Check hardware and ini file"); 99 | sys.exit(); 100 | 101 | dword = bd.rd( 0x00000000 )[0]; # Mesa Bus Read Example 102 | print("%08x" % dword ); 103 | bd.wr( 0x00000004, [ 0x00000055 ] ); # Mesa Bus Write Example 104 | dword = bd.rd( 0x00000004 )[0]; # Mesa Bus Read Example 105 | print("%08x" % dword ); 106 | 107 | return; 108 | 109 | 110 | ############################################################################### 111 | try: 112 | if __name__=='__main__': main() 113 | except KeyboardInterrupt: 114 | print('Break!') 115 | # EOF 116 | -------------------------------------------------------------------------------- /verilog/README.txt: -------------------------------------------------------------------------------- 1 | Example Verilog test for Digilent BASYS3 board. 2 | Provides some simple local bus registers that drive LEDs 3 | and read switches that may be accessed using Mesa Bus. 4 | -------------------------------------------------------------------------------- /verilog/ft232_xface.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- Source file: ft232_xface.v 3 | -- Date: June 8, 2016 4 | -- Author: khubbard 5 | -- Description: Top Level Verilog RTL for Mesa Bus Backdoor interface to UART 6 | -- Language: Verilog-2001 and VHDL-1993 7 | -- Simulation: Mentor-Modelsim 8 | -- Synthesis: Xilinxt XST or Lattice 9 | -- 10 | -- Revision History: 11 | -- Ver# When Who What 12 | -- ---- -------- -------- --------------------------------------------------- 13 | -- 0.1 06.08.16 khubbard Creation 14 | -- ***************************************************************************/ 15 | `default_nettype none // Strictly enforce all nets to be declared 16 | 17 | module ft232_xface 18 | ( 19 | input wire reset, 20 | input wire clk_lb, 21 | input wire ftdi_wi, 22 | output wire ftdi_ro, 23 | 24 | output wire lb_wr, 25 | output wire lb_rd, 26 | output wire [31:0] lb_addr, 27 | output wire [31:0] lb_wr_d, 28 | input wire [31:0] lb_rd_d, 29 | input wire lb_rd_rdy 30 | 31 | //inout wire ftdi_wo, 32 | //inout wire ftdi_ri, 33 | 34 | //output wire prom_wr, 35 | //output wire prom_rd, 36 | //output wire [31:0] prom_addr, 37 | //output wire [31:0] prom_wr_d, 38 | //input wire [31:0] prom_rd_d, 39 | //input wire prom_rd_rdy 40 | );// module ft232_xface 41 | 42 | reg cks_off_req; 43 | 44 | reg reset_core; 45 | wire reset_loc; 46 | 47 | reg bd_ro_muxd; 48 | wire mesa_wo_loc; 49 | wire mesa_ri_loc; 50 | reg mesa_wo_muxd; 51 | 52 | wire mesa_wi_flush; 53 | wire mesa_wi_loc; 54 | wire mesa_wi_nib_en; 55 | wire [3:0] mesa_wi_nib_d; 56 | wire mesa_wo_byte_en; 57 | wire [7:0] mesa_wo_byte_d; 58 | wire mesa_wo_busy; 59 | wire mesa_ro_byte_en; 60 | wire [7:0] mesa_ro_byte_d; 61 | wire mesa_ro_busy; 62 | wire mesa_ro_done; 63 | wire mesa_ro_loc; 64 | 65 | wire [7:0] rx_loc_d; 66 | wire rx_loc_rdy; 67 | wire rx_loc_start; 68 | wire rx_loc_stop; 69 | 70 | wire [7:0] core_ro_byte_d; 71 | wire core_ro_byte_en; 72 | wire core_ro_done; 73 | wire core_ro_busy; 74 | wire [8:0] subslot_ctrl; 75 | reg [3:0] tx_busy_sr; 76 | 77 | reg prom_boot_en; 78 | reg [1:0] prom_boot_sel; 79 | reg [1:0] pin_ctrl_ro; 80 | reg [1:0] pin_ctrl_wo; 81 | reg pin_ctrl_ri; 82 | reg clr_baudlock; 83 | wire int_l_loc; 84 | wire user_wo; 85 | wire user_ro; 86 | reg reboot_req; 87 | reg report_id; 88 | 89 | wire ftdi_ri_oe_l; 90 | wire ftdi_ri_in; 91 | wire ftdi_ri_out; 92 | wire ftdi_wo_out; 93 | reg ftdi_wo_oe_l; 94 | 95 | 96 | assign reset_loc = reset; 97 | assign int_l_loc = 1; 98 | assign user_ro = 1;// User function for ro 99 | 100 | //iob_bidi u2_out ( .IO( ftdi_wo ), .T( ftdi_wo_oe_l ), 101 | // .I ( ftdi_wo_out ), .O( )); 102 | // 103 | //iob_bidi u1_out ( .IO( ftdi_ri ), .T( 1'b1 ), 104 | // .I ( ftdi_ri_out ), .O( ftdi_ri_in )); 105 | 106 | 107 | assign ftdi_ri_oe_l = ~ pin_ctrl_ri;// Ri becomes an output if User_Ri sel 108 | assign ftdi_ri_out = 1'b1; 109 | assign ftdi_ro = ( ~ bd_ro_muxd ); 110 | assign ftdi_wo_out = ~mesa_wo_muxd; 111 | //assign mesa_ri_loc = ( pin_ctrl_ri == 0 ) ? ftdi_ri_in : 1; 112 | assign mesa_ri_loc = 1'b1; 113 | assign mesa_wi_loc = ftdi_wi; 114 | 115 | 116 | //----------------------------------------------------------------------------- 117 | // Subslot Control bits control muxes for pin functions 118 | // 0x0 = Ro pin is MesaBus Ro Readback ( Default ) 119 | // 0x1 = Ro pin is MesaBus Wi loopback 120 | // 0x2 = Ro pin is MesaBus Interrupt 121 | // 0x3 = Ro pin is user defined output function 122 | // 0x4 = Wo pin is MesaBus Wo Write-Out ( Default ) 123 | // 0x5 = Wo pin is MesaBus Wi loopback 124 | // 0x6 = Wo pin is MesaBus Interrupt 125 | // 0x7 = Wo pin is user defined function 126 | // 0x8 = Ri pin is MesaBus Ri Read-In ( Default ) 127 | // 0x9 = Ri pin is user defined input function. Ri is disabled. 128 | // 129 | // Ro pin is active Low and is used for both serial readback and interrupts 130 | // Use combinatorial AND between internal Ro and incoming Ri 131 | // Note: Inversions to try and keep logic '1' after reset instead of 0 132 | // 133 | // Wo pin may be used for Wo, Interrupt, Wi Loopback or User Function 134 | //----------------------------------------------------------------------------- 135 | always @ ( posedge clk_lb ) begin : proc_wo_mux 136 | case( pin_ctrl_ro[1:0] ) 137 | default : bd_ro_muxd <= ~mesa_ro_loc; 138 | 2'd1 : bd_ro_muxd <= ~mesa_wi_loc;// Wi Loopback to Ro 139 | 2'd2 : bd_ro_muxd <= ~int_l_loc; 140 | 2'd3 : bd_ro_muxd <= ~user_ro; 141 | endcase 142 | case( pin_ctrl_wo[1:0] ) 143 | default : mesa_wo_muxd <= ~mesa_wo_loc; 144 | 2'd1 : mesa_wo_muxd <= ~ftdi_wi; 145 | 2'd2 : mesa_wo_muxd <= ~int_l_loc; 146 | 2'd3 : mesa_wo_muxd <= ~user_wo; 147 | endcase 148 | //mesa_wo_muxd <= ~user_wo; 149 | 150 | end // proc_wo_mux 151 | 152 | 153 | //----------------------------------------------------------------------------- 154 | // Wo is tristated until bus goes active. 155 | //----------------------------------------------------------------------------- 156 | always @ ( posedge clk_lb ) begin : proc_wo_oe 157 | if ( reset_loc == 1 ) begin 158 | ftdi_wo_oe_l <= 1;// Tristate Wo until bus goes active 159 | end else if ( ftdi_wi == 0 ) begin 160 | ftdi_wo_oe_l <= 0; 161 | end 162 | end // proc_wo_oe 163 | 164 | 165 | //----------------------------------------------------------------------------- 166 | // Subslot Control : Decode subslot control nibbles for pin functions,etc 167 | //----------------------------------------------------------------------------- 168 | always @ ( posedge clk_lb ) begin : proc_subslot_ctrl 169 | clr_baudlock <= 0; 170 | report_id <= 0; 171 | reset_core <= 0; 172 | prom_boot_sel[1] <= 0; 173 | prom_boot_sel[0] <= 0;// 1st or 2nd slot 174 | prom_boot_en <= 0; 175 | cks_off_req <= 0; 176 | if ( subslot_ctrl[8] == 1 && subslot_ctrl[7:4] == 4'hF ) begin 177 | if ( subslot_ctrl[3:2] == 2'b00 ) begin 178 | pin_ctrl_ro <= subslot_ctrl[1:0];// 0-3 179 | end 180 | if ( subslot_ctrl[3:2] == 2'b01 ) begin 181 | pin_ctrl_wo <= subslot_ctrl[1:0];// 4-7 182 | end 183 | if ( subslot_ctrl[3:0] == 4'h8 ) begin 184 | pin_ctrl_ri <= 0; 185 | end 186 | if ( subslot_ctrl[3:0] == 4'h9 ) begin 187 | pin_ctrl_ri <= 1; 188 | end 189 | if ( subslot_ctrl[3:0] == 4'hA ) begin 190 | report_id <= 1; 191 | end 192 | if ( subslot_ctrl[3:0] == 4'hB ) begin 193 | reset_core <= 1; 194 | end 195 | if ( subslot_ctrl[3:0] == 4'hC ) begin 196 | clr_baudlock <= 1; 197 | end 198 | if ( subslot_ctrl[3:0] == 4'hD ) begin 199 | cks_off_req <= 1; 200 | end 201 | if ( subslot_ctrl[3:0] == 4'hE ) begin 202 | prom_boot_sel[0] <= 0;// 1st slot 203 | prom_boot_en <= 1; 204 | end 205 | if ( subslot_ctrl[3:0] == 4'hF ) begin 206 | prom_boot_sel[0] <= 1;// 2nd slot 207 | prom_boot_en <= 1; 208 | end 209 | end 210 | 211 | if ( reset_loc == 1 ) begin 212 | reset_core <= 1; 213 | pin_ctrl_ro <= 2'd0; 214 | pin_ctrl_wo <= 2'd0; 215 | pin_ctrl_ri <= 0; 216 | end 217 | end // proc_subslot_ctrl 218 | 219 | 220 | //----------------------------------------------------------------------------- 221 | // MesaBus Phy : Convert UART serial to/from binary for Mesa Bus Interface 222 | //----------------------------------------------------------------------------- 223 | mesa_uart_phy u_mesa_uart_phy 224 | ( 225 | .reset ( reset_loc ), 226 | .clk ( clk_lb ), 227 | .clr_baudlock ( clr_baudlock ), 228 | .uart_baud ( ), 229 | .dbg_rx ( ), 230 | .dbg_out ( ), 231 | .user_wo ( user_wo ), 232 | .mesa_wi ( mesa_wi_loc ), 233 | .mesa_ro ( mesa_ro_loc ), 234 | .mesa_wo ( mesa_wo_loc ), 235 | .mesa_ri ( mesa_ri_loc ), 236 | .mesa_wi_flush ( mesa_wi_flush ), 237 | .mesa_wi_nib_en ( mesa_wi_nib_en ), 238 | .mesa_wi_nib_d ( mesa_wi_nib_d[3:0] ), 239 | 240 | .mesa_wo_byte_en ( mesa_wo_byte_en ), 241 | .mesa_wo_byte_d ( mesa_wo_byte_d[7:0] ), 242 | 243 | .mesa_wo_busy ( mesa_wo_busy ), 244 | .mesa_ro_byte_en ( mesa_ro_byte_en ), 245 | .mesa_ro_byte_d ( mesa_ro_byte_d[7:0] ), 246 | .mesa_ro_busy ( mesa_ro_busy ), 247 | .mesa_ro_done ( mesa_ro_done ) 248 | );// module mesa_uart_phy 249 | 250 | 251 | //----------------------------------------------------------------------------- 252 | // Decode Slot Addresses : Take in the Wi path as nibbles and generate the Wo 253 | // paths for both internal and external devices. 254 | //----------------------------------------------------------------------------- 255 | mesa_decode u_mesa_decode 256 | ( 257 | .clk ( clk_lb ), 258 | .reset ( reset ), 259 | .rx_in_flush ( mesa_wi_flush ), 260 | .rx_in_rdy ( mesa_wi_nib_en ), 261 | .rx_in_d ( mesa_wi_nib_d[3:0] ), 262 | .rx_out_d ( mesa_wo_byte_d[7:0] ), 263 | .rx_out_rdy ( mesa_wo_byte_en ), 264 | .rx_loc_d ( rx_loc_d[7:0] ), 265 | .rx_loc_rdy ( rx_loc_rdy ), 266 | .rx_loc_start ( rx_loc_start ), 267 | .rx_loc_stop ( rx_loc_stop ) 268 | ); 269 | 270 | 271 | //----------------------------------------------------------------------------- 272 | // Convert Subslots 0x0 and 0xE to 32bit local bus for user logic and prom 273 | //----------------------------------------------------------------------------- 274 | mesa2lb u_mesa2lb 275 | ( 276 | .clk ( clk_lb ), 277 | .reset ( reset ), 278 | .mode_usb3 ( 1'b0 ), 279 | .rx_byte_d ( rx_loc_d[7:0] ), 280 | .rx_byte_rdy ( rx_loc_rdy ), 281 | .rx_byte_start ( rx_loc_start ), 282 | .rx_byte_stop ( rx_loc_stop ), 283 | 284 | .tx_byte_d ( core_ro_byte_d[7:0] ), 285 | .tx_byte_rdy ( core_ro_byte_en ), 286 | .tx_done ( core_ro_done ), 287 | .tx_busy ( core_ro_busy ), 288 | 289 | .lb_wr ( lb_wr ), 290 | .lb_rd ( lb_rd ), 291 | .lb_wr_d ( lb_wr_d[31:0] ), 292 | .lb_addr ( lb_addr[31:0] ), 293 | .lb_rd_d ( lb_rd_d[31:0] ), 294 | .lb_rd_rdy ( lb_rd_rdy ), 295 | 296 | .prom_wr ( ), 297 | .prom_rd ( ), 298 | .prom_wr_d ( ), 299 | .prom_addr ( ), 300 | .prom_rd_d ( 32'd0 ), 301 | .prom_rd_rdy ( 1'b0 ) 302 | 303 | //.prom_wr ( prom_wr ), 304 | //.prom_rd ( prom_rd ), 305 | //.prom_wr_d ( prom_wr_d[31:0] ), 306 | //.prom_addr ( prom_addr[31:0] ), 307 | //.prom_rd_d ( prom_rd_d[31:0] ), 308 | //.prom_rd_rdy ( prom_rd_rdy ) 309 | ); 310 | 311 | 312 | //----------------------------------------------------------------------------- 313 | // FSM for reporting ID : This also muxes in Ro Byte path from Core 314 | //----------------------------------------------------------------------------- 315 | mesa_id u_mesa_id 316 | ( 317 | .reset ( reset_loc ), 318 | .clk ( clk_lb ), 319 | .report_id ( report_id ), 320 | .id_mfr ( 32'h00000001 ), 321 | .id_dev ( 32'h00000001 ), 322 | .id_snum ( 32'h00000001 ), 323 | .mesa_core_ro_byte_en ( core_ro_byte_en ), 324 | .mesa_core_ro_byte_d ( core_ro_byte_d[7:0] ), 325 | .mesa_core_ro_done ( core_ro_done ), 326 | .mesa_ro_byte_en ( mesa_ro_byte_en ), 327 | .mesa_ro_byte_d ( mesa_ro_byte_d[7:0] ), 328 | .mesa_ro_done ( mesa_ro_done ), 329 | .mesa_ro_busy ( mesa_ro_busy ) 330 | );// module mesa_id 331 | 332 | 333 | // ---------------------------------------------------------------------------- 334 | // Support pipeling Ro byte path by asserting busy for 4 clocks after a byte 335 | // ---------------------------------------------------------------------------- 336 | always @ ( posedge clk_lb ) begin : proc_tx 337 | tx_busy_sr[0] <= core_ro_byte_en | mesa_ro_busy; 338 | tx_busy_sr[3:1] <= tx_busy_sr[2:0]; 339 | end // proc_tx 340 | assign core_ro_busy = ( tx_busy_sr != 4'b0000 ) ? 1 : 0; 341 | 342 | 343 | //----------------------------------------------------------------------------- 344 | // Decode Subslot Nibble Controls : Used for Pin Reassigns,ReportID,ResetCore 345 | //----------------------------------------------------------------------------- 346 | mesa2ctrl u_mesa2ctrl 347 | ( 348 | .clk ( clk_lb ), 349 | .reset ( reset ), 350 | .rx_byte_d ( rx_loc_d[7:0] ), 351 | .rx_byte_rdy ( rx_loc_rdy ), 352 | .rx_byte_start ( rx_loc_start ), 353 | .rx_byte_stop ( rx_loc_stop ), 354 | .subslot_ctrl ( subslot_ctrl[8:0] ) 355 | ); 356 | 357 | 358 | endmodule // ft232_xface.v 359 | `default_nettype wire // enable Verilog default for any 3rd party IP needing it 360 | -------------------------------------------------------------------------------- /verilog/hlist.txt: -------------------------------------------------------------------------------- 1 | # ChipVault hierarchy file. See http://chipvault.sourceforge.net/ 2 | hlist.txt 3 | top.v 4 | ft232_xface.v 5 | mesa_uart_phy.v 6 | mesa_uart.v 7 | mesa_tx_uart.v 8 | mesa_byte2ascii.v 9 | mesa_ascii2nibble.v 10 | mesa_decode.v 11 | mesa2lb.v 12 | mesa_id.v 13 | time_stamp.v 14 | mesa2ctrl.v 15 | -------------------------------------------------------------------------------- /verilog/iob_bidi.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- Source file: iob_bidi.v 3 | -- Date: February 2016 4 | -- Author: khubbard 5 | -- Description: Infer a simple single ended bidirectional IO buffer. 6 | -- Language: Verilog-2001 7 | -- Simulation: Mentor-Modelsim 8 | -- Synthesis: Lattice 9 | -- 10 | -- Revision History: 11 | -- Ver# When Who What 12 | -- ---- -------- -------- --------------------------------------------------- 13 | -- 0.1 02.01.16 khubbard Creation 14 | -- ***************************************************************************/ 15 | `default_nettype none // Strictly enforce all nets to be declared 16 | 17 | module iob_bidi 18 | ( 19 | input wire I, 20 | input wire T, 21 | output wire O, 22 | inout wire IO 23 | );// module iob_bidi 24 | 25 | assign IO = ( T == 1 ) ? 1'bz : I; 26 | assign O = IO; 27 | 28 | endmodule // iob_bidi.v 29 | -------------------------------------------------------------------------------- /verilog/mesa2ctrl.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- (C) Copyright 2015 Kevin M. Hubbard @ Black Mesa Labs 3 | -- Source file: mesa2ctrl.v 4 | -- Date: October 4, 2015 5 | -- Author: khubbard 6 | -- Language: Verilog-2001 7 | -- Description: The Mesa Bus to Control Bus translator. Decodes all subslot 8 | -- command nibbles for this slot. Write Only Operations. 9 | -- 10 | -- "\n"..."FFFF"."(F0-12-34-04)[11223344]\n" : 11 | -- 0xFF = Bus Idle ( NULLs ) 12 | -- B0 0xF0 = New Bus Cycle to begin ( Nibble and bit orientation ) 13 | -- B1 0x12 = Slot Number, 0xFF = Broadcast all slots, 0xFE = NULL Dest 14 | -- B2 0x3 = Sub-Slot within the chip (0-0xF) 15 | -- 0x4 = Command Nibble for Sub-Slot 16 | -- B3 0x04 = Number of Payload Bytes (0-255) 17 | -- 0x11223344 = Payload 18 | -- 19 | -- Slot 0xFF = Broadcast all slots 20 | -- Sub-Slot 0x0 = User Local Bus Access 21 | -- Sub-Slot 0xE = PROM Local Bus Access 22 | -- 0x0 = Bus Write 23 | -- 0x1 = Bus Read 24 | -- 0x2 = Bus Write Repeat ( burst to single address ) 25 | -- 0x3 = Bus Read Repeat ( burst read from single address ) 26 | -- Sub-Slot 0xF = Power and Pin Control ( Write Only ) 27 | -- 28 | -- Revision History: 29 | -- Ver# When Who What 30 | -- ---- -------- -------- --------------------------------------------------- 31 | -- 0.1 10.04.15 khubbard Creation 32 | -- ***************************************************************************/ 33 | `default_nettype none // Strictly enforce all nets to be declared 34 | 35 | module mesa2ctrl 36 | ( 37 | input wire clk, 38 | input wire reset, 39 | input wire rx_byte_start, 40 | input wire rx_byte_stop, 41 | input wire rx_byte_rdy, 42 | input wire [7:0] rx_byte_d, 43 | output reg [8:0] subslot_ctrl 44 | ); // module mesa2ctrl 45 | 46 | reg [3:0] byte_cnt; 47 | reg [31:0] dword_sr; 48 | reg rx_byte_rdy_p1; 49 | reg rx_byte_rdy_p2; 50 | reg rx_byte_rdy_p3; 51 | reg rx_byte_stop_p1; 52 | reg rx_byte_stop_p2; 53 | reg rx_byte_stop_p3; 54 | 55 | 56 | //----------------------------------------------------------------------------- 57 | // Shift a nibble into a byte shift register. 58 | // |---- Header ----|--- Payload ---| 59 | // 0 1 2 3 60 | // Write : <00><00><08>[] 61 | // Read : <00><00><08>[] 62 | //----------------------------------------------------------------------------- 63 | always @ ( posedge clk ) begin : proc_lb1 64 | rx_byte_rdy_p1 <= rx_byte_rdy; 65 | rx_byte_rdy_p2 <= rx_byte_rdy_p1; 66 | rx_byte_rdy_p3 <= rx_byte_rdy_p2; 67 | rx_byte_stop_p1 <= rx_byte_stop; 68 | rx_byte_stop_p2 <= rx_byte_stop_p1; 69 | rx_byte_stop_p3 <= rx_byte_stop_p2; 70 | 71 | if ( rx_byte_start == 1 ) begin 72 | byte_cnt <= 4'd0; 73 | end else if ( rx_byte_rdy == 1 ) begin 74 | if ( byte_cnt != 4'd4 ) begin 75 | byte_cnt <= byte_cnt + 1; 76 | end 77 | end 78 | 79 | // Shift bytes into a 32bit SR 80 | if ( rx_byte_rdy == 1 ) begin 81 | dword_sr[31:0] <= { dword_sr[23:0], rx_byte_d[7:0] }; 82 | end 83 | 84 | subslot_ctrl[8] <= 0;// Strobe 85 | // Accept single DWORD packets for Slot-00 (this) or Slot-FF (all) 86 | if ( rx_byte_rdy_p2 == 1 && byte_cnt[3:0] == 4'd3 ) begin 87 | if ( dword_sr[31:16] == 16'hF000 || 88 | dword_sr[31:16] == 16'hF0FF ) begin 89 | // Payload must be 0x00 length 90 | if ( dword_sr[7:0] == 8'h00 ) begin 91 | subslot_ctrl <= { 1'b1, dword_sr[15:8] };// D(8) is Strobe 92 | end 93 | end 94 | end 95 | 96 | if ( reset == 1 ) begin 97 | byte_cnt <= 4'd0; 98 | end 99 | 100 | end // proc_lb1 101 | 102 | 103 | endmodule // mesa2ctrl 104 | -------------------------------------------------------------------------------- /verilog/mesa2spi.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- (C) Copyright 2015 Kevin M. Hubbard @ Black Mesa Labs 3 | -- Source file: mesa2spi.v 4 | -- Date: October 4, 2015 5 | -- Author: khubbard 6 | -- Language: Verilog-2001 7 | -- Description: A Mesa Bus to SPI translator. Uses a Subslot for SPI RDs,WRs. 8 | -- 9 | -- "\n"..."FFFF"."(F0-12-34-04)[11223344]\n" : 10 | -- 0xFF = Bus Idle ( NULLs ) 11 | -- B0 0xF0 = New Bus Cycle to begin ( Nibble and bit orientation ) 12 | -- B1 0x12 = Slot Number, 0xFF = Broadcast all slots, 0xFE = NULL Dest 13 | -- B2 0x3 = Sub-Slot within the chip (0-0xF) 14 | -- 0x4 = Command Nibble for Sub-Slot 15 | -- B3 0x04 = Number of Payload Bytes (0-255) : Length of SPI Cycle 16 | -- 0x11223344 = Payload 17 | -- 18 | -- Sub-Slot Commands 19 | -- 0x0 = SPI Write Burst from Mesa to SPI with SPI faster than Mesa 20 | -- 0x1 = SPI Cycle : Byte and Continue ( for SPI slower than Mesa ) 21 | -- 0x2 = SPI Cycle : Last Byte ( deasserts SS after xfer ) 22 | -- 23 | -- Fast Mode: single LF at end of SPI Cycle 24 | -- Burst : 0x0 25 | -- 26 | -- Slow Mode: LF at end of each byte 27 | -- Single Byte : 0x2 28 | -- Two Bytes : 0x1,0x2 29 | -- Three+ Bytes : 0x1,0x1,..0x2 30 | -- 31 | -- 32 | -- Example MesaBus Cycle with 2-Byte Payload: 33 | -- rx_byte_start _/ \___________________________________________ 34 | -- rx_byte_rdy _/ \____/ \____/ \____/ \____/ \____/ \___ 35 | -- rx_byte_d -----<00>----<00>----<02>----<11>----<22>--- 36 | -- rx_byte_stop _________________________________________/ \__ 37 | -- 38 | -- Revision History: 39 | -- Ver# When Who What 40 | -- ---- -------- -------- --------------------------------------------------- 41 | -- 0.1 10.04.15 khubbard Creation 42 | -- ***************************************************************************/ 43 | `default_nettype none // Strictly enforce all nets to be declared 44 | 45 | module mesa2spi 46 | ( 47 | input wire clk, 48 | input wire reset, 49 | input wire [3:0] subslot, 50 | input wire rx_byte_start, 51 | input wire rx_byte_stop, 52 | input wire rx_byte_rdy, 53 | input wire [7:0] rx_byte_d, 54 | output reg [7:0] tx_byte_d, 55 | output reg tx_byte_rdy, 56 | output reg tx_done, 57 | input wire tx_busy, 58 | 59 | input wire [3:0] spi_ck_div, 60 | output reg spi_sck, 61 | input wire spi_miso, 62 | output reg spi_mosi, 63 | output reg spi_ss_l 64 | 65 | ); // module mesa2spi 66 | 67 | 68 | reg [3:0] byte_cnt; 69 | reg [31:0] dword_sr; 70 | reg rx_byte_rdy_p1; 71 | reg rx_byte_rdy_p2; 72 | reg rx_byte_rdy_p3; 73 | reg rx_byte_stop_p1; 74 | reg rx_byte_stop_p2; 75 | reg rx_byte_stop_p3; 76 | reg spi_ck_loc; 77 | reg spi_cycle_jk; 78 | reg [4:0] spi_halfbit_cnt; 79 | reg [3:0] spi_ck_cnt; 80 | reg [7:0] spi_mosi_sr; 81 | reg [7:0] spi_miso_sr; 82 | reg spi_miso_loc; 83 | reg dword_rdy; 84 | reg header_jk; 85 | reg spi_mosi_loc; 86 | reg spi_ss_loc; 87 | reg sample_miso; 88 | reg sample_miso_p1; 89 | reg sample_miso_p2; 90 | reg [1:0] mesa_cmd; 91 | 92 | 93 | //----------------------------------------------------------------------------- 94 | // Convert a MesaBus payload into SPI bus cycles 95 | //----------------------------------------------------------------------------- 96 | always @ ( posedge clk ) begin : proc_lb1 97 | rx_byte_rdy_p1 <= rx_byte_rdy; 98 | rx_byte_rdy_p2 <= rx_byte_rdy_p1; 99 | rx_byte_rdy_p3 <= rx_byte_rdy_p2; 100 | rx_byte_stop_p1 <= rx_byte_stop; 101 | rx_byte_stop_p2 <= rx_byte_stop_p1; 102 | rx_byte_stop_p3 <= rx_byte_stop_p2; 103 | dword_rdy <= 0; 104 | 105 | if ( rx_byte_start == 1 ) begin 106 | byte_cnt <= 4'd0; 107 | header_jk <= 1; 108 | end else if ( rx_byte_rdy == 1 ) begin 109 | if ( byte_cnt[3:0] != 4'd4 ) begin 110 | byte_cnt <= byte_cnt + 1; 111 | end 112 | end 113 | 114 | // Shift bytes into a 32bit SR 115 | if ( rx_byte_rdy == 1 ) begin 116 | dword_sr[31:0] <= { dword_sr[23:0], rx_byte_d[7:0] }; 117 | end 118 | 119 | // After we have 4 bytes, look for Slot=00,SubSlot=n,Command=m 120 | if ( rx_byte_rdy_p2 == 1 && byte_cnt[1:0] == 2'd3 ) begin 121 | header_jk <= 0; 122 | dword_rdy <= 1; 123 | // Note: This doesn't handle slot broadcast - only direct for LB Access 124 | if ( header_jk == 1 && dword_sr[31:16] == 16'hF000 ) begin 125 | if ( dword_sr[15:12] == subslot[3:0] ) begin 126 | spi_cycle_jk <= 1; 127 | mesa_cmd[1:0] <= dword_sr[9:8]; 128 | end 129 | end 130 | end // if ( rx_byte_rdy_p2 == 1 && byte_cnt[1:0] == 2'd3 ) begin 131 | 132 | if ( rx_byte_stop_p3 == 1 ) begin 133 | header_jk <= 0; 134 | if ( mesa_cmd == 2'd0 || mesa_cmd == 2'd2 ) begin 135 | spi_cycle_jk <= 0; 136 | end 137 | end 138 | if ( reset == 1 ) begin 139 | spi_cycle_jk <= 0; 140 | header_jk <= 0; 141 | end 142 | 143 | end // proc_lb1 144 | 145 | 146 | //----------------------------------------------------------------------------- 147 | // Convert incoming bytes into SPI bytes at specified clock divisor rate 148 | //----------------------------------------------------------------------------- 149 | always @ ( posedge clk ) begin : proc_lb2 150 | sample_miso <= 0; 151 | sample_miso_p1 <= sample_miso; 152 | sample_miso_p2 <= sample_miso_p1; 153 | tx_byte_rdy <= 0; 154 | tx_done <= 0; 155 | if ( rx_byte_rdy == 1 && spi_cycle_jk == 1 && byte_cnt[3:0] == 4'd3 ) begin 156 | spi_mosi_sr <= rx_byte_d[7:0]; 157 | spi_halfbit_cnt <= 5'd16; 158 | spi_ck_cnt <= 4'd0; 159 | spi_ck_loc <= 1; 160 | spi_ss_loc <= 1; 161 | spi_ck_cnt <= spi_ck_div[3:0]; 162 | end else if ( spi_halfbit_cnt != 5'd0 ) begin 163 | // actions happen when clock half period counter reaches 0 164 | if ( spi_ck_cnt == spi_ck_div[3:0] ) begin 165 | spi_halfbit_cnt <= spi_halfbit_cnt - 1; 166 | spi_ck_cnt <= 4'd0; 167 | spi_ck_loc <= ~spi_ck_loc; 168 | // Shift new data out on falling clock edge 169 | if ( spi_ck_loc == 1 ) begin 170 | spi_mosi_sr <= { spi_mosi_sr[6:0], 1'b1 }; 171 | spi_mosi_loc <= spi_mosi_sr[7]; 172 | end 173 | sample_miso <= ~ spi_ck_loc; 174 | end else begin 175 | spi_ck_cnt <= spi_ck_cnt[3:0] + 1; 176 | end 177 | end else begin 178 | spi_halfbit_cnt <= 5'd0; 179 | spi_ck_loc <= 1; 180 | spi_mosi_loc <= 1; 181 | if ( spi_cycle_jk == 0 ) begin 182 | spi_ss_loc <= 0; 183 | end 184 | end 185 | if ( sample_miso_p1 == 1 ) begin 186 | spi_miso_sr <= { spi_miso_sr[6:0], spi_miso_loc }; 187 | // spi_miso_sr <= { spi_miso_sr[6:0], spi_mosi_loc };// Just for sims 188 | end 189 | if ( sample_miso_p2 == 1 && spi_halfbit_cnt == 5'd0 ) begin 190 | tx_byte_d <= spi_miso_sr[7:0]; 191 | tx_byte_rdy <= 1; 192 | if ( spi_cycle_jk == 0 || 193 | mesa_cmd == 2'd1 ) begin 194 | tx_done <= 1;// Queue up a \n LF 195 | end 196 | end 197 | 198 | spi_ss_l <= ~ spi_ss_loc; 199 | spi_sck <= spi_ck_loc; 200 | spi_mosi <= spi_mosi_loc; 201 | spi_miso_loc <= spi_miso; 202 | 203 | end // proc_lb2 204 | 205 | 206 | endmodule // mesa2spi 207 | -------------------------------------------------------------------------------- /verilog/mesa_ascii2nibble.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- Source file: mesa_ascii2nibble.v 3 | -- Date: October 4, 2015 4 | -- Author: khubbard 5 | -- Description: Convert an ASCII character to a binary nibble. 6 | -- Language: Verilog-2001 and VHDL-1993 7 | -- Simulation: Mentor-Modelsim 8 | -- Synthesis: Lattice 9 | -- 10 | -- Revision History: 11 | -- Ver# When Who What 12 | -- ---- -------- -------- --------------------------------------------------- 13 | -- 0.1 10.04.15 khubbard Creation 14 | -- ***************************************************************************/ 15 | `default_nettype none // Strictly enforce all nets to be declared 16 | 17 | module mesa_ascii2nibble 18 | ( 19 | input wire clk, 20 | input wire rx_char_en, 21 | input wire [7:0] rx_char_d, 22 | output reg rx_nib_en, 23 | output reg [3:0] rx_nib_d 24 | );// module mesa_ascii2nibble 25 | 26 | reg [4:0] rx_nib_bin; // MSB is Valid Char Flag for "0"-"F" 27 | 28 | 29 | //----------------------------------------------------------------------------- 30 | // When UART receives an ASCII char, see if it is 0-9,a-f,A-F else toss 31 | //----------------------------------------------------------------------------- 32 | always @ ( posedge clk ) begin : proc_rx 33 | rx_nib_d <= rx_nib_bin[3:0]; 34 | rx_nib_en <= rx_char_en & rx_nib_bin[4]; 35 | end 36 | 37 | 38 | //----------------------------------------------------------------------------- 39 | // Convert ASCII to binary nibbles. Toss and ignore all other received chars 40 | // 0x30 = "0" 41 | // 0x39 = "9" 42 | // 0x41 = "A" 43 | // 0x46 = "F" 44 | // 0x61 = "a" 45 | // 0x66 = "f" 46 | //----------------------------------------------------------------------------- 47 | always @ ( * ) begin : proc_lut 48 | begin 49 | case( rx_char_d[7:0] ) 50 | 8'h30 : rx_nib_bin[4:0] <= 5'h10;// 0 51 | 8'h31 : rx_nib_bin[4:0] <= 5'h11; 52 | 8'h32 : rx_nib_bin[4:0] <= 5'h12; 53 | 8'h33 : rx_nib_bin[4:0] <= 5'h13; 54 | 8'h34 : rx_nib_bin[4:0] <= 5'h14; 55 | 8'h35 : rx_nib_bin[4:0] <= 5'h15; 56 | 8'h36 : rx_nib_bin[4:0] <= 5'h16; 57 | 8'h37 : rx_nib_bin[4:0] <= 5'h17; 58 | 8'h38 : rx_nib_bin[4:0] <= 5'h18; 59 | 8'h39 : rx_nib_bin[4:0] <= 5'h19;// 9 60 | 61 | 8'h41 : rx_nib_bin[4:0] <= 5'h1A;// A 62 | 8'h42 : rx_nib_bin[4:0] <= 5'h1B; 63 | 8'h43 : rx_nib_bin[4:0] <= 5'h1C; 64 | 8'h44 : rx_nib_bin[4:0] <= 5'h1D; 65 | 8'h45 : rx_nib_bin[4:0] <= 5'h1E; 66 | 8'h46 : rx_nib_bin[4:0] <= 5'h1F;// F 67 | 68 | 8'h61 : rx_nib_bin[4:0] <= 5'h1A;// a 69 | 8'h62 : rx_nib_bin[4:0] <= 5'h1B; 70 | 8'h63 : rx_nib_bin[4:0] <= 5'h1C; 71 | 8'h64 : rx_nib_bin[4:0] <= 5'h1D; 72 | 8'h65 : rx_nib_bin[4:0] <= 5'h1E; 73 | 8'h66 : rx_nib_bin[4:0] <= 5'h1F;// f 74 | 75 | default : rx_nib_bin[4:0] <= 5'h0F; 76 | endcase 77 | end 78 | end // proc_lut 79 | 80 | 81 | endmodule // mesa_ascii2nibble 82 | -------------------------------------------------------------------------------- /verilog/mesa_byte2ascii.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- Source file: mesa_byte2ascii.v 3 | -- Date: October 4, 2015 4 | -- Author: khubbard 5 | -- Description: Convert a binary byte to two ASCII nibs for UART transmission. 6 | -- Must handshake with both byte sender and UART for busy status. 7 | -- Also tracks a tx_done signal that queues up a "\n" to be sent. 8 | -- Language: Verilog-2001 9 | -- Simulation: Mentor-Modelsim 10 | -- Synthesis: Lattice 11 | -- 12 | -- Revision History: 13 | -- Ver# When Who What 14 | -- ---- -------- -------- --------------------------------------------------- 15 | -- 0.1 10.04.15 khubbard Creation 16 | -- 0.2 10.21.17 khubbard Added no_handshake for USB3 support 17 | -- ***************************************************************************/ 18 | `default_nettype none // Strictly enforce all nets to be declared 19 | 20 | module mesa_byte2ascii 21 | ( 22 | input wire clk, 23 | input wire reset, 24 | input wire no_handshake, 25 | input wire [7:0] tx_byte_d, 26 | input wire tx_byte_en, 27 | output wire tx_byte_busy, 28 | input wire tx_byte_done, 29 | output reg [7:0] tx_char_d, 30 | output wire tx_char_en, 31 | input wire tx_char_busy, 32 | input wire tx_char_idle 33 | );// module mesa_byte2ascii 34 | 35 | reg tx_done_jk; 36 | reg tx_done_char; 37 | reg tx_en; 38 | reg tx_en_p1; 39 | reg tx_busy_jk; 40 | reg [1:0] tx_fsm; 41 | reg [7:0] tx_byte_sr; 42 | wire tx_uart_busy; 43 | reg tx_uart_busy_p1; 44 | reg [7:0] tx_uart_busy_sr; 45 | wire [3:0] tx_nib_bin; 46 | 47 | `define ascii_lf 8'H0a 48 | 49 | assign tx_uart_busy = tx_char_busy; 50 | assign tx_char_en = tx_en; 51 | assign tx_byte_busy = tx_busy_jk | tx_byte_en; 52 | 53 | //----------------------------------------------------------------------------- 54 | // When a binary byte is sent to transmit, immediately assert tx_busy 55 | // then convert 1of2 nibbles to ASCII and send out until byte is done. 56 | // If tx_done asserts, wait for tx_busy to drop and then send a "\n". 57 | // 0x30 = "0" 58 | // 0x39 = "9" 59 | // 0x41 = "A" 60 | // 0x46 = "F" 61 | // 0x61 = "a" 62 | // 0x66 = "f" 63 | //----------------------------------------------------------------------------- 64 | always @ ( posedge clk ) begin : proc_tx 65 | tx_done_char <= 0; 66 | tx_en <= 0; 67 | tx_en_p1 <= tx_en; 68 | tx_uart_busy_p1 <= tx_uart_busy; 69 | tx_uart_busy_sr <= { tx_uart_busy_sr[6:0], tx_uart_busy }; 70 | 71 | // Remember that the transmission was complete to queue up a "\n" 72 | if ( tx_byte_done == 1 ) begin 73 | tx_done_jk <= 1; 74 | end 75 | 76 | // Deassert tx_busy_jk on falling edge of UART busy when no more nibbles 77 | if ( tx_fsm == 2'b00 && 78 | tx_char_idle == 1 ) begin 79 | tx_busy_jk <= 0; 80 | if ( tx_done_jk == 1 ) begin 81 | tx_done_char <= 1; 82 | tx_done_jk <= 0; 83 | end 84 | end 85 | 86 | // Shift out a nibble when ready 87 | if ( tx_fsm != 2'b00 && ( no_handshake == 1 || 88 | ( tx_uart_busy == 0 && tx_en == 0 && tx_en_p1 == 0 ) ) ) begin 89 | tx_en <= 1;// Send tx_char_d[7:0] to UART 90 | tx_fsm[1:0] <= { tx_fsm[0], 1'b0 }; 91 | tx_byte_sr <= { tx_byte_sr[3:0], 4'd0 };// Nibble Shift 92 | end 93 | 94 | // Queue up a binary byte to convert to ASCII as 2 nibbles for UART 95 | if ( tx_byte_en == 1 ) begin 96 | tx_busy_jk <= 1; 97 | tx_fsm <= 2'b11; 98 | tx_byte_sr <= tx_byte_d[7:0]; 99 | end 100 | 101 | // tx_char_d[7:0] is ASCII converted version of tx_nib_bin[3:0] 102 | if ( tx_nib_bin < 4'hA ) begin 103 | tx_char_d[7:0] <= 8'h30 + tx_nib_bin[3:0];// 0x30-0x00=0x30 (duh) 104 | end else begin 105 | tx_char_d[7:0] <= 8'h37 + tx_nib_bin[3:0];// 0x41-0x0A=0x37 106 | end 107 | 108 | // Was a "\n" queued up? Send it now 109 | if ( tx_done_char == 1 ) begin 110 | tx_char_d[7:0] <= `ascii_lf; // aka "\n" 111 | tx_en <= 1; 112 | end 113 | 114 | if ( reset == 1 ) begin 115 | tx_busy_jk <= 0; 116 | tx_done_jk <= 0; 117 | tx_fsm <= 2'b00; 118 | end 119 | end 120 | assign tx_nib_bin = tx_byte_sr[7:4]; 121 | 122 | 123 | endmodule // mesa_byte2ascii 124 | -------------------------------------------------------------------------------- /verilog/mesa_core.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- Source file: mesa_core.v 3 | -- Date: October 4, 2015 4 | -- Author: khubbard 5 | -- Description: Wrapper around a bunch of Mesa Bus Modules. This takes in the 6 | -- binary nibble stream from mesa_phy and takes care of slot 7 | -- enumeration and subslot bus decoding to local-bus. 8 | -- SubSlot-0 is 32bit user localbus. 9 | -- SubSlot-E is 32bit SPI PROM Interface localbus. 10 | -- SubSlot-F is power management,etc. 11 | -- License: This project is licensed with the CERN Open Hardware Licence 12 | -- v1.2. You may redistribute and modify this project under the 13 | -- terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl). 14 | -- This project is distributed WITHOUT ANY EXPRESS OR IMPLIED 15 | -- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY 16 | -- AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL 17 | -- v.1.2 for applicable Conditions. 18 | -- 19 | -- Language: Verilog-2001 and VHDL-1993 20 | -- Simulation: Mentor-Modelsim 21 | -- Synthesis: Xilinst-XST 22 | -- 23 | -- Revision History: 24 | -- Ver# When Who What 25 | -- ---- -------- -------- --------------------------------------------------- 26 | -- 0.1 10.04.15 khubbard Creation 27 | -- ***************************************************************************/ 28 | `default_nettype none // Strictly enforce all nets to be declared 29 | 30 | module mesa_core # 31 | ( 32 | parameter spi_prom_en = 1 33 | ) 34 | ( 35 | input wire clk, 36 | input wire reset, 37 | output wire lb_wr, 38 | output wire lb_rd, 39 | output wire [31:0] lb_addr, 40 | output wire [31:0] lb_wr_d, 41 | input wire [31:0] lb_rd_d, 42 | input wire lb_rd_rdy, 43 | 44 | output wire spi_sck, 45 | output wire spi_cs_l, 46 | output wire spi_mosi, 47 | input wire spi_miso, 48 | 49 | input wire [3:0] pi_mosi_d, 50 | input wire pi_mosi_rdy, 51 | input wire [3:0] rx_in_d, 52 | input wire rx_in_rdy, 53 | 54 | output reg [7:0] tx_byte_d, 55 | output reg tx_byte_rdy, 56 | output reg tx_done, 57 | input wire tx_busy, 58 | output wire [7:0] tx_wo_byte, 59 | output wire tx_wo_rdy, 60 | input wire oob_en, 61 | input wire oob_done, 62 | //input wire user_ro_en, 63 | 64 | output wire [8:0] subslot_ctrl, 65 | output wire reconfig_req, 66 | output wire [31:0] reconfig_addr, 67 | //output reg ftdi_release, 68 | output reg power_off_req, 69 | output wire bist_req 70 | );// module mesa_core 71 | 72 | wire rx_loc_rdy; 73 | wire rx_loc_start; 74 | wire rx_loc_stop; 75 | wire [7:0] rx_loc_d; 76 | 77 | wire [7:0] tx_spi_byte_d; 78 | wire tx_spi_byte_rdy; 79 | wire tx_spi_done; 80 | wire [7:0] tx_lb_byte_d; 81 | wire tx_lb_byte_rdy; 82 | wire tx_lb_done; 83 | wire tx_busy_loc; 84 | reg [3:0] tx_busy_sr; 85 | 86 | //wire lb_wr; 87 | //wire lb_rd; 88 | //wire [31:0] lb_addr; 89 | //wire [31:0] lb_wr_d; 90 | //reg [31:0] lb_rd_d; 91 | //reg lb_rd_rdy; 92 | //wire [31:0] u0_lb_rd_d; 93 | //wire u0_lb_rd_rdy; 94 | 95 | wire prom_wr; 96 | wire prom_rd; 97 | wire [31:0] prom_addr; 98 | wire [31:0] prom_wr_d; 99 | wire [31:0] prom_rd_d; 100 | wire prom_rd_rdy; 101 | reg prom_cs_c; 102 | reg prom_cs_d; 103 | 104 | //reg [31:0] lb_00_reg; 105 | //reg [31:0] lb_08_reg; 106 | //reg [31:0] lb_10_reg; 107 | //reg [31:0] lb_40_reg; 108 | //reg [31:0] lb_44_reg; 109 | //reg [31:0] lb_48_reg; 110 | wire [31:0] slot_size; 111 | //wire [7:0] tx_byte_d; 112 | //wire tx_byte_rdy; 113 | //wire tx_busy; 114 | //wire tx_done; 115 | //assign tx_busy = 0; 116 | wire [31:0] time_stamp_d; 117 | //wire oob_en_loc; 118 | //wire oob_done; 119 | //wire oob_tx_busy; 120 | 121 | 122 | //----------------------------------------------------------------------------- 123 | // Decode the 2 PROM Addresses at 0x20 and 0x24 using combo logic 124 | //----------------------------------------------------------------------------- 125 | always @ ( * ) begin : proc_prom_decode 126 | begin 127 | if ( prom_addr[15:0] == 16'h0020 ) begin 128 | prom_cs_c <= prom_wr | prom_rd; 129 | end else begin 130 | prom_cs_c <= 0; 131 | end 132 | if ( prom_addr[15:0] == 16'h0024 ) begin 133 | prom_cs_d <= prom_wr | prom_rd; 134 | end else begin 135 | prom_cs_d <= 0; 136 | end 137 | end 138 | end // proc_prom_decode 139 | 140 | 141 | // ---------------------------------------------------------------------------- 142 | // Ro Mux : Mux between multiple byte sources for Ro readback path. 143 | // Note: There is no arbitration - 1st come 1st service requires that only 144 | // one device will send readback data ( polled requests ). 145 | // ---------------------------------------------------------------------------- 146 | always @ ( posedge clk ) begin : proc_tx 147 | tx_busy_sr[0] <= tx_lb_byte_rdy | tx_spi_byte_rdy | tx_busy; 148 | tx_busy_sr[3:1] <= tx_busy_sr[2:0]; 149 | tx_byte_rdy <= tx_lb_byte_rdy | tx_spi_byte_rdy; 150 | tx_done <= tx_lb_done | tx_spi_done | oob_done;// Sends LF 151 | 152 | if ( tx_lb_byte_rdy == 1 ) begin 153 | tx_byte_d <= tx_lb_byte_d[7:0]; 154 | end else begin 155 | tx_byte_d <= tx_spi_byte_d[7:0]; 156 | end 157 | end // proc_tx 158 | // Support pipeling Ro byte path by asserting busy for 4 clocks after a byte 159 | assign tx_busy_loc = ( tx_busy_sr != 4'b0000 ) ? 1 : 0; 160 | 161 | 162 | //----------------------------------------------------------------------------- 163 | // Decode Slot Addresses : Take in the Wi path as nibbles and generate the Wo 164 | // paths for both internal and external devices. 165 | //----------------------------------------------------------------------------- 166 | mesa_decode u_mesa_decode 167 | ( 168 | .clk ( clk ), 169 | .reset ( reset ), 170 | .rx_in_d ( rx_in_d[3:0] ), 171 | .rx_in_rdy ( rx_in_rdy ), 172 | .pi_mosi_d ( pi_mosi_d[3:0] ), 173 | .pi_mosi_rdy ( pi_mosi_rdy ), 174 | .rx_out_d ( tx_wo_byte[7:0] ), 175 | .rx_out_rdy ( tx_wo_rdy ), 176 | .rx_loc_d ( rx_loc_d[7:0] ), 177 | .rx_loc_rdy ( rx_loc_rdy ), 178 | .rx_loc_start ( rx_loc_start ), 179 | .rx_loc_stop ( rx_loc_stop ) 180 | ); 181 | 182 | 183 | //----------------------------------------------------------------------------- 184 | // Convert Subslots 0x0 and 0xE to 32bit local bus for user logic and prom 185 | //----------------------------------------------------------------------------- 186 | mesa2lb u_mesa2lb 187 | ( 188 | .clk ( clk ), 189 | .reset ( reset ), 190 | .rx_byte_d ( rx_loc_d[7:0] ), 191 | .rx_byte_rdy ( rx_loc_rdy ), 192 | .rx_byte_start ( rx_loc_start ), 193 | .rx_byte_stop ( rx_loc_stop ), 194 | .tx_byte_d ( tx_lb_byte_d[7:0] ), 195 | .tx_byte_rdy ( tx_lb_byte_rdy ), 196 | .tx_done ( tx_lb_done ), 197 | .tx_busy ( tx_busy_loc ), 198 | .lb_wr ( lb_wr ), 199 | .lb_rd ( lb_rd ), 200 | .lb_wr_d ( lb_wr_d[31:0] ), 201 | .lb_addr ( lb_addr[31:0] ), 202 | .lb_rd_d ( lb_rd_d[31:0] ), 203 | .lb_rd_rdy ( lb_rd_rdy ), 204 | .oob_en ( oob_en ), 205 | .oob_rd_d ( lb_rd_d[31:0] ), 206 | .oob_rd_rdy ( lb_rd_rdy ), 207 | .prom_wr ( prom_wr ), 208 | .prom_rd ( prom_rd ), 209 | .prom_wr_d ( prom_wr_d[31:0] ), 210 | .prom_addr ( prom_addr[31:0] ), 211 | .prom_rd_d ( prom_rd_d[31:0] ), 212 | .prom_rd_rdy ( prom_rd_rdy ) 213 | ); 214 | 215 | 216 | //----------------------------------------------------------------------------- 217 | // Convert Subslots 0x1 to SPI 218 | // Use spi_ck_div of 0x7 for div-8 of 24 MHz to 3 MHz for SPI of 1.5 MHz. 219 | //----------------------------------------------------------------------------- 220 | //mesa2spi u_mesa2spi 221 | //( 222 | // .clk ( clk ), 223 | // .reset ( reset ), 224 | // .subslot ( 4'd1 ), 225 | // .spi_ck_div ( 4'd7 ), 226 | // .rx_byte_d ( rx_loc_d[7:0] ), 227 | // .rx_byte_rdy ( rx_loc_rdy ), 228 | // .rx_byte_start ( rx_loc_start ), 229 | // .rx_byte_stop ( rx_loc_stop ), 230 | // 231 | // .tx_byte_d ( tx_spi_byte_d[7:0] ), 232 | // .tx_byte_rdy ( tx_spi_byte_rdy ), 233 | // .tx_done ( tx_spi_done ), 234 | // .tx_busy ( tx_busy_loc ), 235 | // .spi_sck ( ), 236 | // .spi_ss_l ( ), 237 | // .spi_mosi ( ), 238 | // .spi_miso ( ) 239 | //); 240 | assign tx_spi_byte_d[7:0] = 8'd0; 241 | assign tx_spi_byte_rdy = 1'b0; 242 | assign tx_spi_done = 1'b0; 243 | 244 | 245 | //----------------------------------------------------------------------------- 246 | // Decode Subslot Nibble Controls 247 | //----------------------------------------------------------------------------- 248 | mesa2ctrl u_mesa2ctrl 249 | ( 250 | .clk ( clk ), 251 | .reset ( reset ), 252 | .rx_byte_d ( rx_loc_d[7:0] ), 253 | .rx_byte_rdy ( rx_loc_rdy ), 254 | .rx_byte_start ( rx_loc_start ), 255 | .rx_byte_stop ( rx_loc_stop ), 256 | .subslot_ctrl ( subslot_ctrl[8:0] ) 257 | ); 258 | 259 | 260 | //----------------------------------------------------------------------------- 261 | // Interface to SPI PROM : Allow LB to program SPI PROM, request reconfig 262 | // ck_divisor 10 is for ( 80M / 10 ) for 2x SPI Clock Rate of 4 MHz 263 | // ck_divisor 3 is for ( 24M / 3 ) for 2x SPI Clock Rate of 4 MHz 264 | // PROM Slot Size 265 | // slot_size 0x00020000 is 1Mbit Slot for ICE5LP4K 266 | // slot_size 0x00040000 is 2Mbit Slot for XC3S200A (Compressed, no BRAM ROMs) 267 | // slot_size 0x00080000 is 4Mbit Slot for XC6SLX9 (Compressed, no BRAM ROMs) 268 | //----------------------------------------------------------------------------- 269 | generate 270 | if ( spi_prom_en == 1 ) begin 271 | spi_prom u_spi_prom 272 | ( 273 | .reset ( reset ), 274 | .prom_is_32b ( 1'b0 ), 275 | .ck_divisor ( 8'd3 ), 276 | .slot_size ( slot_size[31:0] ), 277 | .protect_1st_slot ( 1'b1 ), 278 | .clk_lb ( clk ), 279 | 280 | .lb_cs_prom_c ( prom_cs_c ), 281 | .lb_cs_prom_d ( prom_cs_d ), 282 | .lb_wr ( prom_wr ), 283 | .lb_rd ( prom_rd ), 284 | .lb_wr_d ( prom_wr_d[31:0] ), 285 | .lb_rd_d ( prom_rd_d[31:0] ), 286 | .lb_rd_rdy ( prom_rd_rdy ), 287 | 288 | .spi_ctrl ( 4'b0000 ), 289 | .spi_sck ( spi_sck ), 290 | .spi_cs_l ( spi_cs_l ), 291 | .spi_mosi ( spi_mosi ), 292 | .spi_miso ( spi_miso ), 293 | 294 | .flag_wip ( ), 295 | .bist_req ( bist_req ), 296 | .reconfig_2nd_slot ( 1'b0 ), 297 | .reconfig_req ( reconfig_req ), 298 | .reconfig_addr ( reconfig_addr[31:0] ) 299 | );// spi_prom 300 | end else begin 301 | assign spi_sck = 1; 302 | assign spi_cs_l = 1; 303 | assign spi_mosi = 1; 304 | assign bist_req = 0; 305 | assign reconfig_req = 0; 306 | assign reconfig_addr = 32'd0; 307 | assign prom_rd_d = 32'd0; 308 | assign prom_rd_rdy = 0; 309 | end 310 | endgenerate 311 | assign slot_size = 32'h00020000; 312 | 313 | 314 | endmodule // mesa_core 315 | -------------------------------------------------------------------------------- /verilog/mesa_decode.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- (C) Copyright 2015 Kevin M. Hubbard @ Black Mesa Labs 3 | -- Source file: mesa_decode.v 4 | -- Date: October 4, 2015 5 | -- Author: khubbard 6 | -- Language: Verilog-2001 7 | -- Description: The Mesa Bus decoder. Mesa Bus is a byte-pipe much like a 8 | -- 8b10b SERDES pipe. It supports sending packetized streams of 9 | -- serialized bytes to multiple targets on a single serial bus. 10 | -- This implementation uses UART serial, but the protocol is 11 | -- portable and may be used over SERDES or a synchronous bit, 12 | -- nibble or byte wide streams. 13 | -- This block decodes packets and routes them to both 14 | -- dowstream slots and the internal sub-slots for this slot. 15 | -- 16 | -- Example: 17 | -- .."FF".."FF"."F0123401[56]" : 18 | -- 0xFF = Bus Idle ( NULLs ) 19 | -- B0 0xF0 = New Bus Cycle to begin ( Nibble and bit orientation ) 20 | -- B1 0x12 = Slot Number, 0xFF = Broadcast all slots, 0xFE = NULL Dest 21 | -- B2 0x3 = Sub-Slot within the chip (0-0xF) 22 | -- 0x4 = Command Nibble for Sub-Slot ( Specific to that SubSlot ) 23 | -- B3 0x01 = Number of Payload Bytes (0-255) 24 | -- 0x56 = The Payload ( 1 Byte in this example, up to 255 total ) 25 | -- 26 | -- Slot Numbering 0x00-0xFF: 27 | -- 0x00 - 0xFD : Physical Slots 0-253 28 | -- 0xF0 - 0xFD : Reserved 29 | -- 0xFE : Nobody slot ( NULL ) 30 | -- 0xFF : Broadcast to 0x00-0xEF 31 | -- 32 | -- SubSlot Numbering 0x0-0xF: 33 | -- 0x0 - 0x7 : User SubSlots ( 0x0 is nominally a 32bit PCI local bus ) 34 | -- 0x0 = LB Bus Write 35 | -- 0x1 = LB Bus Read 36 | -- 0x2 = LB Bus Write Repeat ( same address ) 37 | -- 0x3 = LB Bus Read Repeat ( same address ) 38 | -- 0x8 - 0xB : Scope Probe CH1-CH4 Mux Selects 39 | -- 0x0 - 0xF : 1 of 16 signal sets to observe. 0x0 nom OFF 40 | -- 0xE : FPGA PROM Access 41 | -- Commands: 42 | -- 0x0 = LB Bus Write 43 | -- 0x1 = LB Bus Read 44 | -- 0x2 = LB Bus Write Repeat ( same address ) 45 | -- 0x3 = LB Bus Read Repeat ( same address ) 46 | -- 0xF : Mesa Control : Power and Pin Control 47 | -- Commands: 48 | -- 49 | -- 0x0 = Ro pin is MesaBus Ro Readback ( Default ) 50 | -- 0x1 = Ro pin is MesaBus Wi loopback 51 | -- 0x2 = Ro pin is MesaBus Interrupt 52 | -- 0x3 = Ro pin is user defined output function 53 | -- 0x4 = Ri pin is MesaBus Input ( Default ) 54 | -- 0x5 = Ri pin is disabled 55 | -- 0x6 = Wo pin is MesaBus Output ( Default ) 56 | -- 0x7 = Wo pin is disabled 57 | -- 58 | -- 0x8 = RESERVED 59 | -- 0x9 = RESERVED 60 | -- 0xA = Report Device ID 61 | -- 0xB = Reset Core 62 | -- 0xC = Clear Baud Lock 63 | -- 0xD = Power Off - Clock Trees Disabled 64 | -- 0xE = Boot to Slot-1 Bootloader (Default) 65 | -- 0xF = Boot to Slot-2 User Image 66 | -- 67 | -- Revision History: 68 | -- Ver# When Who What 69 | -- ---- -------- -------- --------------------------------------------------- 70 | -- 0.1 10.04.15 khubbard Creation 71 | -- 0.2 07.16.15 khubbard rx_in_flush added. 72 | -- 0.3 10.21.17 khubbard USB3 fix to support nibbles coming in every clock 73 | -- ***************************************************************************/ 74 | //`default_nettype none // Strictly enforce all nets to be declared 75 | 76 | module mesa_decode 77 | ( 78 | input wire clk, 79 | input wire reset, 80 | input wire rx_in_flush, 81 | input wire [3:0] rx_in_d, 82 | input wire rx_in_rdy, 83 | output wire [7:0] rx_out_d, 84 | output wire rx_out_rdy, 85 | output wire [7:0] rx_loc_d, 86 | output wire rx_loc_rdy, 87 | output wire rx_loc_start, 88 | output wire rx_loc_stop 89 | ); // module mesa_decode 90 | 91 | 92 | reg lbracket_jk; 93 | reg passthru_jk; 94 | reg broadcst_jk; 95 | reg payload_jk; 96 | reg process_jk; 97 | 98 | reg packet_jk; 99 | reg packet_jk_p1; 100 | reg [7:0] byte_sr; 101 | reg byte_pingpong; 102 | reg rx_in_rdy_p1; 103 | reg byte_rdy; 104 | reg byte_rdy_p1; 105 | reg [3:0] byte_cnt; 106 | reg [7:0] byte_loc; 107 | reg [7:0] byte_out; 108 | reg [7:0] payload_cnt; 109 | reg packet_done; 110 | 111 | reg loc_start; 112 | reg [7:0] loc_slot; 113 | reg [3:0] loc_subslot; 114 | reg [3:0] loc_command; 115 | reg [7:0] loc_payload; 116 | 117 | assign rx_out_d = byte_out[7:0]; 118 | assign rx_out_rdy = byte_rdy_p1; 119 | assign rx_loc_d = byte_loc[7:0]; 120 | assign rx_loc_rdy = byte_rdy_p1; 121 | assign rx_loc_start = loc_start; 122 | assign rx_loc_stop = packet_done; 123 | 124 | 125 | //----------------------------------------------------------------------------- 126 | // Shift a nibble into a byte shift register. The 1st 0xF0 received when NOT 127 | // currently in a packet determines the phasing for byte within nibble stream. 128 | //----------------------------------------------------------------------------- 129 | always @ ( posedge clk ) begin : proc_nib_in 130 | rx_in_rdy_p1 <= rx_in_rdy; 131 | if ( rx_in_rdy == 1 ) begin 132 | byte_sr[7:4] <= byte_sr[3:0]; 133 | byte_sr[3:0] <= rx_in_d[3:0]; 134 | byte_pingpong <= ~ byte_pingpong; 135 | end 136 | if ( packet_jk == 0 ) begin 137 | byte_pingpong <= 0; 138 | end 139 | if ( reset == 1 ) begin 140 | byte_sr[7:0] <= 8'hFF; 141 | end 142 | end 143 | 144 | 145 | //----------------------------------------------------------------------------- 146 | // Decode and direct : Packet begins on a 0xF0 byte - which provides for both 147 | // bit and nibble alignment as bus sits idle at 0xFF. 148 | //----------------------------------------------------------------------------- 149 | always @ ( posedge clk ) begin : proc_byte_in 150 | byte_rdy <= 0; 151 | packet_jk_p1 <= packet_jk; 152 | 153 | // 2017.10.21 Fix to support nibbles coming in every clock cycle 154 | if ( rx_in_rdy == 1 ) begin 155 | if ( rx_in_d[3:0] == 4'h0 && byte_sr[3:0] == 4'hF && packet_jk == 0 ) begin 156 | packet_jk <= 1; 157 | byte_rdy <= 1; 158 | end 159 | if ( packet_jk == 1 && byte_pingpong == 1 ) begin 160 | byte_rdy <= 1; 161 | end 162 | end 163 | 164 | if ( reset == 1 || packet_done == 1 || rx_in_flush == 1 ) begin 165 | packet_jk <= 0; 166 | end 167 | end // proc_byte_in 168 | 169 | 170 | //----------------------------------------------------------------------------- 171 | // B0 B1 B2 B3 172 | // 0xFF,0xFF,0xF0,Slot,Sub-Slot+Command,Payload_Len,{ payload }, 173 | // 174 | // A Packet is a 4-byte header followed by an optional n-Byte Payload. 175 | // The Byte after the 1st 0xF0 determines the destination slot. 176 | // slot 0xFF is broadcast and is forwarded untouched as 0xFF. 177 | // slot 0xFE is null and is forwarded untouched as 0xFE. 178 | // slot 0x00 is for this slot and is forwarded as 0xFE. 179 | // slot 0x01-0xFD is decremented by 1 and forwarded 180 | // The 4th Byte determines the length of the payload. If 0, the packet is done. 181 | // otherwise, packet continues for n-Bytes to deliver the payload. A 0xF0 182 | // following a completed packet indicates start of next packet. 183 | //----------------------------------------------------------------------------- 184 | always @ ( posedge clk ) begin : proc_header 185 | byte_rdy_p1 <= byte_rdy; 186 | packet_done <= 0; 187 | loc_start <= 0; 188 | if ( byte_rdy == 1 ) begin 189 | // Count the Packet Header Bytes from 1-4 and stop 190 | if ( byte_cnt != 4'h4 ) begin 191 | byte_cnt <= byte_cnt + 1; 192 | end 193 | if ( byte_cnt == 4'h3 ) begin 194 | payload_cnt <= byte_sr[7:0]; 195 | if ( byte_sr == 8'd0 ) begin 196 | packet_done <= 1;// No Payload - done immediately 197 | end 198 | end 199 | if ( byte_cnt == 4'h4 ) begin 200 | payload_cnt <= payload_cnt - 1; 201 | end 202 | if ( byte_cnt == 4'h4 && payload_cnt == 8'd1 ) begin 203 | packet_done <= 1; 204 | end 205 | 206 | if ( byte_cnt == 4'h0 ) begin 207 | loc_start <= 1; 208 | end 209 | if ( byte_cnt == 4'h1 ) begin 210 | loc_slot <= byte_sr[7:0]; 211 | end 212 | if ( byte_cnt == 4'h2 ) begin 213 | loc_subslot <= byte_sr[7:4]; 214 | loc_command <= byte_sr[3:0]; 215 | end 216 | if ( byte_cnt == 4'h3 ) begin 217 | loc_payload <= byte_sr[7:0]; 218 | end 219 | 220 | // Decode the Slot Number, Decrement when needed. Route to Local and Ext 221 | if ( byte_cnt == 4'h1 ) begin 222 | if ( byte_sr == 8'hFF || 223 | byte_sr == 8'hFE ) begin 224 | byte_loc <= byte_sr[7:0];// 0xFF Broadcast and 0xFE null go to everybody 225 | byte_out <= byte_sr[7:0]; 226 | end else if ( byte_sr != 8'h00 ) begin 227 | byte_loc <= 8'hFE; 228 | byte_out <= byte_sr[7:0] - 1;// Decrement the Slot Number as non-zero 229 | end else begin 230 | byte_loc <= byte_sr[7:0];// Slot Number is 0x00, so this slot gets it 231 | byte_out <= 8'hFE; // Downstream slots get 0xFE instead 232 | end 233 | end else begin 234 | byte_loc <= byte_sr[7:0]; 235 | byte_out <= byte_sr[7:0]; 236 | end 237 | end // if ( byte_rdy == 1 ) begin 238 | 239 | if ( packet_jk == 0 ) begin 240 | byte_cnt <= 4'd0; 241 | payload_cnt <= 8'd0; 242 | end 243 | end // proc_header 244 | 245 | 246 | endmodule // mesa_decode 247 | -------------------------------------------------------------------------------- /verilog/mesa_id.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- Source file: mesa_id.v 3 | -- Date: October 2015 4 | -- Author: khubbard 5 | -- Description: Simple state machine the reports chip ID over mesa-bus on 6 | -- request and muxes in the normal Ro byte path when idle. 7 | -- Language: Verilog-2001 8 | -- Simulation: Mentor-Modelsim 9 | -- Synthesis: Lattice 10 | -- 11 | -- Revision History: 12 | -- Ver# When Who What 13 | -- ---- -------- -------- --------------------------------------------------- 14 | -- 0.1 10.04.15 khubbard Creation 15 | -- ***************************************************************************/ 16 | `default_nettype none // Strictly enforce all nets to be declared 17 | 18 | module mesa_id 19 | ( 20 | input wire clk, 21 | input wire reset, 22 | input wire report_id, 23 | input wire [31:0] id_mfr, 24 | input wire [31:0] id_dev, 25 | input wire [31:0] id_snum, 26 | input wire [7:0] mesa_core_ro_byte_d, 27 | input wire mesa_core_ro_byte_en, 28 | input wire mesa_core_ro_done, 29 | input wire mesa_ro_busy, 30 | output reg [7:0] mesa_ro_byte_d, 31 | output reg mesa_ro_byte_en, 32 | output reg mesa_ro_done 33 | );// module mesa_id 34 | 35 | reg report_jk; 36 | reg report_id_p1; 37 | reg [4:0] report_cnt; 38 | reg mesa_ro_busy_p1; 39 | wire [31:0] time_stamp_d; 40 | 41 | 42 | //----------------------------------------------------------------------------- 43 | // Ro binary bytes are converted to 2 ASCII nibble chars for MesaBus Ro 44 | // This is also a report_id FSM that muxes into the ro byte path on request. 45 | //----------------------------------------------------------------------------- 46 | always @ ( posedge clk ) begin : proc_mesa_ro_byte 47 | report_id_p1 <= report_id; 48 | mesa_ro_byte_d[7:0] <= mesa_core_ro_byte_d[7:0]; 49 | mesa_ro_byte_en <= mesa_core_ro_byte_en; 50 | mesa_ro_done <= mesa_core_ro_done; 51 | mesa_ro_busy_p1 <= mesa_ro_busy; 52 | 53 | // When report_id asserts ( SubSlot 0xFA command ) shift out 54 | // a unique 32bit ID of 16 bit Manufacture and 16bit Device 55 | if ( report_id == 1 ) begin 56 | report_jk <= 1;// Start FSM 57 | report_cnt <= 5'd0; 58 | end 59 | 60 | // State Machine for sending out device id when requested 61 | mesa_ro_busy_p1 <= mesa_ro_busy; 62 | if ( report_jk == 1 ) begin 63 | mesa_ro_byte_en <= 0; 64 | mesa_ro_done <= 0; 65 | 66 | if ( report_id_p1==1 || ( mesa_ro_busy_p1==1 && mesa_ro_busy==0 )) begin 67 | report_cnt <= report_cnt[4:0] + 1; 68 | mesa_ro_byte_en <= 1; 69 | if ( report_cnt == 5'd0 ) begin 70 | mesa_ro_byte_d[7:0] <= 8'hF0;// Header : Preamble 71 | end else if ( report_cnt == 5'd1 ) begin 72 | mesa_ro_byte_d[7:0] <= 8'hFE;// Header : Ro Slot is 0xFE 73 | end else if ( report_cnt == 5'd2 ) begin 74 | mesa_ro_byte_d[7:0] <= 8'h00;// Header : Ro Subslot is 0x00 75 | end else if ( report_cnt == 5'd3 ) begin 76 | mesa_ro_byte_d[7:0] <= 8'h10;// Header : 16 Bytes in Payload 77 | 78 | end else if ( report_cnt == 5'd4 ) begin 79 | mesa_ro_byte_d[7:0] <= id_mfr[31:24]; 80 | end else if ( report_cnt == 5'd5 ) begin 81 | mesa_ro_byte_d[7:0] <= id_mfr[23:16]; 82 | end else if ( report_cnt == 5'd6 ) begin 83 | mesa_ro_byte_d[7:0] <= id_mfr[15:8]; 84 | end else if ( report_cnt == 5'd7 ) begin 85 | mesa_ro_byte_d[7:0] <= id_mfr[7:0]; 86 | 87 | end else if ( report_cnt == 5'd8 ) begin 88 | mesa_ro_byte_d[7:0] <= id_dev[31:24]; 89 | end else if ( report_cnt == 5'd9 ) begin 90 | mesa_ro_byte_d[7:0] <= id_dev[23:16]; 91 | end else if ( report_cnt == 5'd10) begin 92 | mesa_ro_byte_d[7:0] <= id_dev[15:8]; 93 | end else if ( report_cnt == 5'd11) begin 94 | mesa_ro_byte_d[7:0] <= id_dev[7:0]; 95 | 96 | end else if ( report_cnt == 5'd12) begin 97 | mesa_ro_byte_d[7:0] <= id_snum[31:24]; 98 | end else if ( report_cnt == 5'd13) begin 99 | mesa_ro_byte_d[7:0] <= id_snum[23:16]; 100 | end else if ( report_cnt == 5'd14) begin 101 | mesa_ro_byte_d[7:0] <= id_snum[15:8]; 102 | end else if ( report_cnt == 5'd15) begin 103 | mesa_ro_byte_d[7:0] <= id_snum[7:0]; 104 | 105 | end else if ( report_cnt == 5'd16) begin 106 | mesa_ro_byte_d[7:0] <= time_stamp_d[31:24]; 107 | end else if ( report_cnt == 5'd17) begin 108 | mesa_ro_byte_d[7:0] <= time_stamp_d[23:16]; 109 | end else if ( report_cnt == 5'd18) begin 110 | mesa_ro_byte_d[7:0] <= time_stamp_d[15:8]; 111 | end else if ( report_cnt == 5'd19) begin 112 | mesa_ro_byte_d[7:0] <= time_stamp_d[7:0]; 113 | mesa_ro_done <= 1;// Send LF 114 | report_jk <= 0;// All Done - stop FSM 115 | end else begin 116 | mesa_ro_byte_d[7:0] <= 8'h00;// 0x00 = NULL 117 | end 118 | end 119 | end // if ( report_jk == 1 ) begin 120 | 121 | end // proc_mesa_ro_byte 122 | 123 | //----------------------------------------------------------------------------- 124 | // 32bit UNIX TimeStamp of when the design was synthesized 125 | //----------------------------------------------------------------------------- 126 | time_stamp u_time_stamp 127 | ( 128 | .time_dout ( time_stamp_d[31:0] ) 129 | ); 130 | 131 | 132 | endmodule // mesa_id.v 133 | -------------------------------------------------------------------------------- /verilog/mesa_phy.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- Source file: mesa_phy.v 3 | -- Date: October 2015 4 | -- Author: khubbard 5 | -- Description: Interface the Byte binary stream of the internal Mesa-Bus with 6 | -- the physical layer. For this case, using UARTs. 7 | -- This instantiates the UARTs and takes care of the binary to 8 | -- ASCII conversions for all directions. 9 | -- Language: Verilog-2001 and VHDL-1993 10 | -- Simulation: Mentor-Modelsim 11 | -- Synthesis: Lattice 12 | -- License: This project is licensed with the CERN Open Hardware Licence 13 | -- v1.2. You may redistribute and modify this project under the 14 | -- terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl). 15 | -- This project is distributed WITHOUT ANY EXPRESS OR IMPLIED 16 | -- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY 17 | -- AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL 18 | -- v.1.2 for applicable Conditions. 19 | -- 20 | -- Revision History: 21 | -- Ver# When Who What 22 | -- ---- -------- -------- --------------------------------------------------- 23 | -- 0.1 10.04.15 khubbard Creation 24 | -- ***************************************************************************/ 25 | `default_nettype none // Strictly enforce all nets to be declared 26 | 27 | module mesa_phy 28 | ( 29 | input wire clk, 30 | input wire reset, 31 | input wire disable_chain, 32 | input wire clr_baudlock, 33 | output wire mesa_wi_baudlock, 34 | 35 | input wire mesa_wi, 36 | output wire mesa_wo, 37 | input wire mesa_ri, 38 | output wire mesa_ro, 39 | 40 | output wire mesa_wi_nib_en, 41 | output wire [3:0] mesa_wi_nib_d, 42 | input wire mesa_wo_byte_en, 43 | input wire [7:0] mesa_wo_byte_d, 44 | output wire mesa_wo_busy, 45 | input wire mesa_ro_byte_en, 46 | input wire [7:0] mesa_ro_byte_d, 47 | output wire mesa_ro_busy, 48 | input wire mesa_ro_done 49 | );// module mesa_phy 50 | 51 | 52 | wire wi_char_en; 53 | wire [7:0] wi_char_d; 54 | wire ro_char_en; 55 | wire [7:0] ro_char_d; 56 | wire ro_uart_busy; 57 | wire ro_uart_idle; 58 | wire wo_char_en; 59 | wire [7:0] wo_char_d; 60 | wire wo_uart_busy; 61 | wire baud_lock; 62 | wire [15:0] baud_rate; 63 | 64 | assign mesa_wi_baudlock = baud_lock; 65 | 66 | //----------------------------------------------------------------------------- 67 | // UART to convert serial streams to/from ASCII bytes for Wi and Ro. 68 | //----------------------------------------------------------------------------- 69 | mesa_uart u_mesa_uart 70 | ( 71 | .clk ( clk ), 72 | .reset ( reset ), 73 | .clr_baudlock ( clr_baudlock ), 74 | .en_autobaud ( 1'b1 ), 75 | //.en_autobaud ( 1'b0 ), 76 | .rxd ( mesa_wi ), 77 | .txd ( mesa_ro ), 78 | .flush ( ), 79 | .dbg ( ), 80 | .rx_rdy ( wi_char_en ), 81 | .rx_byte ( wi_char_d[7:0] ), 82 | 83 | .tx_en ( ro_char_en ), 84 | .tx_byte ( ro_char_d[7:0] ), 85 | .tx_busy ( ro_uart_busy ), 86 | .tx_idle ( ro_uart_idle ), 87 | .rx_idle ( ), 88 | .baud_rate ( baud_rate[15:0] ), 89 | .baud_lock ( baud_lock ) 90 | ); // module mesa_uart 91 | 92 | 93 | //----------------------------------------------------------------------------- 94 | // TX Only UART. Sends Wo data. When 1st UART goes to lock, sends "\n" out, 95 | // otherwise just echos the binary stream from decode block ( Wi->Wo ). 96 | //----------------------------------------------------------------------------- 97 | mesa_tx_uart u_mesa_tx_uart 98 | ( 99 | .clk ( clk ), 100 | .reset ( reset | disable_chain ), 101 | .txd ( mesa_wo ), 102 | .tx_en ( wo_char_en ), 103 | .tx_byte ( wo_char_d[7:0] ), 104 | .tx_busy ( wo_uart_busy ), 105 | .baud_rate ( baud_rate[15:0] ), 106 | .baud_lock ( baud_lock ) 107 | ); // module mesa_uart 108 | 109 | 110 | //----------------------------------------------------------------------------- 111 | // Convert Wi ASCII to Binary Nibbles. Decoder figures out nibble/byte phase 112 | //----------------------------------------------------------------------------- 113 | mesa_ascii2nibble u_mesa_ascii2nibble 114 | ( 115 | .clk ( clk ), 116 | .rx_char_en ( wi_char_en ), 117 | .rx_char_d ( wi_char_d[7:0] ), 118 | .rx_nib_en ( mesa_wi_nib_en ), 119 | .rx_nib_d ( mesa_wi_nib_d[3:0] ) 120 | );// module mesa_ascii2nibble 121 | 122 | 123 | //----------------------------------------------------------------------------- 124 | // Convert Ro Binary Bytes to ASCII 125 | //----------------------------------------------------------------------------- 126 | mesa_byte2ascii u0_mesa_byte2ascii 127 | ( 128 | .clk ( clk ), 129 | .reset ( reset ), 130 | .tx_byte_en ( mesa_ro_byte_en ), 131 | .tx_byte_d ( mesa_ro_byte_d[7:0] ), 132 | .tx_byte_busy ( mesa_ro_busy ), 133 | .tx_byte_done ( mesa_ro_done ), 134 | .tx_char_en ( ro_char_en ), 135 | .tx_char_d ( ro_char_d[7:0] ), 136 | .tx_char_busy ( ro_uart_busy ), 137 | .tx_char_idle ( ro_uart_idle ) 138 | );// module mesa_byte2ascii 139 | 140 | 141 | //----------------------------------------------------------------------------- 142 | // Convert Wo Binary Bytes to ASCII 143 | //----------------------------------------------------------------------------- 144 | mesa_byte2ascii u1_mesa_byte2ascii 145 | ( 146 | .clk ( clk ), 147 | .reset ( reset | disable_chain ), 148 | .tx_byte_en ( mesa_wo_byte_en ), 149 | .tx_byte_d ( mesa_wo_byte_d[7:0] ), 150 | .tx_byte_busy ( mesa_wo_busy ), 151 | .tx_byte_done ( 1'b0 ), 152 | .tx_char_en ( wo_char_en ), 153 | .tx_char_d ( wo_char_d[7:0] ), 154 | .tx_char_busy ( wo_uart_busy ) 155 | );// module mesa_byte2ascii 156 | 157 | 158 | endmodule // mesa_phy.v 159 | -------------------------------------------------------------------------------- /verilog/mesa_pi_spi.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- (C) Copyright 2015 Kevin M. Hubbard @ Black Mesa Labs 3 | -- Source file: mesa_pi_spi.v 4 | -- Date: August 2, 2015 5 | -- Author: khubbard 6 | -- Description: Convert SPI MOSI stream from a RaspPi to Mesa binary nibbles 7 | -- Language: Verilog-2001 8 | -- License: This project is licensed with the CERN Open Hardware Licence 9 | -- v1.2. You may redistribute and modify this project under the 10 | -- terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl). 11 | -- This project is distributed WITHOUT ANY EXPRESS OR IMPLIED 12 | -- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY 13 | -- AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL 14 | -- v.1.2 for applicable Conditions. 15 | -- 16 | -- 2 MHz Capture 17 | -- pi_spi_cs_l \________________________________________________________/ 18 | -- pi_spi_sck ___________/ \__/ \__/ \__/ \______/ \_/ \_/ \________ 19 | -- pi_spi_mosi ---------< 7 >< 6 >< .. >< 0 >----< 7 ><..><0 >-------- 20 | -- pi_spi_miso 21 | -- |<-10us->| |<-2us->| 22 | -- 23 | -- http://www.raspberry-projects.com/pi/programming-in-c/spi/ 24 | -- using-the-spi-interface 25 | -- 26 | -- Revision History: 27 | -- Ver# When Who What 28 | -- ---- -------- -------- --------------------------------------------------- 29 | -- 0.1 08.02.15 khubbard Creation 30 | -- ***************************************************************************/ 31 | //`default_nettype none // Strictly enforce all nets to be declared 32 | 33 | module mesa_pi_spi 34 | ( 35 | input wire pi_spi_sck, 36 | input wire pi_spi_cs_l, 37 | input wire pi_spi_mosi, 38 | output wire pi_spi_miso, 39 | 40 | input wire mesa_id_req, 41 | input wire [31:0] id_mfr, 42 | input wire [31:0] id_dev, 43 | input wire [31:0] id_snum, 44 | input wire [31:0] id_timestamp, 45 | 46 | input wire clk, 47 | input wire lb_rd, 48 | input wire [31:0] lb_rd_d, 49 | input wire lb_rd_rdy, 50 | 51 | output reg [3:0] mosi_nib_d, 52 | output reg [3:0] tp_dbg, 53 | output reg mosi_nib_rdy 54 | ); // module mesa_pi_spi 55 | 56 | 57 | reg [1:0] bit_cnt; 58 | reg [7:0] id_bit_cnt; 59 | reg [3:0] nib_sr; 60 | reg [7:0] miso_byte; 61 | reg bit_togl; 62 | reg rdy_loc; 63 | reg rdy_meta; 64 | reg rdy_p1; 65 | reg rdy_p2; 66 | reg cs_l_meta; 67 | reg cs_l_p1; 68 | reg cs_l_p2; 69 | reg cs_l_p3; 70 | reg [2:0] spi_bit_cnt; 71 | reg [31:0] rd_d_xfer; 72 | reg [63:0] miso_sr; 73 | reg lb_rd_rdy_p1; 74 | reg rd_rdy_xfer; 75 | reg rd_rdy_xfer_wide; 76 | reg miso_shift_en; 77 | reg mesa_id_jk; 78 | 79 | 80 | //----------------------------------------------------------------------------- 81 | // Xfer clock domains 82 | //----------------------------------------------------------------------------- 83 | always @ ( posedge clk ) begin : proc_xfer 84 | begin 85 | rdy_meta <= rdy_loc; 86 | rdy_p1 <= rdy_meta; 87 | rdy_p2 <= rdy_p1; 88 | mosi_nib_rdy <= rdy_p1 & ~ rdy_p2; 89 | end 90 | end 91 | 92 | 93 | //----------------------------------------------------------------------------- 94 | // Convert MOSI to 2 nibbles to insert in regular UART nibble stream 95 | // input pi_spi_sck; 96 | // input pi_spi_cs_l; 97 | // input pi_spi_mosi; 98 | // output pi_spi_miso; 99 | //----------------------------------------------------------------------------- 100 | always @ ( posedge pi_spi_sck or posedge pi_spi_cs_l ) begin : proc_tx 101 | begin 102 | if ( pi_spi_cs_l == 1 ) begin 103 | bit_cnt <= 2'd0; 104 | rdy_loc <= 0; 105 | tp_dbg[3] <= 0; 106 | end else begin 107 | tp_dbg[3] <= rdy_loc; 108 | rdy_loc <= 0; 109 | nib_sr <= { nib_sr[2:0], pi_spi_mosi }; 110 | bit_cnt <= bit_cnt + 1; 111 | if ( bit_cnt == 2'd3 ) begin 112 | mosi_nib_d <= { nib_sr[2:0], pi_spi_mosi }; 113 | rdy_loc <= 1; 114 | end 115 | end 116 | end 117 | end // proc_tx 118 | 119 | 120 | //----------------------------------------------------------------------------- 121 | // Handle the Readback. When 32bit read comes in, latch and then decrement a 122 | // count after each SPI cycle ( where each cycle reads 1 of 8 bytes ). 123 | //----------------------------------------------------------------------------- 124 | always @ ( posedge clk ) begin : proc_lb_sr 125 | begin 126 | cs_l_meta <= pi_spi_cs_l; 127 | cs_l_p1 <= cs_l_meta; 128 | cs_l_p2 <= cs_l_p1; 129 | cs_l_p3 <= cs_l_p2; 130 | 131 | 132 | if ( lb_rd_rdy == 1 ) begin 133 | rd_d_xfer <= lb_rd_d[31:0]; 134 | miso_shift_en <= 0;// Prevent shift of 1st Ro bit from end of Wi cycle 135 | mesa_id_jk <= 0; 136 | end 137 | 138 | if ( mesa_id_req == 1 ) begin 139 | miso_shift_en <= 0;// Prevent shift of 1st Ro bit from end of Wi cycle 140 | mesa_id_jk <= 1; 141 | end 142 | 143 | if ( cs_l_p1 == 1 && cs_l_p2 == 0 ) begin 144 | miso_shift_en <= 1; 145 | end 146 | 147 | lb_rd_rdy_p1 <= lb_rd_rdy | mesa_id_req; 148 | rd_rdy_xfer <= lb_rd_rdy_p1; 149 | rd_rdy_xfer_wide <= rd_rdy_xfer | lb_rd_rdy_p1; 150 | tp_dbg[0] <= rd_rdy_xfer_wide; 151 | 152 | end 153 | end 154 | 155 | //----------------------------------------------------------------------------- 156 | // Reads are handled by MOSI shifting bytes at a time, looking for 0xF0. 157 | // When 0xF0 is received, it then reads 3+4 bytes. 158 | // Burst reads are NOT supported. 159 | // 0xFF = Bus Idle ( NULLs ) 160 | // B0 0xF0 = New Bus Cycle to begin ( Nibble and bit orientation ) 161 | // B1 0xFE = Slot Number - Default is 0xFE for Ro traffic 162 | // B2 0x0 = Sub-Slot within the chip (0-0xF) 163 | // 0x0 = Command Nibble for Sub-Slot 164 | // B3 0x04 = Number of Payload Bytes (0-255) 165 | // Wi Cycle Ro Cycle 166 | // spi_cs_l \________________/ \_____________/ 167 | // spi_sck /\/\/\/\/\________________/\/\/\/\/ 168 | //----------------------------------------------------------------------------- 169 | //always @ ( negedge pi_spi_sck or posedge rd_rdy_xfer ) begin : proc_rd_cnt 170 | //if ( rd_rdy_xfer == 1 ) begin 171 | always @ (negedge pi_spi_sck or posedge rd_rdy_xfer_wide) begin : proc_rd_cnt 172 | tp_dbg[1] <= 0; 173 | if ( rd_rdy_xfer_wide == 1 ) begin 174 | miso_sr <= { 32'hF0FE0004, rd_d_xfer[31:0] }; 175 | id_bit_cnt <= 8'd1; 176 | bit_togl <= 1'b1; 177 | end else begin 178 | if ( pi_spi_cs_l == 0 && miso_shift_en == 1 ) begin 179 | id_bit_cnt <= id_bit_cnt + 1; 180 | miso_sr <= { miso_sr[62:0], 1'b1 }; 181 | // miso_sr <= { miso_sr[62:0], bit_togl };// Debug Only 182 | bit_togl <= ~ bit_togl; 183 | if ( id_bit_cnt == 8'd1 ) begin 184 | tp_dbg[1] <= 1; 185 | end 186 | tp_dbg[2] <= bit_togl; 187 | 188 | if ( mesa_id_jk == 1 ) begin 189 | if ( id_bit_cnt == 8'd24 ) begin 190 | miso_sr[63:56] <= 8'h10;// 16 Bytes or 4 DWORDs 191 | end 192 | if ( id_bit_cnt == 8'd32 ) begin 193 | miso_sr[63:32] <= id_mfr[31:0]; 194 | end 195 | if ( id_bit_cnt == 8'd64 ) begin 196 | miso_sr[63:32] <= id_dev[31:0]; 197 | end 198 | if ( id_bit_cnt == 8'd96 ) begin 199 | miso_sr[63:32] <= id_snum[31:0]; 200 | end 201 | if ( id_bit_cnt == 8'd128 ) begin 202 | miso_sr[63:32] <= id_timestamp[31:0]; 203 | end 204 | end 205 | end 206 | end 207 | end 208 | assign pi_spi_miso = miso_sr[63]; 209 | 210 | endmodule // mesa_pi_spi 211 | -------------------------------------------------------------------------------- /verilog/mesa_rx_uart.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- (C) Copyright 2015 Black Mesa Labs 3 | -- Source file: mesa_rx_uart.v 4 | -- Date: June 1, 2015 5 | -- Author: khubbard 6 | -- Description: A UART that is fixed baud and receive only. This design is a 7 | -- derivative of the autobauding rx+tx mesa_uart.v module. 8 | -- Language: Verilog-2001 9 | -- 10 | -- RXD \START/<..>/STOP 11 | -- 12 | -- Note: baud_rate[15:0] is actual number of clocks in a symbol: 13 | -- Example 10 Mbps with 100 MHz clock, baud_rate = 0x000a;// Div-10 14 | -- 15 | -- Revision History: 16 | -- Ver# When Who What 17 | -- ---- -------- -------- --------------------------------------------------- 18 | -- 0.1 06.01.15 khubbard Creation 19 | -- 0.2 08.18.16 khubbard rx_sr[2:0] fix for metastable sampling issue. 20 | -- ***************************************************************************/ 21 | //`default_nettype none // Strictly enforce all nets to be declared 22 | 23 | module mesa_rx_uart 24 | ( 25 | input wire reset, 26 | input wire clk, 27 | input wire rxd, 28 | output wire [7:0] rx_byte, 29 | output wire rx_rdy, 30 | input wire [15:0] baud_rate 31 | ); // module mesa_rx_uart 32 | 33 | 34 | reg [8:0] rx_byte_sr; 35 | reg [3:0] rx_bit_cnt; 36 | reg sample_now; 37 | reg sample_now_p1; 38 | reg rxd_meta; 39 | wire rxd_sample; 40 | reg [7:0] rxd_sr; 41 | reg rx_byte_jk; 42 | reg rx_byte_jk_p1; 43 | 44 | wire [7:0] rx_byte_loc; 45 | reg [15:0] rx_cnt_16b; 46 | wire [15:0] baud_rate_loc; 47 | reg rx_cnt_16b_p1; 48 | reg rx_cnt_16b_roll; 49 | reg rx_start_b; 50 | reg rx_cnt_en_b; 51 | reg rx_rdy_loc; 52 | reg rxd_fal; 53 | reg rxd_ris; 54 | 55 | 56 | assign baud_rate_loc = baud_rate[15:0]; 57 | assign rx_rdy = rx_rdy_loc; 58 | 59 | 60 | //----------------------------------------------------------------------------- 61 | // Asynchronous sampling of RXD into 4 bit Shift Register 62 | // Note: RXD is immediately inverted to prevent runt '0's from pipeline 63 | // being detected as start bits. FPGA Flops powerup to '0', so inverting fixes. 64 | //----------------------------------------------------------------------------- 65 | always @ ( posedge clk ) begin : proc_din 66 | begin 67 | rxd_meta <= ~ rxd;// Note Inversion to prevent runt post config 68 | rxd_sr[7:0] <= { rxd_sr[6:0], rxd_meta }; 69 | rxd_fal <= 0; 70 | rxd_ris <= 0; 71 | 72 | // if ( rxd_sr[2:0] == 3'b001 ) begin 73 | if ( rxd_sr[2:0] == 3'b011 ) begin 74 | rxd_fal <= 1; 75 | end 76 | // if ( rxd_sr[2:0] == 3'b110 ) begin 77 | if ( rxd_sr[2:0] == 3'b100 ) begin 78 | rxd_ris <= 1; 79 | end 80 | 81 | end 82 | end // proc_din 83 | assign rxd_sample = ~ rxd_sr[2]; 84 | 85 | 86 | //----------------------------------------------------------------------------- 87 | // 16bit Counter used for both rx_start_bit width count and sample count 88 | //----------------------------------------------------------------------------- 89 | always @ ( posedge clk ) begin : proc_cnt 90 | begin 91 | 92 | if ( rx_start_b == 1 ) begin 93 | // rx_cnt_16b <= 16'd0; 94 | rx_cnt_16b <= 16'd2;// This makes the baud_rate input correct 95 | end else if ( rx_cnt_en_b == 1 ) begin 96 | rx_cnt_16b <= rx_cnt_16b + 1; 97 | end 98 | 99 | rx_cnt_16b_p1 <= rx_cnt_16b[15]; 100 | rx_cnt_16b_roll <= rx_cnt_16b_p1 & ~ rx_cnt_16b[15]; 101 | 102 | end 103 | end // proc_cnt 104 | 105 | 106 | //----------------------------------------------------------------------------- 107 | // look for falling edge of rx_start_bit and count 1/2 way into bit and sample 108 | //----------------------------------------------------------------------------- 109 | always @ ( posedge clk ) begin : proc_s2 110 | begin 111 | rx_rdy_loc <= 0; 112 | rx_start_b <= 0; 113 | rx_cnt_en_b <= 0; 114 | rx_byte_jk_p1 <= rx_byte_jk; 115 | sample_now <= 0; 116 | sample_now_p1 <= sample_now; 117 | 118 | if ( rx_byte_jk == 0 ) begin 119 | rx_bit_cnt <= 4'd0; 120 | if ( rxd_fal == 1 ) begin 121 | rx_start_b <= 1; 122 | rx_byte_jk <= 1;// Starting a new Byte 123 | end 124 | end 125 | 126 | // assert sample_now at 1/2 baud into D0 data bit. 127 | if ( rx_byte_jk == 1 ) begin 128 | rx_cnt_en_b <= 1; 129 | if ( rx_bit_cnt == 4'd1 ) begin 130 | // Div-2 baud count to sample middle of eye 131 | if ( rx_cnt_16b[15:0] == { 1'b0, baud_rate_loc[15:1] } ) begin 132 | rx_bit_cnt <= rx_bit_cnt + 1; 133 | rx_start_b <= 1; 134 | sample_now <= 1; 135 | end 136 | end else if ( rx_cnt_16b[15:0] == baud_rate_loc[15:0] ) begin 137 | rx_bit_cnt <= rx_bit_cnt + 1; 138 | rx_start_b <= 1; 139 | sample_now <= 1; 140 | end 141 | end 142 | 143 | if ( sample_now == 1 ) begin 144 | rx_byte_sr[8] <= rxd_sample; 145 | rx_byte_sr[7:0] <= rx_byte_sr[8:1]; 146 | end 147 | 148 | if ( sample_now_p1 == 1 && rx_bit_cnt == 4'd9 ) begin 149 | rx_byte_jk <= 0; 150 | rx_bit_cnt <= 4'd0; 151 | end 152 | 153 | if ( reset == 1 ) begin 154 | rx_byte_jk <= 0; 155 | rx_byte_sr[8:0] <= 9'd0; 156 | end 157 | 158 | // Grab received byte after last bit received 159 | if ( sample_now_p1 == 1 && rx_bit_cnt == 4'd9 ) begin 160 | rx_rdy_loc <= 1; 161 | end 162 | 163 | end 164 | end // proc_s2 165 | assign rx_byte_loc = rx_byte_sr[8:1]; 166 | assign rx_byte = rx_byte_sr[8:1]; 167 | 168 | 169 | endmodule // mesa_rx_uart 170 | -------------------------------------------------------------------------------- /verilog/mesa_tx_uart.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- (C) Copyright 2015 Black Mesa Labs 3 | -- Source file: mesa_tx_uart.v 4 | -- Date: June 1, 2015 5 | -- Author: khubbard 6 | -- Description: TX only 1/2 of UART for transmitting Wo bytes. 7 | -- Language: Verilog-2001 8 | -- 9 | -- RXD \START/<..>/STOP 10 | -- Design Statistics after Packing 11 | -- en_clr_lock = 1; 12 | -- Number of LUTs : 190 / 384 13 | -- Number of DFFs : 110 / 384 14 | -- 15 | -- Revision History: 16 | -- Ver# When Who What 17 | -- ---- -------- -------- --------------------------------------------------- 18 | -- 0.1 06.01.15 khubbard Creation 19 | -- ***************************************************************************/ 20 | //`default_nettype none // Strictly enforce all nets to be declared 21 | 22 | module mesa_tx_uart 23 | ( 24 | input wire reset, 25 | input wire clk, 26 | input wire [7:0] tx_byte, 27 | input wire tx_en, 28 | output reg tx_busy, 29 | output reg txd, 30 | input wire baud_lock, 31 | input wire [15:0] baud_rate 32 | ); // module mesa_tx_uart 33 | 34 | 35 | reg [15:0] tx_cnt_16b; 36 | reg [3:0] tx_bit_cnt; 37 | reg [9:0] tx_sr; 38 | reg txd_loc; 39 | reg tx_shift; 40 | reg tx_now; 41 | reg tx_en_p1; 42 | reg baud_lock_p1; 43 | reg send_lf; 44 | 45 | 46 | //----------------------------------------------------------------------------- 47 | // TX : Load 8bits into 10bit SR and shift out at the RX baud rate 48 | //----------------------------------------------------------------------------- 49 | always @ ( posedge clk ) begin : proc_tx 50 | begin 51 | tx_shift <= 0; 52 | tx_busy <= 0; 53 | txd <= txd_loc; 54 | txd_loc <= tx_sr[0]; 55 | tx_now <= 0; 56 | tx_en_p1 <= tx_en; 57 | baud_lock_p1 <= baud_lock; 58 | send_lf <= baud_lock & ~ baud_lock_p1; 59 | 60 | // Load a new Byte to send 61 | if ( ( tx_en == 1 && tx_en_p1 == 0 ) || ( send_lf == 1 ) ) begin 62 | tx_bit_cnt <= 4'd10; 63 | tx_cnt_16b <= 16'h0000; 64 | tx_busy <= 1; 65 | tx_shift <= 1; 66 | tx_sr[9:0] <= { 1'b1, tx_byte[7:0], 1'b0 }; 67 | if ( send_lf == 1 ) begin 68 | tx_sr[9:0] <= { 1'b1, 8'h0A , 1'b0 };// Used for autobauding next node 69 | end 70 | 71 | // Shift and send the byte until bit_cnt goes to 0 72 | end else if ( tx_bit_cnt != 4'd0 ) begin 73 | tx_cnt_16b <= tx_cnt_16b + 1; 74 | tx_busy <= 1; 75 | if ( tx_now == 1 ) begin 76 | tx_shift <= 1; 77 | tx_bit_cnt <= tx_bit_cnt[3:0] - 1; 78 | tx_cnt_16b <= 16'h0000; 79 | tx_sr[9:0] <= { 1'b1, tx_sr[9:1] }; 80 | end 81 | end else begin 82 | tx_sr <= 10'H3FF; 83 | end 84 | 85 | if ( tx_cnt_16b[15:0] == baud_rate[15:0] ) begin 86 | tx_now <= 1; 87 | end 88 | 89 | if ( reset == 1 ) begin 90 | tx_bit_cnt <= 4'd0; 91 | end 92 | 93 | end 94 | end // proc_tx 95 | 96 | 97 | endmodule // mesa_tx_uart 98 | -------------------------------------------------------------------------------- /verilog/mesa_uart.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- (C) Copyright 2015 Black Mesa Labs 3 | -- Source file: mesa_uart.v 4 | -- Date: June 1, 2015 5 | -- Author: khubbard 6 | -- Description: A UART that autobauds to first "\n" 0x0A character. 7 | -- Language: Verilog-2001 8 | -- 9 | -- RXD \START/<..>/STOP 10 | -- Design Statistics after Packing 11 | -- en_clr_lock = 1; 12 | -- Number of LUTs : 190 / 384 13 | -- Number of DFFs : 110 / 384 14 | -- 15 | -- Revision History: 16 | -- Ver# When Who What 17 | -- ---- -------- -------- --------------------------------------------------- 18 | -- 0.1 06.01.15 khubbard Creation 19 | -- 0.2 08.18.16 khubbard rx_sr[2:0] fix for metastable sampling issue. 20 | -- ***************************************************************************/ 21 | //`default_nettype none // Strictly enforce all nets to be declared 22 | 23 | module mesa_uart 24 | ( 25 | input wire reset, 26 | input wire clk, 27 | input wire clr_baudlock, 28 | input wire en_autobaud, 29 | input wire rxd, 30 | output wire flush, 31 | output reg txd, 32 | output reg [7:0] dbg, 33 | output wire [7:0] rx_byte, 34 | output reg rx_rdy, 35 | input wire [7:0] tx_byte, 36 | input wire tx_en, 37 | output reg tx_busy, 38 | output reg tx_idle, 39 | output wire rx_idle, 40 | output wire [15:0] baud_rate, 41 | output wire baud_lock 42 | ); // module mesa_uart 43 | 44 | 45 | reg [8:0] rx_byte_sr; 46 | reg [3:0] rx_bit_cnt; 47 | reg [3:0] tx_bit_cnt; 48 | reg sample_now; 49 | reg sample_now_p1; 50 | reg rxd_meta; 51 | reg rxd_loc; 52 | wire rxd_sample; 53 | reg [7:0] rxd_sr; 54 | reg clr_bit_lock; 55 | reg dbg_sample_togl; 56 | reg dbg_sample_togl_p1; 57 | reg dbg_byte_togl; 58 | reg clr_jk; 59 | reg bad_jk; 60 | reg bit_lock_jk; 61 | reg bit_lock_jk_p1; 62 | reg baud_lock_jk; 63 | reg rx_byte_jk; 64 | reg rx_byte_jk_p1; 65 | 66 | wire [7:0] rx_byte_loc; 67 | reg [15:0] rx_cnt_16b; 68 | reg [15:0] tx_cnt_16b; 69 | reg [15:0] baud_rate_loc; 70 | reg rx_cnt_16b_p1; 71 | reg rx_cnt_16b_roll; 72 | reg rx_start_a; 73 | reg rx_start_b; 74 | reg rx_cnt_en_a_jk; 75 | reg rx_cnt_en_b; 76 | reg rx_rdy_loc; 77 | reg rx_rdy_pre; 78 | wire en_loopback; 79 | wire en_fast_autobaud; 80 | reg [7:0] tx_byte_loc; 81 | reg tx_en_loc; 82 | reg [9:0] tx_sr; 83 | reg txd_loc; 84 | reg rxd_fal; 85 | reg rxd_ris; 86 | reg [7:0] rxd_fal_sr; 87 | reg tx_shift; 88 | reg tx_now; 89 | reg rx_ascii_cr; 90 | reg rx_bad_symbol; 91 | reg [7:0] dbg_loc; 92 | reg [7:0] dbg_loc_p1; 93 | reg [3:0] dbg_cnt; 94 | reg sample_first; 95 | 96 | 97 | // Send RXD to TXD to test circuit 98 | assign en_loopback = 0; 99 | assign en_fast_autobaud = 0; 100 | assign rx_idle = 0; 101 | 102 | // When baud_lock asserts, send "\n" to downstream nodes for detection 103 | assign baud_rate = baud_rate_loc[15:0]; 104 | assign baud_lock = baud_lock_jk; 105 | 106 | //----------------------------------------------------------------------------- 107 | // Output some debug signals for Saleae. Pulse extend short events 108 | //----------------------------------------------------------------------------- 109 | always @ ( posedge clk ) begin : proc_dbg 110 | begin 111 | // dbg_loc[0] <= ~ rxd_meta; 112 | dbg_loc[0] <= rxd_sample; 113 | dbg_loc[1] <= txd_loc; 114 | dbg_loc[2] <= bit_lock_jk; 115 | dbg_loc[3] <= baud_lock_jk; 116 | // dbg_loc[4] <= sample_now; 117 | dbg_loc[4] <= reset; 118 | // dbg_loc[5] <= rx_rdy_loc; 119 | dbg_loc[5] <= clr_jk; 120 | dbg_loc[6] <= dbg_sample_togl; 121 | dbg_loc[7] <= dbg_byte_togl; 122 | // dbg_loc[7] <= bad_jk; 123 | // dbg_loc[7] <= rx_ascii_cr; 124 | dbg_loc_p1 <= dbg_loc[7:0]; 125 | 126 | // Extend transitions for Saleae 127 | if ( dbg_cnt != 4'hF ) begin 128 | dbg_cnt <= dbg_cnt + 1; 129 | end 130 | 131 | if ( dbg_loc[7:4] != dbg_loc_p1[7:4] && dbg_cnt == 4'hF ) begin 132 | dbg <= dbg_loc[7:0]; 133 | dbg_cnt <= 4'h0; 134 | end 135 | if ( reset == 1 ) begin 136 | dbg_cnt <= 4'h0; 137 | end 138 | 139 | dbg[0] <= dbg_loc[0]; 140 | dbg[1] <= dbg_loc[1]; 141 | dbg[2] <= dbg_loc[2]; 142 | dbg[3] <= dbg_loc[3]; 143 | 144 | end 145 | end // proc_din 146 | 147 | 148 | //----------------------------------------------------------------------------- 149 | // Asynchronous sampling of RXD into 4 bit Shift Register 150 | // Note: RXD is immediately inverted to prevent runt '0's from pipeline 151 | // being detected as start bits. FPGA Flops powerup to '0', so inverting fixes. 152 | //----------------------------------------------------------------------------- 153 | always @ ( posedge clk ) begin : proc_din 154 | begin 155 | rxd_meta <= ~ rxd;// Note Inversion to prevent runt post config 156 | rxd_loc <= rxd_meta; 157 | // rxd_sr[7:0] <= { rxd_sr[6:0], rxd_meta }; 158 | rxd_sr[7:0] <= { rxd_sr[6:0], rxd_loc }; 159 | rxd_fal <= 0; 160 | rxd_ris <= 0; 161 | 162 | // if ( rxd_sr[3:0] == 4'b0001 ) begin 163 | // if ( rxd_sr[2:0] == 3'b001 ) begin 164 | // if ( rxd_sr[2:0] == 3'b011 ) begin 165 | if ( rxd_sr[7:6] == 2'b00 && rxd_sr[2:0] == 3'b011 ) begin 166 | rxd_fal <= 1; 167 | end 168 | // if ( rxd_sr[3:0] == 4'b1110 ) begin 169 | // if ( rxd_sr[2:0] == 3'b110 ) begin 170 | // if ( rxd_sr[2:0] == 3'b100 ) begin 171 | if ( rxd_sr[7:6] == 2'b11 && rxd_sr[2:0] == 3'b100 ) begin 172 | rxd_ris <= 1; 173 | end 174 | 175 | end 176 | end // proc_din 177 | assign rxd_sample = ~ rxd_sr[2]; 178 | 179 | 180 | //----------------------------------------------------------------------------- 181 | // 16bit Counter used for both rx_start_bit width count and sample count 182 | //----------------------------------------------------------------------------- 183 | always @ ( posedge clk ) begin : proc_cnt 184 | begin 185 | 186 | if ( rx_start_a == 1 || rx_start_b == 1 ) begin 187 | rx_cnt_16b <= 16'd0; 188 | end else if ( rx_cnt_en_a_jk == 1 || 189 | rx_cnt_en_b == 1 ) begin 190 | rx_cnt_16b <= rx_cnt_16b + 1; 191 | end 192 | 193 | if ( en_fast_autobaud == 1 ) begin 194 | rx_cnt_16b[15:12] <= 4'd0; 195 | rx_cnt_16b_p1 <= rx_cnt_16b[11]; 196 | rx_cnt_16b_roll <= rx_cnt_16b_p1 & ~ rx_cnt_16b[11]; 197 | end else begin 198 | rx_cnt_16b_p1 <= rx_cnt_16b[15]; 199 | rx_cnt_16b_roll <= rx_cnt_16b_p1 & ~ rx_cnt_16b[15]; 200 | end 201 | 202 | end 203 | end // proc_cnt 204 | 205 | 206 | 207 | //----------------------------------------------------------------------------- 208 | // Autobaud off "\n" character. Tricky, as both start bit at D0 are 0. 209 | // When there is no bit_lock, look for falling edge of RXD and count width of 210 | // StartBit and the 1st '0' of 0xA "\n" "01010000". 211 | // bit_lock remains on unless we don't get baud_lock 212 | // bit_lock == Think we know where to sample each symbol. 213 | // baud_lock == We sampled 8 symbols and got 0x0A or "\n" 214 | //----------------------------------------------------------------------------- 215 | always @ ( posedge clk ) begin : proc_s1 216 | begin 217 | sample_first <= 0; 218 | rx_start_a <= 0; 219 | bit_lock_jk_p1 <= bit_lock_jk; 220 | if ( bit_lock_jk == 0 && baud_lock_jk == 0 ) begin 221 | if ( rxd_fal == 1 ) begin 222 | rx_start_a <= 1; 223 | rx_cnt_en_a_jk <= 1; 224 | end else if ( rxd_ris == 1 && rx_cnt_en_a_jk == 1 ) begin 225 | // baud_rate_loc <= { 1'b0, rx_cnt_16b[15:1] };// Div2 Shift 226 | baud_rate_loc <= { 1'b0, rx_cnt_16b[15:1] } - 16'd1;// Div2 Shift 227 | bit_lock_jk <= 1; 228 | rx_start_a <= 1; 229 | rx_cnt_en_a_jk <= 0; 230 | sample_first <= 1; 231 | end 232 | end else begin 233 | rx_cnt_en_a_jk <= 0; 234 | end 235 | 236 | if ( clr_bit_lock == 1 ) begin 237 | bit_lock_jk <= 0; 238 | end 239 | 240 | if ( en_fast_autobaud == 1 ) begin 241 | baud_rate_loc[15:12] <= 4'd0; 242 | end 243 | 244 | if ( en_autobaud == 0 ) begin 245 | baud_rate_loc <= 16'd43; 246 | bit_lock_jk <= 1; 247 | end 248 | 249 | end 250 | end // proc_s1 251 | assign flush = rx_ascii_cr; 252 | 253 | 254 | //----------------------------------------------------------------------------- 255 | // Decode the character bytes 256 | //----------------------------------------------------------------------------- 257 | always @ ( posedge clk ) begin : proc_s3 258 | begin 259 | rx_ascii_cr <= 0; 260 | rx_bad_symbol <= 0; 261 | clr_bit_lock <= 0; 262 | rx_rdy_loc <= 0; 263 | rx_rdy <= rx_rdy_loc & baud_lock_jk; 264 | 265 | // Assert baud_lock if 1st char is "\n" else clear and start over. 266 | if ( sample_now_p1 == 1 && rx_bit_cnt == 4'd9 ) begin 267 | if ( rx_byte_loc[7:0] == 8'h0a ) begin 268 | baud_lock_jk <= 1; 269 | rx_ascii_cr <= 1; 270 | clr_jk <= 0; 271 | bad_jk <= 0; 272 | end else if ( baud_lock_jk == 0 ) begin 273 | clr_bit_lock <= 1; 274 | end 275 | // Only expect ASCII 0x20 - 0x7F, detect 0x80+ as bad and clear baud lock 276 | if ( rx_byte_loc[7] == 1 ) begin 277 | rx_bad_symbol <= 1; 278 | end 279 | // Only expect ASCII 0x20 - 0x7F, detect under 0x20 and clear baud lock 280 | if ( rx_byte_loc != 8'h0A && rx_byte_loc < 8'h20 ) begin 281 | rx_bad_symbol <= 1; 282 | end 283 | end 284 | 285 | // Grab received byte after last bit received 286 | if ( sample_now_p1 == 1 && rx_bit_cnt == 4'd9 ) begin 287 | rx_rdy_loc <= 1; 288 | end 289 | 290 | if ( reset == 1 || rx_bad_symbol == 1 || clr_baudlock == 1 ) begin 291 | baud_lock_jk <= 0; 292 | clr_bit_lock <= 1; 293 | rx_rdy_loc <= 0; 294 | end 295 | 296 | // if ( dbg_sample_togl != dbg_sample_togl_p1 ) begin 297 | // clr_jk <= 0; 298 | // bad_jk <= 0; 299 | // end 300 | if ( rx_bad_symbol == 1 ) begin 301 | bad_jk <= 1; 302 | end 303 | if ( clr_baudlock == 1 ) begin 304 | clr_jk <= 1; 305 | end 306 | if ( reset == 1 ) begin 307 | clr_jk <= 0; 308 | bad_jk <= 0; 309 | end 310 | 311 | 312 | end 313 | end // proc_s3 314 | 315 | assign rx_byte_loc = rx_byte_sr[8:1]; 316 | assign rx_byte = rx_byte_sr[8:1]; 317 | 318 | 319 | //----------------------------------------------------------------------------- 320 | // look for falling edge of rx_start_bit and count 1/2 way into bit and sample 321 | //----------------------------------------------------------------------------- 322 | always @ ( posedge clk ) begin : proc_s2 323 | begin 324 | tx_en_loc <= 0; 325 | sample_now <= 0; 326 | rx_start_b <= 0; 327 | rx_cnt_en_b <= 0; 328 | rx_byte_jk_p1 <= rx_byte_jk; 329 | sample_now_p1 <= sample_now; 330 | dbg_sample_togl_p1 <= dbg_sample_togl; 331 | 332 | if ( rx_byte_jk == 0 ) begin 333 | rx_bit_cnt <= 4'd0; 334 | if ( rxd_fal == 1 ) begin 335 | rx_start_b <= 1; 336 | rx_byte_jk <= 1;// Starting a new Byte 337 | dbg_byte_togl <= ~dbg_byte_togl; 338 | end 339 | end 340 | 341 | // When to start sample_now is tricky as for bit_lock, it is 1/2 baud into 342 | // the D1 data bit of \n, after lock, it is 1/2 baud into D0 data bit. 343 | // cnt=0 is StartBit, cnt=1 is D0, cnt=2 is D1 344 | if ( bit_lock_jk == 1 && rx_byte_jk == 1 ) begin 345 | rx_cnt_en_b <= 1; 346 | if ( 347 | ( baud_lock_jk == 0 && rx_bit_cnt == 4'd2 ) || 348 | ( baud_lock_jk == 1 && rx_bit_cnt == 4'd1 ) ) begin 349 | // Div-2 baud count to sample middle of eye 350 | if ( rx_cnt_16b[15:0] == { 1'b0, baud_rate_loc[15:1] } ) begin 351 | rx_bit_cnt <= rx_bit_cnt + 1; 352 | rx_start_b <= 1; 353 | sample_now <= 1; 354 | end 355 | end else if ( rx_cnt_16b[15:0] == baud_rate_loc[15:0] ) begin 356 | rx_bit_cnt <= rx_bit_cnt + 1; 357 | rx_start_b <= 1; 358 | sample_now <= 1; 359 | end 360 | end 361 | 362 | // Assume "\n" and stuff the 1st 0 since it already flew by 363 | if ( sample_first == 1 ) begin 364 | rx_bit_cnt <= 4'd2; 365 | rx_byte_sr[8] <= 0; 366 | rx_byte_sr[7:0] <= rx_byte_sr[8:1]; 367 | end 368 | 369 | if ( sample_now == 1 ) begin 370 | rx_byte_sr[8] <= rxd_sample; 371 | rx_byte_sr[7:0] <= rx_byte_sr[8:1]; 372 | dbg_sample_togl <= ~dbg_sample_togl; 373 | end 374 | 375 | if ( sample_now_p1 == 1 && rx_bit_cnt == 4'd9 ) begin 376 | rx_byte_jk <= 0; 377 | rx_bit_cnt <= 4'd0; 378 | end 379 | 380 | if ( rx_rdy_loc == 1 && baud_lock_jk == 1 && en_loopback == 1 ) begin 381 | tx_byte_loc <= rx_byte_loc[7:0]; 382 | tx_en_loc <= 1; 383 | end else if ( tx_en == 1 ) begin 384 | tx_byte_loc <= tx_byte[7:0]; 385 | tx_en_loc <= 1; 386 | end 387 | 388 | if ( reset == 1 ) begin 389 | rx_byte_jk <= 0; 390 | rx_byte_sr[8:0] <= 9'd0; 391 | dbg_sample_togl <= 0; 392 | dbg_byte_togl <= 0; 393 | end 394 | 395 | end 396 | end // proc_s2 397 | 398 | 399 | //----------------------------------------------------------------------------- 400 | // TX : Load 8bits into 10bit SR and shift out at the RX baud rate 401 | //----------------------------------------------------------------------------- 402 | always @ ( posedge clk ) begin : proc_tx 403 | begin 404 | tx_shift <= 0; 405 | tx_busy <= 0; 406 | txd <= txd_loc; 407 | txd_loc <= tx_sr[0]; 408 | tx_now <= 0; 409 | 410 | // Load a new Byte to send 411 | if ( tx_en_loc == 1 ) begin 412 | tx_bit_cnt <= 4'd10; 413 | tx_cnt_16b <= 16'h0000; 414 | tx_idle <= 0; 415 | tx_busy <= 1; 416 | tx_shift <= 1; 417 | tx_sr[9:0] <= { 1'b1, tx_byte_loc[7:0], 1'b0 }; 418 | 419 | // Shift and send the byte until bit_cnt goes to 0 420 | end else if ( tx_bit_cnt != 4'd0 ) begin 421 | tx_cnt_16b <= tx_cnt_16b + 1; 422 | tx_busy <= 1; 423 | tx_idle <= 0; 424 | if ( tx_now == 1 ) begin 425 | tx_shift <= 1; 426 | tx_bit_cnt <= tx_bit_cnt[3:0] - 1; 427 | tx_cnt_16b <= 16'h0000; 428 | tx_sr[9:0] <= { 1'b1, tx_sr[9:1] }; 429 | end 430 | end else begin 431 | tx_sr <= 10'H3FF; 432 | if ( tx_now == 1 ) begin 433 | tx_idle <= 1; 434 | end else begin 435 | tx_cnt_16b <= tx_cnt_16b + 1; 436 | end 437 | end 438 | 439 | if ( tx_cnt_16b[15:0] == baud_rate_loc[15:0] ) begin 440 | tx_now <= 1; 441 | end 442 | 443 | if ( reset == 1 ) begin 444 | tx_bit_cnt <= 4'd0; 445 | tx_idle <= 1; 446 | end 447 | 448 | if ( en_fast_autobaud == 1 ) begin 449 | tx_cnt_16b[15:12] <= 4'd0; 450 | end 451 | 452 | end 453 | end // proc_tx 454 | 455 | 456 | endmodule // mesa_uart 457 | -------------------------------------------------------------------------------- /verilog/mesa_uart_phy.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- Source file: mesa_uart_phy.v 3 | -- Date: October 2015 4 | -- Author: khubbard 5 | -- Description: Interface the Byte binary stream of the internal Mesa-Bus with 6 | -- the physical layer. For this case, using UARTs. 7 | -- This instantiates the UARTs and takes care of the binary to 8 | -- ASCII conversions for all directions. 9 | -- Language: Verilog-2001 and VHDL-1993 10 | -- Simulation: Mentor-Modelsim 11 | -- Synthesis: Lattice 12 | -- 13 | -- Revision History: 14 | -- Ver# When Who What 15 | -- ---- -------- -------- --------------------------------------------------- 16 | -- 0.1 10.04.15 khubbard Creation 17 | -- ***************************************************************************/ 18 | `default_nettype none // Strictly enforce all nets to be declared 19 | 20 | module mesa_uart_phy 21 | ( 22 | input wire clk, 23 | input wire reset, 24 | input wire clr_baudlock, 25 | output wire user_wo, 26 | 27 | input wire mesa_wi, 28 | output wire mesa_wo, 29 | input wire mesa_ri, 30 | output wire mesa_ro, 31 | output wire [15:0] uart_baud, 32 | output wire dbg_rx, 33 | output wire [7:0] dbg_out, 34 | 35 | output wire mesa_wi_flush, 36 | output wire mesa_wi_nib_en, 37 | output wire [3:0] mesa_wi_nib_d, 38 | input wire mesa_wo_byte_en, 39 | input wire [7:0] mesa_wo_byte_d, 40 | output wire mesa_wo_busy, 41 | input wire mesa_ro_byte_en, 42 | input wire [7:0] mesa_ro_byte_d, 43 | output wire mesa_ro_busy, 44 | input wire mesa_ro_done 45 | );// module mesa_uart_phy 46 | 47 | 48 | wire wi_char_en; 49 | wire [7:0] wi_char_d; 50 | wire ro_char_en; 51 | wire [7:0] ro_char_d; 52 | wire ro_uart_busy; 53 | wire ro_uart_idle; 54 | wire wo_char_en; 55 | wire [7:0] wo_char_d; 56 | wire wo_uart_busy; 57 | wire baud_lock; 58 | wire [15:0] baud_rate; 59 | 60 | 61 | assign uart_baud = baud_rate[15:0]; 62 | assign dbg_rx = wi_char_en; 63 | 64 | 65 | //----------------------------------------------------------------------------- 66 | // UART to convert serial streams to/from ASCII bytes for Wi and Ro. 67 | //----------------------------------------------------------------------------- 68 | mesa_uart u_mesa_uart 69 | ( 70 | .clk ( clk ), 71 | .reset ( reset ), 72 | .clr_baudlock ( clr_baudlock ), 73 | .en_autobaud ( 1'b1 ), 74 | .rxd ( mesa_wi ), 75 | .txd ( mesa_ro ), 76 | .flush ( mesa_wi_flush ), 77 | .dbg ( dbg_out[7:0] ), 78 | .rx_rdy ( wi_char_en ), 79 | .rx_byte ( wi_char_d[7:0] ), 80 | 81 | .tx_en ( ro_char_en ), 82 | .tx_byte ( ro_char_d[7:0] ), 83 | .tx_busy ( ro_uart_busy ), 84 | .tx_idle ( ro_uart_idle ), 85 | .rx_idle ( ), 86 | .baud_rate ( baud_rate[15:0] ), 87 | .baud_lock ( baud_lock ) 88 | ); // module mesa_uart 89 | 90 | 91 | //----------------------------------------------------------------------------- 92 | // Debug Only TX Only UART. 93 | //----------------------------------------------------------------------------- 94 | mesa_tx_uart u_dbg_mesa_tx_uart 95 | ( 96 | .clk ( clk ), 97 | .reset ( reset ), 98 | .txd ( user_wo ), 99 | .tx_en ( wi_char_en ), 100 | .tx_byte ( wi_char_d[7:0] ), 101 | .tx_busy ( ), 102 | .baud_rate ( baud_rate[15:0] ), 103 | .baud_lock ( baud_lock ) 104 | ); // module mesa_uart 105 | 106 | 107 | //----------------------------------------------------------------------------- 108 | // TX Only UART. Sends Wo data. When 1st UART goes to lock, sends "\n" out, 109 | // otherwise just echos the binary stream from decode block ( Wi->Wo ). 110 | //----------------------------------------------------------------------------- 111 | mesa_tx_uart u_mesa_tx_uart 112 | ( 113 | .clk ( clk ), 114 | .reset ( reset ), 115 | .txd ( mesa_wo ), 116 | .tx_en ( wo_char_en ), 117 | .tx_byte ( wo_char_d[7:0] ), 118 | .tx_busy ( wo_uart_busy ), 119 | .baud_rate ( baud_rate[15:0] ), 120 | .baud_lock ( baud_lock ) 121 | ); // module mesa_uart 122 | 123 | 124 | //----------------------------------------------------------------------------- 125 | // Convert Wi ASCII to Binary Nibbles. Decoder figures out nibble/byte phase 126 | //----------------------------------------------------------------------------- 127 | mesa_ascii2nibble u_mesa_ascii2nibble 128 | ( 129 | .clk ( clk ), 130 | .rx_char_en ( wi_char_en ), 131 | .rx_char_d ( wi_char_d[7:0] ), 132 | .rx_nib_en ( mesa_wi_nib_en ), 133 | .rx_nib_d ( mesa_wi_nib_d[3:0] ) 134 | );// module mesa_ascii2nibble 135 | 136 | 137 | //----------------------------------------------------------------------------- 138 | // Convert Ro Binary Bytes to ASCII 139 | //----------------------------------------------------------------------------- 140 | mesa_byte2ascii u0_mesa_byte2ascii 141 | ( 142 | .clk ( clk ), 143 | .reset ( reset ), 144 | .no_handshake ( 1'b0 ), 145 | .tx_byte_en ( mesa_ro_byte_en ), 146 | .tx_byte_d ( mesa_ro_byte_d[7:0] ), 147 | .tx_byte_busy ( mesa_ro_busy ), 148 | .tx_byte_done ( mesa_ro_done ), 149 | .tx_char_en ( ro_char_en ), 150 | .tx_char_d ( ro_char_d[7:0] ), 151 | .tx_char_busy ( ro_uart_busy ), 152 | .tx_char_idle ( ro_uart_idle ) 153 | );// module mesa_byte2ascii 154 | 155 | 156 | //----------------------------------------------------------------------------- 157 | // Convert Wo Binary Bytes to ASCII 158 | //----------------------------------------------------------------------------- 159 | mesa_byte2ascii u1_mesa_byte2ascii 160 | ( 161 | .clk ( clk ), 162 | .reset ( reset ), 163 | .no_handshake ( 1'b0 ), 164 | .tx_byte_en ( mesa_wo_byte_en ), 165 | .tx_byte_d ( mesa_wo_byte_d[7:0] ), 166 | .tx_byte_busy ( mesa_wo_busy ), 167 | .tx_byte_done ( 1'b0 ), 168 | .tx_char_en ( wo_char_en ), 169 | .tx_char_d ( wo_char_d[7:0] ), 170 | .tx_char_busy ( wo_uart_busy ), 171 | .tx_char_idle ( ~wo_uart_busy ) // TBD Check this connection 172 | );// module mesa_byte2ascii 173 | 174 | 175 | endmodule // mesa_uart_phy.v 176 | -------------------------------------------------------------------------------- /verilog/spi_byte2bit.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- Source file: spi_byte2bit.v 3 | -- Date: June 1,2014 4 | -- Author: khubbard 5 | -- Description: Simple interface to SPI that xfers Bytes to Bits. 6 | -- Supports read stalling of MISO stream. 7 | -- Language: Verilog-2001 8 | -- Simulation: Mentor-Modelsim 9 | -- Synthesis: Xilinst-XST 10 | -- License: This project is licensed with the CERN Open Hardware Licence 11 | -- v1.2. You may redistribute and modify this project under the 12 | -- terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl). 13 | -- This project is distributed WITHOUT ANY EXPRESS OR IMPLIED 14 | -- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY 15 | -- AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL 16 | -- v.1.2 for applicable Conditions. 17 | -- 18 | -- spi_byte2bit 19 | -- ---------- 20 | -- clk -------->| | 21 | -- xfer_start ------->| | 22 | -- xfer_tx_bytes[7:0]->| | 23 | -- xfer_rx_bytes[7:0]->| | 24 | -- mosi_byte_d[7:0]--->| |--> miso_byte_d[7:0] 25 | -- mosi_byte_en ------>| |--> miso_byte_rdy 26 | -- mosi_byte_req <-----| | 27 | -- | | 28 | -- spi_miso --->| |--> spi_mosi 29 | -- | |--> spi_sck 30 | -- | |--> spi_cs_l 31 | -- ---------- 32 | -- 33 | -- spi_sck _/\/\/\/\/\/\/\/\____/\/\/\/\/\/\/\/\/\/\/\/\/ 34 | -- spi_cs_l \_________________________/ 35 | -- spi_mosi -----------< B0 >----< B1 >------------------ 36 | -- spi_miso --------------------------< B2 >< B3>------ 37 | -- 38 | -- xfer_start_/ \_______________________________________ 39 | -- xfer_stall___________________________________/ \_____ 40 | -- tx_bytes -< 2 >--------------------------------------- 41 | -- rx_bytes -< 2 >--------------------------------------- 42 | -- 43 | -- mosi_byte_en __/ \__..._/ \_____ 44 | -- mosi_byte_d[7:0] ----...------ 45 | -- mosi_byte_req ______/ \_______ 46 | -- 47 | -- miso_byte_rdy ________________________/ \___/ \__ 48 | -- miso_byte_d[7:0] ----------------------------- 49 | -- 50 | -- 51 | -- Note: Starving the MOSI stream is allowed. The block will gate the SPI clock 52 | -- and wait until the MOSI byte arrives. 53 | -- 54 | -- Note: Stalling the MISO stream is allowed. Asserting xfer_stall will gate 55 | -- the entire block, allowing for the MISO stream to be stalled. 56 | -- 57 | -- Revision History: 58 | -- Ver# When Who What 59 | -- ---- -------- -------- -------------------------------------------------- 60 | -- 0.1 06.01.14 khubbard Creation 61 | -- 0.1 06.25.14 khubbard Removed mosi_starved logic. Not worth complication 62 | -- 0.2 01.29.16 khubbard Fixed reset issue when ck_div is 0x00 at reset. 63 | -- ***************************************************************************/ 64 | //`default_nettype none // Strictly enforce all nets to be declared 65 | 66 | module spi_byte2bit 67 | ( 68 | input wire reset, 69 | input wire clk, 70 | input wire [7:0] ck_divisor, 71 | input wire [3:0] spi_ctrl, 72 | 73 | output reg spi_sck, 74 | output wire spi_cs_l, 75 | output reg spi_mosi, 76 | input wire spi_miso, 77 | output reg spi_is_idle, 78 | 79 | input wire xfer_start, 80 | input wire xfer_stall, 81 | input wire [11:0] xfer_tx_bytes, 82 | input wire [11:0] xfer_rx_bytes, 83 | 84 | input wire [7:0] mosi_byte_d, 85 | input wire mosi_byte_en, 86 | output wire mosi_byte_req, 87 | output reg mosi_err, 88 | 89 | output reg [7:0] miso_byte_d, 90 | output reg miso_byte_rdy 91 | ); 92 | 93 | reg [7:0] ck_cnt; 94 | wire [7:0] ck_div; 95 | reg ck_loc; 96 | reg ck_off_pre; 97 | reg ck_off; 98 | reg ck_en_fal; 99 | reg ck_en_ris; 100 | reg spi_cs_pre; 101 | reg spi_cs_l_loc; 102 | reg mosi_load; 103 | reg mosi_loaded; 104 | reg [7:0] mosi_sr; 105 | wire [7:0] mosi_sr_loc; 106 | reg [7:0] mosi_byte_queue; 107 | reg mosi_queued_jk; 108 | reg mosi_refused; 109 | reg mosi_byte_req_loc; 110 | reg mosi_byte_en_p1; 111 | reg miso_loc; 112 | reg [7:0] miso_sr; 113 | reg [11:0] xfer_cnt; 114 | reg xfer_tx_jk; 115 | reg xfer_tx_jk_p1; 116 | reg xfer_rx_jk; 117 | reg [4:0] xfer_rx_jk_sr; 118 | reg xfer_start_jk; 119 | reg [11:0] xfer_length; 120 | reg [11:0] xfer_rx_length; 121 | wire [8:0] xfer_byte; 122 | wire [2:0] xfer_bit; 123 | reg [2:0] xfer_bit_p1; 124 | reg [2:0] xfer_bit_p2; 125 | reg [2:0] xfer_bit_p3; 126 | reg [2:0] xfer_bit_p4; 127 | 128 | //assign ck_div = 8'd10; 129 | assign ck_div = ck_divisor[7:0];// Num of clocks in 1/2 spi clock period 130 | 131 | 132 | //----------------------------------------------------------------------------- 133 | // Generate spi_ck. Counts 1/2 periods and toggles a bit. 134 | // ck _/ \_/ \_/ \_/ \_/ \_/ \_/ 135 | // cnt 1 2 1 2 1 2 136 | // ck_loc _/ \_______/ \_ 137 | // ck_en_ris _/ \___________/ \_____ 138 | // ck_en_fal _________/ \___________/ 139 | //----------------------------------------------------------------------------- 140 | always @ ( posedge clk ) begin : proc_spi_ck 141 | begin 142 | if ( xfer_stall == 0 ) begin 143 | ck_en_fal <= 0; 144 | ck_en_ris <= 0; 145 | // Clock Divider 146 | // if ( ck_cnt != 8'hFF ) begin 147 | if ( 1 == 1 ) begin 148 | ck_cnt <= ck_cnt + 1; 149 | if ( ck_cnt == ck_div ) begin 150 | ck_loc <= ~ ck_loc; 151 | ck_cnt <= 8'h1; 152 | if ( ck_loc == 1 ) begin 153 | ck_en_fal <= 1; 154 | end else begin 155 | ck_en_ris <= 1; 156 | end 157 | end 158 | end 159 | // end else begin 160 | // ck_cnt <= ck_cnt[7:0]; 161 | // ck_loc <= 0; 162 | // end 163 | 164 | if ( reset == 1 ) begin 165 | ck_cnt <= 8'd1; 166 | ck_loc <= 0; 167 | end 168 | end 169 | end 170 | end // proc_spi_ck 171 | 172 | 173 | //----------------------------------------------------------------------------- 174 | // Shift in the MISO data 175 | //----------------------------------------------------------------------------- 176 | always @ ( posedge clk ) begin : proc_miso_sr 177 | begin 178 | if ( xfer_stall == 0 ) begin 179 | // miso_byte_d <= 8'd0; 180 | miso_byte_rdy <= 0; 181 | // if ( ck_en_fal == 1 ) begin 182 | if ( ck_en_ris == 1 ) begin 183 | xfer_bit_p1 <= xfer_bit[2:0]; 184 | xfer_bit_p2 <= xfer_bit_p1[2:0]; 185 | xfer_bit_p3 <= xfer_bit_p2[2:0]; 186 | xfer_bit_p4 <= xfer_bit_p3[2:0]; 187 | if ( xfer_rx_jk == 1 || xfer_rx_jk_sr != 5'd0 ) begin 188 | miso_loc <= spi_miso; 189 | miso_sr[0] <= miso_loc; 190 | miso_sr[7:1] <= miso_sr[6:0]; 191 | if ( xfer_bit_p4 == 3'd0 && xfer_rx_jk_sr[4] == 1 ) begin 192 | miso_byte_d <= miso_sr[7:0]; 193 | miso_byte_rdy <= 1; 194 | end 195 | end 196 | end 197 | end 198 | if ( reset == 1 ) begin 199 | miso_byte_rdy <= 0; 200 | xfer_bit_p1 <= 3'd0; 201 | xfer_bit_p2 <= 3'd0; 202 | xfer_bit_p3 <= 3'd0; 203 | xfer_bit_p4 <= 3'd0; 204 | end 205 | end 206 | end // proc_miso_sr 207 | 208 | 209 | //----------------------------------------------------------------------------- 210 | // On rising edge of xfer_start_jk, load the number of bytes * 8bits into a 211 | // bit counter and start the counter. Count down to 0 then turn off xfer_tx_jk. 212 | // xfer_start __/ \_________________________/ \___ 213 | // tx_bytes --<2>-------------------------<2>--- 214 | // rx_bytes --<4>-------------------------<4>--- 215 | // mosi -------<0><1>----------------------- 216 | // miso -------------<0><1><2><3>----------- 217 | // xfer_tx_jk _______/ \______________________ 218 | // xfer_rx_jk _____________/ \__________ 219 | //----------------------------------------------------------------------------- 220 | always @ ( posedge clk ) begin : proc_xfer_req 221 | begin 222 | if ( xfer_stall == 0 ) begin 223 | if ( xfer_start == 1 ) begin 224 | xfer_length <= xfer_tx_bytes[11:0]; 225 | xfer_rx_length <= xfer_rx_bytes[11:0]; 226 | end 227 | 228 | if ( ck_en_fal == 1 ) begin 229 | mosi_err <= 0; 230 | mosi_load <= 0; 231 | xfer_tx_jk_p1 <= xfer_tx_jk; 232 | xfer_rx_jk_sr[0] <= xfer_rx_jk; 233 | xfer_rx_jk_sr[4:1] <= xfer_rx_jk_sr[3:0]; 234 | if ( xfer_start_jk != 0 ) begin 235 | xfer_cnt <= { xfer_length[8:0] , 3'b000 }; 236 | xfer_tx_jk <= 1; 237 | end else if ( xfer_cnt != 12'd0 ) begin 238 | if ( xfer_tx_jk == 1 ) begin 239 | if ( xfer_bit == 2'd0 ) begin 240 | if ( mosi_queued_jk == 1 ) begin 241 | mosi_load <= 1; // Time for a new Byte 242 | end else begin 243 | mosi_err <= 1; // Nothing to send. 244 | end 245 | end 246 | xfer_cnt <= xfer_cnt - 1; 247 | if ( xfer_cnt == 12'd1 ) begin 248 | xfer_tx_jk <= 0; 249 | if ( xfer_rx_length[8:0] != 9'd0 ) begin 250 | xfer_rx_jk <= 1; 251 | xfer_cnt <= { xfer_rx_length[8:0] , 3'b000 }; 252 | end 253 | end 254 | end else if ( xfer_rx_jk == 1 ) begin 255 | xfer_cnt <= xfer_cnt - 1; 256 | if ( xfer_cnt == 12'd1 ) begin 257 | xfer_rx_jk <= 0; 258 | end 259 | end 260 | end 261 | end 262 | 263 | if ( reset == 1 ) begin 264 | mosi_load <= 0; 265 | xfer_cnt <= 12'd0; 266 | xfer_tx_jk <= 0; 267 | xfer_rx_jk <= 0; 268 | xfer_tx_jk_p1 <= 0; 269 | xfer_rx_jk_sr <= 5'd0; 270 | end 271 | end 272 | end 273 | end // proc_xfer_req 274 | assign xfer_byte[8:0] = xfer_cnt[11:3]; 275 | assign xfer_bit[2:0] = xfer_cnt[2:0]; 276 | 277 | 278 | //----------------------------------------------------------------------------- 279 | // Latch the MOSI byte data and start shifting out 280 | //----------------------------------------------------------------------------- 281 | always @ ( posedge clk ) begin : proc_mosi_sr 282 | begin 283 | if ( xfer_stall == 0 ) begin 284 | mosi_refused <= 0; 285 | mosi_byte_en_p1 <= mosi_byte_en; 286 | if ( ck_en_fal == 1 ) begin 287 | xfer_start_jk <= 0; 288 | end 289 | 290 | // When new mosi byte comes in, place in queue and drop request 291 | if ( mosi_byte_en == 1 ) begin 292 | xfer_start_jk <= ~ xfer_tx_jk; // A new Xfer 293 | mosi_byte_queue <= mosi_byte_d[7:0]; 294 | mosi_queued_jk <= 1; 295 | mosi_byte_req_loc <= 0; 296 | // Assert refused if not expecting a byte. 297 | if ( xfer_tx_jk == 1 ) begin 298 | mosi_refused <= ~ mosi_byte_req_loc; 299 | end 300 | end // if ( mosi_byte_en == 1 ) begin 301 | 302 | if ( mosi_loaded == 1 || xfer_start == 1 ) begin 303 | mosi_byte_queue <= 8'd0; 304 | mosi_queued_jk <= 0; 305 | if ( xfer_byte != 9'd0 || xfer_start == 1 ) begin 306 | mosi_byte_req_loc <= 1; 307 | end 308 | end 309 | 310 | if ( reset == 1 ) begin 311 | mosi_queued_jk <= 0; 312 | mosi_byte_req_loc <= 0; 313 | xfer_start_jk <= 0; 314 | end // if ( reset == 1 ) begin 315 | end 316 | end 317 | end // proc_mosi_sr 318 | 319 | assign mosi_sr_loc[7:0] = mosi_sr[7:0]; 320 | assign mosi_byte_req = mosi_byte_req_loc; 321 | 322 | 323 | //----------------------------------------------------------------------------- 324 | // Either Latch a new MOSI byte or shift existing byte 325 | //----------------------------------------------------------------------------- 326 | always @ ( posedge clk ) begin : proc_mosi_shift 327 | begin 328 | if ( xfer_stall == 0 ) begin 329 | mosi_loaded <= 0; 330 | if ( ck_en_fal == 1 ) begin 331 | if ( mosi_load == 1 ) begin 332 | mosi_sr <= mosi_byte_queue[7:0]; 333 | mosi_loaded <= 1; 334 | end else begin 335 | mosi_sr <= { mosi_sr[6:0], 1'd0 }; // Shift the Byte Out 336 | end 337 | end // if ( ck_en_fal == 1 ) begin 338 | if ( reset == 1 ) begin 339 | mosi_sr <= 8'd0; 340 | end 341 | end 342 | end 343 | end // proc mosi_shift 344 | 345 | 346 | //----------------------------------------------------------------------------- 347 | // SPI Master Output : The serial bits. 348 | //----------------------------------------------------------------------------- 349 | always @ ( posedge clk ) begin : proc_mosi_out 350 | begin 351 | if ( xfer_stall == 0 ) begin 352 | if ( spi_ctrl[0] == 0 ) begin 353 | spi_sck <= ck_loc & ~ ck_off; 354 | end else begin 355 | spi_sck <= ~ ck_loc & ~ ck_off; 356 | end 357 | 358 | // if ( ck_en_fal == 1 ) begin 359 | if ( ( ck_en_fal == 1 && spi_ctrl[1] == 0 ) || 360 | ( ck_en_ris == 1 && spi_ctrl[1] == 1 ) ) begin 361 | ck_off <= ck_off_pre; 362 | spi_cs_pre <= xfer_tx_jk_p1 | xfer_rx_jk_sr[0]; 363 | spi_cs_l_loc <= ~ spi_cs_pre; 364 | spi_is_idle <= ~ spi_cs_pre; 365 | spi_mosi <= mosi_sr_loc[7]; 366 | if ( spi_cs_pre == 0 && 367 | xfer_tx_jk_p1 == 0 && 368 | xfer_rx_jk_sr[0] == 0 ) begin 369 | ck_off_pre <= 1; 370 | end else begin 371 | ck_off_pre <= 0; 372 | ck_off <= 0; 373 | end 374 | end 375 | end // if ( xfer_stall == 0 ) begin 376 | if ( reset == 1 ) begin 377 | ck_off_pre <= 0; 378 | ck_off <= 0; 379 | spi_cs_pre <= 0; 380 | spi_cs_l_loc <= 1; 381 | end 382 | end 383 | end // proc_mosi_out 384 | assign spi_cs_l = spi_cs_l_loc; 385 | 386 | 387 | endmodule // spi_byte2bit 388 | -------------------------------------------------------------------------------- /verilog/top.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- (C) Copyright 2024 Kevin Hubbard - All rights reserved. 3 | -- Source file: top.v 4 | -- Date: November 29, 2024 5 | -- Author: khubbard 6 | -- Description: Artix7 sample design of Mesa Bus over FTDI UART. 7 | -- Language: Verilog-2001 8 | -- Simulation: Mentor-Modelsim 9 | -- Synthesis: Xilinx-Vivado 10 | -- License: This project is licensed with the CERN Open Hardware Licence 11 | -- v1.2. You may redistribute and modify this project under the 12 | -- terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl). 13 | -- This project is distributed WITHOUT ANY EXPRESS OR IMPLIED 14 | -- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY 15 | -- AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL 16 | -- v.1.2 for applicable Conditions. 17 | -- 18 | -- Revision History: 19 | -- Ver# When Who What 20 | -- ---- -------- -------- --------------------------------------------------- 21 | -- 0.1 11.29.24 khubbard Creation 22 | -- ***************************************************************************/ 23 | `timescale 1 ns/ 100 ps 24 | `default_nettype none // Strictly enforce all nets to be declared 25 | 26 | module top 27 | ( 28 | input wire clk, 29 | input wire bd_rx, 30 | output wire bd_tx, 31 | input wire [7:0] sw, 32 | output reg [7:0] led 33 | );// module top 34 | 35 | reg reset_loc = 1; 36 | wire clk_100m_loc; 37 | wire clk_100m_tree; 38 | wire lb_wr; 39 | wire lb_rd; 40 | wire [31:0] lb_addr; 41 | wire [31:0] lb_wr_d; 42 | reg [31:0] lb_rd_d; 43 | reg lb_rd_rdy; 44 | wire ftdi_wi; 45 | wire ftdi_ro; 46 | reg [31:0] reg_04 = 32'd0; 47 | 48 | assign clk_100m_loc = clk; // infer IBUF 49 | 50 | BUFGCE u0_bufg ( .I( clk_100m_loc ), .O( clk_100m_tree ), .CE(1) ); 51 | 52 | assign ftdi_wi = bd_rx; 53 | assign bd_tx = ftdi_ro; 54 | 55 | 56 | //----------------------------------------------------------------------------- 57 | // Configuration reset 58 | //----------------------------------------------------------------------------- 59 | always @ ( posedge clk_100m_tree ) begin : proc_reset 60 | reset_loc <= 0; 61 | end 62 | 63 | 64 | //----------------------------------------------------------------------------- 65 | // Local Bus test registers 66 | //----------------------------------------------------------------------------- 67 | always @ ( posedge clk_100m_tree ) begin : proc_bus_regs 68 | lb_rd_rdy <= 0; 69 | lb_rd_d <= 32'd0; 70 | led <= reg_04[7:0]; 71 | if ( lb_rd == 1 ) begin 72 | lb_rd_rdy <= 1; 73 | case( lb_addr[7:0] ) 74 | 8'h00 : lb_rd_d <= 32'h12345678; 75 | 8'h04 : lb_rd_d <= reg_04[31:0]; 76 | 8'h08 : lb_rd_d <= { 24'd0, sw[7:0] }; 77 | default : lb_rd_d <= 32'hDEADBEEF; 78 | endcase 79 | end 80 | if ( lb_wr == 1 ) begin 81 | case( lb_addr[7:0] ) 82 | 8'h00 : begin end 83 | 8'h04 : reg_04 <= lb_wr_d[31:0]; 84 | 8'h08 : begin end 85 | default : begin end 86 | endcase 87 | end 88 | end // proc_led_flops 89 | 90 | 91 | //----------------------------------------------------------------------------- 92 | // MesaBus interface to LocalBus : 2-wire FTDI UART to 32bit PCIe like localbus 93 | // Files available at https://github.com/blackmesalabs/MesaBusProtocol 94 | // ft232_xface.v, mesa_uart_phy.v, mesa_decode.v, mesa2lb.v, mesa_id.v, 95 | // mesa2ctrl.v, mesa_uart.v, mesa_tx_uart.v, mesa_ascii2nibble.v, 96 | // mesa_byte2ascii.v, iob_bidi.v 97 | //----------------------------------------------------------------------------- 98 | ft232_xface u_ft232_xface 99 | ( 100 | .reset ( reset_loc ), 101 | .clk_lb ( clk_100m_tree ), 102 | .ftdi_wi ( ftdi_wi ), 103 | .ftdi_ro ( ftdi_ro ), 104 | .lb_wr ( lb_wr ), 105 | .lb_rd ( lb_rd ), 106 | .lb_addr ( lb_addr[31:0] ), 107 | .lb_wr_d ( lb_wr_d[31:0] ), 108 | .lb_rd_d ( lb_rd_d[31:0] ), 109 | .lb_rd_rdy ( lb_rd_rdy ) 110 | );// u_ft232_xface 111 | 112 | 113 | endmodule // top.v 114 | `default_nettype wire // enable Verilog default for any 3rd party IP needing it 115 | -------------------------------------------------------------------------------- /vivado/go.sh: -------------------------------------------------------------------------------- 1 | 2 | # Generate a timestamp file with 32bit UNIX timestamp 3 | python time_stamp.py ../src/ 4 | date > start.txt 5 | vivado -mode batch -source go.tcl 6 | date > stop.txt 7 | 8 | # Post Cleanup 9 | rm vivado_*.backup.jou 10 | rm vivado_*.backup.log 11 | 12 | 13 | # Report some usage stats 14 | grep "Slice LUTs" ./reports/post_route_util.rpt 15 | grep "Slice Registers" ./reports/post_route_util.rpt 16 | grep "| RAMB" ./reports/post_route_util.rpt 17 | grep "DSPs" ./reports/post_route_util.rpt 18 | grep "Bonded IOB" ./reports/post_route_util.rpt 19 | grep "BUFGCTRL" ./reports/post_route_util.rpt 20 | grep "BUFIO" ./reports/post_route_util.rpt 21 | grep "BUFMRCE" ./reports/post_route_util.rpt 22 | grep "BUFHCE" ./reports/post_route_util.rpt 23 | grep "BUFR" ./reports/post_route_util.rpt 24 | grep "MMCME2_ADV" ./reports/post_route_util.rpt 25 | grep "PLLE2_ADV" ./reports/post_route_util.rpt 26 | 27 | # List and timing violations 28 | grep "(VIOLATED)" ./reports/post_route_timing_summary.rpt 29 | python ../python/timing_filter.py ./reports/post_route_timing_summary.rpt ./reports/timing_met.txt ./reports/timing_violated.txt 30 | more ./reports/timing_violated.txt 31 | 32 | grep "No pins matched" vivado.log 33 | -------------------------------------------------------------------------------- /vivado/go.tcl: -------------------------------------------------------------------------------- 1 | set design_name top 2 | set device xc7a35tcpg236-1 3 | set_part $device 4 | set rep_dir ./reports ; file mkdir $rep_dir 5 | set tmp_dir ./temp ; file mkdir $tmp_dir 6 | set_property SEVERITY {Warning} [get_drc_checks NSTD-1] 7 | source top_rtl_list.tcl 8 | read_xdc ./${design_name}_timing.xdc 9 | synth_design -top $design_name -part $device -fsm_extraction off 10 | report_timing_summary -file post_synth_timing_summary.rpt 11 | read_xdc ./${design_name}_physical.xdc 12 | opt_design 13 | place_design 14 | route_design 15 | #report_timing -sort_by group -max_paths 20 -file $rep_dir/post_route_timing_worst.rpt 16 | #report_clock_utilization -file $rep_dir/post_route_clock_util.rpt 17 | #report_drc -file $rep_dir/post_route_drc.rpt 18 | #report_datasheet -file $rep_dir/post_route_datasheets.rpt 19 | #check_timing -file $rep_dir/post_route_timing_check.rpt 20 | report_io -file $rep_dir/post_route_io.rpt 21 | report_timing_summary -file $rep_dir/post_route_timing_summary.rpt 22 | report_utilization -file $rep_dir/post_route_util.rpt 23 | report_power -file $rep_dir/post_route_pwr.rpt 24 | set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] 25 | write_bitstream -force ${design_name}.bit 26 | exit 27 | -------------------------------------------------------------------------------- /vivado/time_stamp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # python time_stamp.py ../../src/ 3 | 4 | import time; 5 | import sys; 6 | args = sys.argv; 7 | app_name = args[0]; 8 | src_path = args[1];# ie ../../src/ 9 | 10 | now = time.time() 11 | means = time.ctime(now) 12 | my_time_hex = "%08x" % now; 13 | 14 | veri_list = []; 15 | a=veri_list; 16 | a.append("module time_stamp"); 17 | a.append("("); 18 | a.append(" output wire [31:0] time_dout"); 19 | a.append(");"); 20 | a.append(" assign time_dout = 32'h" + my_time_hex + ";"); 21 | a.append("// " + means + ""); 22 | a.append("endmodule"); 23 | 24 | file_out = open ( src_path+'time_stamp.v', 'w' ); # or 'a' for Write Append 25 | for each in veri_list: 26 | file_out.write( each + "\r\n" ); 27 | file_out.close(); 28 | -------------------------------------------------------------------------------- /vivado/top_physical.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the Basys3 rev B board 2 | ## To use it in a project: 3 | ## - uncomment the lines corresponding to used pins 4 | ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project 5 | 6 | ## Clock signal 7 | set_property -dict { PACKAGE_PIN W5 IOSTANDARD LVCMOS33 } [get_ports clk] 8 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk] 9 | 10 | ##USB-RS232 Interface 11 | set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports bd_rx] 12 | set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports bd_tx] 13 | 14 | 15 | ##Buttons 16 | #set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports btnc] 17 | #set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports btnu] 18 | #set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports btnl] 19 | #set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports btnr] 20 | #set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports btnd] 21 | 22 | 23 | ## Switches 24 | set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports {sw[0]}] 25 | set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports {sw[1]}] 26 | set_property -dict { PACKAGE_PIN W16 IOSTANDARD LVCMOS33 } [get_ports {sw[2]}] 27 | set_property -dict { PACKAGE_PIN W17 IOSTANDARD LVCMOS33 } [get_ports {sw[3]}] 28 | set_property -dict { PACKAGE_PIN W15 IOSTANDARD LVCMOS33 } [get_ports {sw[4]}] 29 | set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports {sw[5]}] 30 | set_property -dict { PACKAGE_PIN W14 IOSTANDARD LVCMOS33 } [get_ports {sw[6]}] 31 | set_property -dict { PACKAGE_PIN W13 IOSTANDARD LVCMOS33 } [get_ports {sw[7]}] 32 | #set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports {sw[8]}] 33 | #set_property -dict { PACKAGE_PIN T3 IOSTANDARD LVCMOS33 } [get_ports {sw[9]}] 34 | #set_property -dict { PACKAGE_PIN T2 IOSTANDARD LVCMOS33 } [get_ports {sw[10]}] 35 | #set_property -dict { PACKAGE_PIN R3 IOSTANDARD LVCMOS33 } [get_ports {sw[11]}] 36 | #set_property -dict { PACKAGE_PIN W2 IOSTANDARD LVCMOS33 } [get_ports {sw[12]}] 37 | #set_property -dict { PACKAGE_PIN U1 IOSTANDARD LVCMOS33 } [get_ports {sw[13]}] 38 | #set_property -dict { PACKAGE_PIN T1 IOSTANDARD LVCMOS33 } [get_ports {sw[14]}] 39 | #set_property -dict { PACKAGE_PIN R2 IOSTANDARD LVCMOS33 } [get_ports {sw[15]}] 40 | 41 | 42 | 43 | ## LEDs 44 | #set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports {led}] 45 | set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports {led[0]}] 46 | set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS33 } [get_ports {led[1]}] 47 | set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports {led[2]}] 48 | set_property -dict { PACKAGE_PIN V19 IOSTANDARD LVCMOS33 } [get_ports {led[3]}] 49 | set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports {led[4]}] 50 | set_property -dict { PACKAGE_PIN U15 IOSTANDARD LVCMOS33 } [get_ports {led[5]}] 51 | set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports {led[6]}] 52 | set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports {led[7]}] 53 | #set_property -dict { PACKAGE_PIN V13 IOSTANDARD LVCMOS33 } [get_ports {led[8]}] 54 | #set_property -dict { PACKAGE_PIN V3 IOSTANDARD LVCMOS33 } [get_ports {led[9]}] 55 | #set_property -dict { PACKAGE_PIN W3 IOSTANDARD LVCMOS33 } [get_ports {led[10]}] 56 | #set_property -dict { PACKAGE_PIN U3 IOSTANDARD LVCMOS33 } [get_ports {led[11]}] 57 | #set_property -dict { PACKAGE_PIN P3 IOSTANDARD LVCMOS33 } [get_ports {led[12]}] 58 | #set_property -dict { PACKAGE_PIN N3 IOSTANDARD LVCMOS33 } [get_ports {led[13]}] 59 | #set_property -dict { PACKAGE_PIN P1 IOSTANDARD LVCMOS33 } [get_ports {led[14]}] 60 | #set_property -dict { PACKAGE_PIN L1 IOSTANDARD LVCMOS33 } [get_ports {led[15]}] 61 | 62 | 63 | ##7 Segment Display 64 | #set_property -dict { PACKAGE_PIN W7 IOSTANDARD LVCMOS33 } [get_ports {seg[0]}] 65 | #set_property -dict { PACKAGE_PIN W6 IOSTANDARD LVCMOS33 } [get_ports {seg[1]}] 66 | #set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS33 } [get_ports {seg[2]}] 67 | #set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports {seg[3]}] 68 | #set_property -dict { PACKAGE_PIN U5 IOSTANDARD LVCMOS33 } [get_ports {seg[4]}] 69 | #set_property -dict { PACKAGE_PIN V5 IOSTANDARD LVCMOS33 } [get_ports {seg[5]}] 70 | #set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports {seg[6]}] 71 | 72 | #set_property -dict { PACKAGE_PIN V7 IOSTANDARD LVCMOS33 } [get_ports dp] 73 | 74 | #set_property -dict { PACKAGE_PIN U2 IOSTANDARD LVCMOS33 } [get_ports {an[0]}] 75 | #set_property -dict { PACKAGE_PIN U4 IOSTANDARD LVCMOS33 } [get_ports {an[1]}] 76 | #set_property -dict { PACKAGE_PIN V4 IOSTANDARD LVCMOS33 } [get_ports {an[2]}] 77 | #set_property -dict { PACKAGE_PIN W4 IOSTANDARD LVCMOS33 } [get_ports {an[3]}] 78 | 79 | 80 | ##Buttons 81 | #set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports btnC] 82 | #set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports btnU] 83 | #set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports btnL] 84 | #set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports btnR] 85 | #set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports btnD] 86 | 87 | 88 | ##Pmod Header JA 89 | #set_property -dict { PACKAGE_PIN J1 IOSTANDARD LVCMOS33 } [get_ports {JA[0]}];#Sch name = JA1 90 | #set_property -dict { PACKAGE_PIN L2 IOSTANDARD LVCMOS33 } [get_ports {JA[1]}];#Sch name = JA2 91 | #set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports {JA[2]}];#Sch name = JA3 92 | #set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports {JA[3]}];#Sch name = JA4 93 | #set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports {JA[4]}];#Sch name = JA7 94 | #set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports {JA[5]}];#Sch name = JA8 95 | #set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports {JA[6]}];#Sch name = JA9 96 | #set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports {JA[7]}];#Sch name = JA10 97 | 98 | ##Pmod Header JB 99 | #set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports {JB[0]}];#Sch name = JB1 100 | #set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVCMOS33 } [get_ports {JB[1]}];#Sch name = JB2 101 | #set_property -dict { PACKAGE_PIN B15 IOSTANDARD LVCMOS33 } [get_ports {JB[2]}];#Sch name = JB3 102 | #set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports {JB[3]}];#Sch name = JB4 103 | #set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports {JB[4]}];#Sch name = JB7 104 | #set_property -dict { PACKAGE_PIN A17 IOSTANDARD LVCMOS33 } [get_ports {JB[5]}];#Sch name = JB8 105 | #set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports {JB[6]}];#Sch name = JB9 106 | #set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports {JB[7]}];#Sch name = JB10 107 | 108 | ##Pmod Header JC 109 | #set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports {JC[0]}];#Sch name = JC1 110 | #set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports {JC[1]}];#Sch name = JC2 111 | #set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports {JC[2]}];#Sch name = JC3 112 | #set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports {JC[3]}];#Sch name = JC4 113 | #set_property -dict { PACKAGE_PIN L17 IOSTANDARD LVCMOS33 } [get_ports {JC[4]}];#Sch name = JC7 114 | #set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports {JC[5]}];#Sch name = JC8 115 | #set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports {JC[6]}];#Sch name = JC9 116 | #set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports {JC[7]}];#Sch name = JC10 117 | 118 | ##Pmod Header JXADC 119 | #set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports {JXADC[0]}];#Sch name = XA1_P 120 | #set_property -dict { PACKAGE_PIN L3 IOSTANDARD LVCMOS33 } [get_ports {JXADC[1]}];#Sch name = XA2_P 121 | #set_property -dict { PACKAGE_PIN M2 IOSTANDARD LVCMOS33 } [get_ports {JXADC[2]}];#Sch name = XA3_P 122 | #set_property -dict { PACKAGE_PIN N2 IOSTANDARD LVCMOS33 } [get_ports {JXADC[3]}];#Sch name = XA4_P 123 | #set_property -dict { PACKAGE_PIN K3 IOSTANDARD LVCMOS33 } [get_ports {JXADC[4]}];#Sch name = XA1_N 124 | #set_property -dict { PACKAGE_PIN M3 IOSTANDARD LVCMOS33 } [get_ports {JXADC[5]}];#Sch name = XA2_N 125 | #set_property -dict { PACKAGE_PIN M1 IOSTANDARD LVCMOS33 } [get_ports {JXADC[6]}];#Sch name = XA3_N 126 | #set_property -dict { PACKAGE_PIN N1 IOSTANDARD LVCMOS33 } [get_ports {JXADC[7]}];#Sch name = XA4_N 127 | 128 | 129 | ##VGA Connector 130 | #set_property -dict { PACKAGE_PIN G19 IOSTANDARD LVCMOS33 } [get_ports {vgaRed[0]}] 131 | #set_property -dict { PACKAGE_PIN H19 IOSTANDARD LVCMOS33 } [get_ports {vgaRed[1]}] 132 | #set_property -dict { PACKAGE_PIN J19 IOSTANDARD LVCMOS33 } [get_ports {vgaRed[2]}] 133 | #set_property -dict { PACKAGE_PIN N19 IOSTANDARD LVCMOS33 } [get_ports {vgaRed[3]}] 134 | #set_property -dict { PACKAGE_PIN N18 IOSTANDARD LVCMOS33 } [get_ports {vgaBlue[0]}] 135 | #set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports {vgaBlue[1]}] 136 | #set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports {vgaBlue[2]}] 137 | #set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports {vgaBlue[3]}] 138 | #set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports {vgaGreen[0]}] 139 | #set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports {vgaGreen[1]}] 140 | #set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports {vgaGreen[2]}] 141 | #set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports {vgaGreen[3]}] 142 | #set_property -dict { PACKAGE_PIN P19 IOSTANDARD LVCMOS33 } [get_ports Hsync] 143 | #set_property -dict { PACKAGE_PIN R19 IOSTANDARD LVCMOS33 } [get_ports Vsync] 144 | 145 | 146 | ##USB-RS232 Interface 147 | #set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports RsRx] 148 | #set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports RsTx] 149 | 150 | 151 | ##USB HID (PS/2) 152 | #set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 PULLUP true } [get_ports PS2Clk] 153 | #set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 PULLUP true } [get_ports PS2Data] 154 | 155 | 156 | ##Quad SPI Flash 157 | ##Note that CCLK_0 cannot be placed in 7 series devices. You can access it using the 158 | ##STARTUPE2 primitive. 159 | #set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports {QspiDB[0]}] 160 | #set_property -dict { PACKAGE_PIN D19 IOSTANDARD LVCMOS33 } [get_ports {QspiDB[1]}] 161 | #set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports {QspiDB[2]}] 162 | #set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports {QspiDB[3]}] 163 | #set_property -dict { PACKAGE_PIN K19 IOSTANDARD LVCMOS33 } [get_ports QspiCSn] 164 | 165 | 166 | ## Configuration options, can be used for all designs 167 | set_property CONFIG_VOLTAGE 3.3 [current_design] 168 | set_property CFGBVS VCCO [current_design] 169 | 170 | ## SPI configuration mode options for QSPI boot, can be used for all designs 171 | set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] 172 | set_property BITSTREAM.CONFIG.CONFIGRATE 33 [current_design] 173 | set_property CONFIG_MODE SPIx4 [current_design] 174 | -------------------------------------------------------------------------------- /vivado/top_rtl_list.tcl: -------------------------------------------------------------------------------- 1 | # Read in source files 2 | #read_verilog [ glob ../src/*.v ] # use glob if all .v files in src are desi 3 | #read_vhdl [ glob ../src/*.vhd ] # use glob if all .vhd files in src are de 4 | read_verilog ../src/top.v 5 | read_verilog ../src/time_stamp.v 6 | read_verilog ../src_ip/mesa_uart.v 7 | read_verilog ../src_ip/mesa_uart_phy.v 8 | read_verilog ../src_ip/mesa_tx_uart.v 9 | read_verilog ../src_ip/mesa_rx_uart.v 10 | read_verilog ../src_ip/mesa_id.v 11 | read_verilog ../src_ip/mesa_decode.v 12 | read_verilog ../src_ip/mesa_byte2ascii.v 13 | read_verilog ../src_ip/mesa_ascii2nibble.v 14 | read_verilog ../src_ip/mesa2spi.v 15 | read_verilog ../src_ip/mesa2lb.v 16 | read_verilog ../src_ip/mesa2ctrl.v 17 | read_verilog ../src_ip/iob_bidi.v 18 | read_verilog ../src_ip/ft232_xface.v 19 | -------------------------------------------------------------------------------- /vivado/top_timing.xdc: -------------------------------------------------------------------------------- 1 | create_clock -period 10.000 -name clk_100m -waveform {0.000 5.000} [get_ports clk_100m_pin] 2 | set_input_jitter clk_100m 0.200 3 | 4 | # Add clock margin 5 | #set_clock_uncertainty -setup 0.050 [get_clocks clk0_tree]; 6 | #set_clock_uncertainty -hold 0.050 [get_clocks clk0_tree]; 7 | # 8 | #set_clock_uncertainty -setup 0.050 [get_clocks clk1_tree]; 9 | #set_clock_uncertainty -hold 0.050 [get_clocks clk1_tree]; 10 | # 11 | #set_clock_groups -asynchronous \ 12 | # -group [ get_clocks {clk_200m_loc} ] \ 13 | # -group [ get_clocks {clk_80m_loc} ] 14 | 15 | --------------------------------------------------------------------------------