├── 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 |
--------------------------------------------------------------------------------