Skip to content

Instantly share code, notes, and snippets.

@urbanij
Last active September 21, 2019 06:46
Show Gist options
  • Save urbanij/c8fa0bb54ad13e1d53547b735c0e11c6 to your computer and use it in GitHub Desktop.
Save urbanij/c8fa0bb54ad13e1d53547b735c0e11c6 to your computer and use it in GitHub Desktop.
Lookup Table generator for 7-segment display (specifically for the 6 on-board on the Terasic DE10-Lite dev. board)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# ==========================================================
# LUT 7-segment generator
# for the Univeristy project G-Pong
# Fall 2018 -- Digital Design class
#
# Francesco Urbani
# Date: Fri Nov 30 10:38:59 CET 2018
#
# usage:
# input : $ python lut_7_seg_generator.py generate-all
# or
# $ python lut_7_seg_generator.py [MAX_SCORE] [ORIENTATION] [ALIGNMENT]
# e.g.
# $ python lut_7_seg_generator.py 23 up right
#
#
# ouput : 4 files called {module_name}.v in current directory if generate-all
# otherwise just a file.
# ==========================================================
import sys
import os
import math
import time
import datetime
try:
import tqdm
except Exception as e:
print("Installing tqdm...")
os.system("pip install tqdm")
def print_error_msg():
print("usage: python lut_7_seg_generator.py generate-all")
print("")
print("or: python lut_7_seg_generator.py [MAX_SCORE] [ORIENTATION] [ALIGNMENT]")
print(" MAX_SCORE: highest displayable score")
print(" ORIENTATION: up/down")
print(" ALIGNMENT: left/right")
print("")
# print("----------------------------")
if sys.platform[:3] != "win": # for unix
unix_date_format = os.popen('date').read()[:-1] # unix time stamp
else: # for shitty windows machines
unix_date_format = str(datetime.datetime.utcfromtimestamp(time.time()).replace(tzinfo=datetime.timezone.utc))
# map of the 7-segment display.
# Terasic DE10-Lite has six 7-segment displays common anode (active low)
# the 7th bit represent the point
# ===================================================
# upright version
# ___________
# | |
# USB| DE10-Lite |VGA
# |___________|
digits_up_bin = [ "8'b11000000", # 0
"8'b11111001", # 1 --0--
"8'b10100100", # 2 | |
"8'b10110000", # 3 5 1
"8'b10011001", # 4 | |
"8'b10010010", # 5 --6--
"8'b10000010", # 6 | |
"8'b11111000", # 7 4 2
"8'b10000000", # 8 | |
"8'b10010000" # 9 --3-- .7
]
# ===================================================
# upside down version
# ___________
# | |
# VGA| DE10-Lite |USB
# |___________|
digits_down_bin = [ "8'b11000000", # 0
"8'b11001111", # 1 --3--
"8'b10100100", # 2 | |
"8'b10000110", # 3 2 4
"8'b10001011", # 4 | |
"8'b10010010", # 5 --6--
"8'b10010000", # 6 | |
"8'b11000111", # 7 1 5
"8'b10000000", # 8 | |
"8'b10000010" # 9 --0-- .7
]
off_n = "8'hFF" # all off
# ===================================================
# turn digits_up and digits_down lists into hex for to save space.
# e.g. digits_up_hex is =
# ["8'hc0", "8'hf9", "8'ha4", "8'hb0", "8'h99", "8'h92", "8'h82", "8'hf8", "8'h80", "8'h90"]
digits_up =[]
for i in digits_up_bin:
digits_up.append( "8'h"+hex(int('0'+i[2:],2))[2:] )
digits_down =[]
for i in digits_down_bin:
digits_down.append( "8'h"+hex(int('0'+i[2:],2))[2:] )
NUM_DIGITS = 6 # on board 7-segments digits
MAX_SCORE = 999
## quick arguments check
if len(sys.argv) == 2:
if sys.argv[1].lower() == "generate-all":
# calls itself 4 times
for i in range(4):
arg_= ("UP RIGHT" if i == 0 else
"UP LEFT" if i == 1 else
"DOWN RIGHT" if i == 2 else
"DOWN LEFT" if i == 3 else None)
os.system("python lut_7_seg_generator.py " + str(MAX_SCORE) + " " + arg_)
print ("\ndone.")
quit()
else:
print_error_msg()
quit()
elif len(sys.argv) != 4 :
print_error_msg()
# creates a dummy file
# MAX_SCORE = 15
# ORIENTATION = "UP"
# ALIGNMENT = "RIGHT"
# print("using default values...")
# print("MAX_SCORE = {}".format(MAX_SCORE))
# print("ORIENTATION = {}".format(ORIENTATION))
# print("ALIGNMENT = {}".format(ALIGNMENT))
quit()
else:
try:
MAX_SCORE = int(sys.argv[1])
ORIENTATION = sys.argv[2].upper()
ALIGNMENT = sys.argv[3].upper()
except Exception as e:
print_error_msg()
quit()
module_name = ( "lut_7_seg_current_score_upright" if (ORIENTATION == "UP" and ALIGNMENT == "RIGHT") else
"lut_7_seg_current_score_upsidedown" if (ORIENTATION == "DOWN" and ALIGNMENT == "RIGHT") else
"lut_7_seg_highest_score_upright" if (ORIENTATION == "UP" and ALIGNMENT == "LEFT" ) else
"lut_7_seg_highest_score_upsidedown" if (ORIENTATION == "DOWN" and ALIGNMENT == "LEFT" ) else None)
if ( math.log2(MAX_SCORE) == int(math.log2(MAX_SCORE)) ):
MAX_POINT_BITS = int(math.ceil(math.log2(MAX_SCORE))) + 1
else:
MAX_POINT_BITS = int(math.ceil(math.log2(MAX_SCORE)))
txt = """//////////////////////////////////////////////
// Project Name: G-Pong
// PSD, Fall 2018
// Group: Leonardo Barzacchi, Filippo Bertelli, Francesco Urbani
// Author(s): Francesco Urbani
//
// Create Date: """ + unix_date_format + """
//
// Design Name:
// Module Name: """ + module_name + """
// Target Devices: Intel MAX10 10M50DAF484C7G
// Tool versions:
// Description: 7 segment LUT. maps integer from 0 to """ + str(MAX_SCORE) + """
// to the six 7-segment display on the board.
//
// ===================================================
// THIS FILE IS AUTOGENERATED
// EDITS TO THIS FILE WILL BE LOST
// ===================================================
//
// generated using a python script:
// $ python lut_7_seg_generator.py """ + str(MAX_SCORE) + """ """ + ORIENTATION + """ """ + ALIGNMENT + """
//
//////////////////////////////////////////////
module """ + module_name + """
(
input wire [""" + str(MAX_POINT_BITS-1) + """:0] points, // [0-""" + str(MAX_SCORE) + """] 2^""" + str(MAX_POINT_BITS-1) + """ < """ + str(MAX_SCORE) + """ < 2^""" + str(MAX_POINT_BITS) + """
output wire [23:0] hex
);
// all turned off
"""
if (ORIENTATION == 'UP' and ALIGNMENT == "RIGHT" or ORIENTATION == "DOWN" and ALIGNMENT == "LEFT"):
r = list(range(0,3))
else:
r = list(range(3,6))
r = r[::-1]
for i in r:
txt += "reg [7:0] hex" + str(i) + " = 8'hFF;\n"
txt += """
always @ (points)
\tbegin
\t\tcase (points)
"""
for i in tqdm.tqdm(range(0, MAX_SCORE+1), desc=module_name):
l = len(str(MAX_SCORE)) # how many digits the number MAX_SCORE has.
# suppose MAX_SCORE = 124, this means only the first 3 digits will be affected not all the 6.
# so I wont change those, saving some disk space. (~200 Mb a lut to represent 0 to 999999 without this "trick")
txt += ("\t"*3 + str(MAX_POINT_BITS)+"'d"+str(i)) + ":\n"
txt += "\t"*4 + "begin\n"
# e.g. MAX_SCORE = 511
# ==> i = 12
# ==> l = 3
p = []
for j in str(i)[::-1]:
p.append(int(j))
# p = [2, 1]
if ALIGNMENT == "LEFT":
p = p[::-1] # reverse list
dig = [off_n] * l # dig = ["8'hFF", "8'hFF", "8'hFF"]
for k in range(0, len(p)):
if ORIENTATION == "UP":
dig[k] = digits_up[p[k]]
# dig = ["8'ha4", "8'hf9", "8'hFF"]
elif ORIENTATION == "DOWN":
dig[k] = digits_down[p[k]]
if ALIGNMENT == "RIGHT":
for k in range(0,len(dig)):
if ORIENTATION == "UP":
txt += ("\t"*5 + "hex" + str(k) + "=" + dig[k] + ";\n")
elif ORIENTATION == "DOWN":
txt += ("\t"*5 + "hex" + str(NUM_DIGITS-k-1) + "=" + dig[k] + ";\n")
else: # LEFT
# mirror the number
# dig = dig[::-1]
for k in range(0,len(dig)):
if ORIENTATION == "UP":
txt += ("\t"*5 + "hex" + str(NUM_DIGITS-k-1) + "=" + dig[k] + ";\n")
elif ORIENTATION == "DOWN":
txt += ("\t"*5 + "hex" + str(k) + "=" + dig[k] + ";\n")
txt += "\t\t\t\tend\n\n"
txt += """\t\t\tdefault:\t\t// any number from """ + str(MAX_SCORE+1) + """ to """ + str(999999) + """
\t\t\t\tbegin
"""
for i in r:
txt += "\t"*5 + "hex" + str(i) + "=8'h7F;\n"
txt += """
\t\t\t\tend
\t\tendcase
\tend
\tassign hex = {"""
for i in r[:-1]: # except last item (no comma)
txt += "hex" + str(i) + ", "
txt += "hex" + str(r[-1]) + "};" # last item
txt += "\n\nendmodule\n"
with open (module_name + ".v", "w") as f:
f.write(txt)
# print(" " + module_name +".v created in current directory")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment