#!/usr/bin/env python3
 
# Raspberry Pi iceprog (piceprog)
# Tool for programming iCE40 FPGAs with Pi GPIOs

import sys
import RPi.GPIO as gpio
from time import sleep
from math import ceil

fpga_sclk = 19
fpga_sdi = 26
fpga_ss = 13
fpga_done = 6
fpga_rst = 5

gpio.setmode(gpio.BCM)
gpio.setwarnings(False)

for pin in [fpga_sclk, fpga_sdi, fpga_ss, fpga_rst]:
	gpio.setup(pin, gpio.OUT)

gpio.setup(fpga_done, gpio.IN)

def prog(fname):
	bitstream = list(open(fname, "rb").read())
	print("{} bytes.".format(len(bitstream)))
	bits = []
	for byte in bitstream:
		for i in range(8):
			bits.append(byte >> 7)
			byte = (byte << 1) & 0xff
	bits.extend(49 * [0]) # at least 49 dummy cycles required at end.
	print("Starting")
	gpio.output(fpga_rst, 0)
	gpio.output(fpga_ss, 0)
	gpio.output(fpga_sclk, 1)	# CPOL = 1 (clock idle high)
	gpio.output(fpga_sdi, 0)
	sleep(0.001)
	gpio.output(fpga_rst, 1)
	sleep(0.001)
	gpio.output(fpga_ss, 1)
	for i in range(8):
		gpio.output(fpga_sclk, 0)
		gpio.output(fpga_sclk, 1)
	# CPHA = 1 (data captured on trailing edge of clock pulse)
	gpio.output(fpga_ss, 0)
	for bit in bits:
		gpio.output(fpga_sdi, bit)
		gpio.output(fpga_sclk, 0)
		gpio.output(fpga_sclk, 1)
	if gpio.input(fpga_done):
		print("CDONE high, yay!")
	else:
		print("CDONE not high, something may have gone wrong")

if __name__ == "__main__":
	if len(sys.argv) != 2:
		exit("Usage: piceprog (file.bin)")
	prog(sys.argv[1])
