I am currently using a BlackIce to test an ASIC I made. I am using nMigen to develop RTL. I did commit my board file upstream; there is a commit for BlackIce and BlackIce II in the nmigen-boards repo.
As I don't have a BlackIce II this file is not fully tested so it would be good if somebody could test it. The nMigen code I used to test the onboard SRAM:
#!/bin/env python3
import types
from nmigen import *
from nmigen.build import *
from nmigen_boards.blackice import BlackIcePlatform
class Debounce(Elaboratable):
def __init__(self, sig=None, samplerate=1000, samples=4):
self.samplerate = samplerate
self.samples = samples
self.i = Signal() if sig is None else sig
self.o = Signal()
def elaborate(self, platform):
MAX_SAMPLED = 2**self.samples - 1
m = Module()
sampled = Signal(self.samples)
cnt = Signal(max=self.samplerate-1)
with m.If(cnt == 0):
m.d.sync += [
sampled[0].eq(self.i),
sampled[1:].eq(sampled[:-1]),
cnt.eq(self.samplerate - 1),
]
with m.Else():
m.d.sync += cnt.eq(cnt - 1)
with m.If(sampled == 0):
m.d.sync += self.o.eq(0)
with m.Elif(sampled == MAX_SAMPLED):
m.d.sync += self.o.eq(1)
return m
def debounce(m, sig):
deb = Debounce(sig)
m.submodules += deb
return deb.o
class Rise(Elaboratable):
def __init__(self, sig=None):
self.i = Signal() if sig is None else sig
self.o = Signal()
def elaborate(self, platform):
m = Module()
prev = Signal()
m.d.sync += prev.eq(self.i)
m.d.comb += self.o.eq(Cat(self.i, prev) == 0b01)
return m
def rise(m, sig):
r = Rise(sig)
m.submodules += r
return r.o
class SRAM_test(Elaboratable):
clk_name = "clk100"
def elaborate(self, platform):
m = Module()
clk = platform.request(self.clk_name, 0)
m.domains.sync = ClockDomain()
m.d.comb += ClockSignal().eq(clk.i)
signames = [
"sram",
"user_ledr", "user_ledg", "user_ledo", "user_ledb",
"user_btn",
]
sigs = types.SimpleNamespace()
for name in signames:
if type(name) == str:
setattr(sigs, name, platform.request(name, 0))
else:
name2 = name[0]
num = name[1]
setattr(sigs, "{}_{}".format(name2, num), platform.request(name2, num))
we = Signal(1, reset_less=True)
din = Signal(16, reset_less=True)
dout = Signal(16, reset_less=True)
oe = Signal(1, reset_less=True)
a = Signal(18)
red = Signal(reset_less=True)
orange = Signal(reset_less=True)
green = Signal(reset_less=True)
blue = Signal()
m.d.comb += [
sigs.sram.address.o.eq(a),
din.eq(sigs.sram.data.i),
sigs.sram.data.o.eq(dout),
sigs.sram.data.oe.eq(~oe), # port in input when SRAM in output
sigs.sram.we.o.eq(we),
sigs.sram.cs.o.eq(1),
sigs.sram.oe.o.eq(oe),
sigs.user_ledr.o.eq(red),
sigs.user_ledo.o.eq(orange),
sigs.user_ledg.o.eq(green),
sigs.user_ledb.o.eq(blue),
]
# Make button toggle push
sw = debounce(m, sigs.user_btn.i)
push = rise(m, sw)
with m.If(push == 1):
m.d.sync += blue.eq(~blue)
with m.FSM():
SWI_DIVIDE2 = 6
cnt = Signal(max=SWI_DIVIDE2-1)
with m.State("START"):
m.d.comb += [
green.eq(0),
orange.eq(1),
red.eq(0),
oe.eq(0b0),
we.eq(0b0),
dout.eq(0),
]
m.d.sync += [
a.eq(0x3FFFF),
cnt.eq(SWI_DIVIDE2-1),
]
m.next = "WRITE"
with m.State("WRITE"):
m.d.comb += [
green.eq(0),
orange.eq(1),
red.eq(0),
oe.eq(0b0),
we.eq(0b0),
dout.eq(a[0:16]),
]
with m.If(cnt == 0):
m.d.sync += cnt.eq(SWI_DIVIDE2 - 1)
m.next = "WRITEB"
with m.Else():
m.d.sync += cnt.eq(cnt - 1)
with m.State("WRITEB"):
m.d.comb += [
green.eq(0),
orange.eq(1),
red.eq(0),
oe.eq(0b0),
we.eq(0b1),
dout.eq(a[0:16]),
]
with m.If(cnt == 0):
m.d.sync += cnt.eq(SWI_DIVIDE2 - 1)
with m.If(a == 0):
m.d.sync += a.eq(0x3FFFF)
m.next = "READ"
with m.Else():
m.d.sync += a.eq(a - 1)
m.next = "WRITE"
with m.Else():
m.d.sync += cnt.eq(cnt - 1)
with m.State("READ"):
m.d.comb += [
green.eq(0),
orange.eq(1),
red.eq(0),
oe.eq(0b1),
we.eq(0b0),
dout.eq(0),
]
with m.If(cnt == 0):
m.d.sync += cnt.eq(SWI_DIVIDE2 - 1)
with m.If(din == a[0:16]):
with m.If(a == 0):
m.next = "DONE"
with m.Else():
m.d.sync += a.eq(a - 1)
m.next = "READ"
with m.Else():
m.next = "ERROR"
with m.Else():
m.d.sync += cnt.eq(cnt - 1)
with m.State("DONE"):
m.d.comb += [
green.eq(1),
orange.eq(0),
red.eq(0),
oe.eq(0b01),
we.eq(0b00),
dout.eq(0),
]
# Button press toggles blue led and if on will contantly read the memmory
with m.If(blue == 1):
m.d.sync += [
cnt.eq(SWI_DIVIDE2 - 1),
a.eq(0x3FFFF),
]
m.next = "READ"
with m.State("ERROR"):
m.d.comb += [
green.eq(0),
orange.eq(0),
red.eq(1),
oe.eq(0b01),
we.eq(0b00),
dout.eq(0),
]
# HALT
return m
p = BlackIcePlatform()
test = SRAM_test()
# Provide empty opts as default --placer opt is not recognized by my older nextpnr executable
p.build(test, nextpnr_opts="", do_program=True)