Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: whitequark/Boneless-CPU
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 7092cdd4d3f6
Choose a base ref
...
head repository: whitequark/Boneless-CPU
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 6968ffe60683
Choose a head ref
  • 3 commits
  • 5 files changed
  • 1 contributor

Commits on Jul 2, 2019

  1. gateware.core_v3: prototype CoreFSM.

    This does not yet handle multicycle instructions, and isn't really
    tested, and is especially not optimized, but it does run.
    whitequark committed Jul 2, 2019
    Copy the full SHA
    af5126a View commit details
  2. Copy the full SHA
    f92bc04 View commit details

Commits on Jul 3, 2019

  1. Copy the full SHA
    6968ffe View commit details
Showing with 554 additions and 326 deletions.
  1. +83 −110 boneless/gateware/alsru.py
  2. +83 −0 boneless/gateware/control.py
  3. +217 −48 boneless/gateware/core_v3.py
  4. +159 −156 boneless/gateware/decoder_v3.py
  5. +12 −12 boneless/test/test_alsru.py
193 changes: 83 additions & 110 deletions boneless/gateware/alsru.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
from nmigen import *

from .control import *


__all__ = ["ALSRU", "ALSRU_4LUT"]


class ALSRU:
"""Arithmetical, logical, shift, and rotate unit."""

# defined by subclasses
BITS_OP = None
CTRL_A = None
CTRL_B = None
CTRL_nB = None
CTRL_AaB = None
CTRL_AoB = None
CTRL_AxB = None
CTRL_ApB = None
CTRL_AmB = None
CTRL_SL = None
CTRL_SR = None
# redefined by subclasses
class Op(MultiControlEnum):
A = ()
B = ()
nB = ()
AaB = ()
AoB = ()
AxB = ()
ApB = ()
AmB = ()
SL = ()
SR = ()

def __init__(self, width):
self.a = Signal(width)
@@ -33,31 +35,7 @@ def __init__(self, width):
self.si = Signal() # shift in
self.so = Signal() # shift out

self.ctrl = None # defined by subclasses

@classmethod
def ctrl_decoder(cls, word):
if word == cls.CTRL_A._as_const():
return "A"
if word == cls.CTRL_B._as_const():
return "B"
if word == cls.CTRL_nB._as_const():
return "~B"
if word == cls.CTRL_AaB._as_const():
return "A&B"
if word == cls.CTRL_AoB._as_const():
return "A|B"
if word == cls.CTRL_AxB._as_const():
return "A^B"
if word == cls.CTRL_ApB._as_const():
return "A+B"
if word == cls.CTRL_AmB._as_const():
return "A-B"
if word == cls.CTRL_SL._as_const():
return "R<<1"
if word == cls.CTRL_SR._as_const():
return "R>>1"
return "? {:0{}b}".format(word, cls.BITS_OP)
self.op = self.Op.signal() # redefined by subclasses


class ALSRU_4LUT(ALSRU, Elaboratable):
@@ -94,92 +72,87 @@ class ALSRU_4LUT(ALSRU, Elaboratable):
# R<<1: S=SLn-1 Y=S O=Y (pre-load R)
# R>>1: S=SRn+1 Y=S O=Y (pre-load R)

MUX_S_x = 0
MUX_S_L = 0b0
MUX_S_R = 0b1

MUX_X_x = 0
MUX_X_A = 0b00
MUX_X_AaB = 0b01
MUX_X_AoB = 0b10
MUX_X_AxB = 0b11

MUX_Y_0 = 0b00
MUX_Y_S = 0b01
MUX_Y_B = 0b10
MUX_Y_nB = 0b11

MUX_O_XpY = 0b0
MUX_O_Y = 0b1

BITS_OP = 6
CTRL_A = Cat(C(MUX_S_x, 1), C(MUX_X_A, 2), C(MUX_Y_0, 2), C(MUX_O_XpY, 1))
CTRL_B = Cat(C(MUX_S_x, 1), C(MUX_X_x, 2), C(MUX_Y_B, 2), C(MUX_O_Y, 1))
CTRL_nB = Cat(C(MUX_S_x, 1), C(MUX_X_x, 2), C(MUX_Y_nB, 2), C(MUX_O_Y, 1))
CTRL_AaB = Cat(C(MUX_S_x, 1), C(MUX_X_AaB, 2), C(MUX_Y_0, 2), C(MUX_O_XpY, 1))
CTRL_AoB = Cat(C(MUX_S_x, 1), C(MUX_X_AoB, 2), C(MUX_Y_0, 2), C(MUX_O_XpY, 1))
CTRL_AxB = Cat(C(MUX_S_x, 1), C(MUX_X_AxB, 2), C(MUX_Y_0, 2), C(MUX_O_XpY, 1))
CTRL_ApB = Cat(C(MUX_S_x, 1), C(MUX_X_A, 2), C(MUX_Y_B, 2), C(MUX_O_XpY, 1))
CTRL_AmB = Cat(C(MUX_S_x, 1), C(MUX_X_A, 2), C(MUX_Y_nB, 2), C(MUX_O_XpY, 1))
CTRL_SL = Cat(C(MUX_S_L, 1), C(MUX_X_x, 2), C(MUX_Y_S, 2), C(MUX_O_Y, 1))
CTRL_SR = Cat(C(MUX_S_R, 1), C(MUX_X_x, 2), C(MUX_Y_S, 2), C(MUX_O_Y, 1))

def __init__(self, width):
super().__init__(width)

self.s = Signal(width)
self.x = Signal(width)
self.y = Signal(width)

self.ctrl = Record([
("s", 1),
("x", 2),
("y", 2),
("o", 1),
])
class MuxS(ControlEnum):
L = 0b0
R = 0b1
x = 0

class MuxX(ControlEnum):
A = 0b00
AaB = 0b01
AoB = 0b10
AxB = 0b11
x = 0

class MuxY(ControlEnum):
Z = 0b00
S = 0b01
B = 0b10
nB = 0b11

class MuxO(ControlEnum):
XpY = 0b0
Y = 0b1

class Op(MultiControlEnum, layout={"s":MuxS, "x":MuxX, "y":MuxY, "o":MuxO}):
A = ("x", "A", "Z", "XpY",)
B = ("x", "x", "B", "Y", )
nB = ("x", "x", "nB", "Y", )
AaB = ("x", "AaB", "Z", "XpY",)
AoB = ("x", "AoB", "Z", "XpY",)
AxB = ("x", "AxB", "Z", "XpY",)
ApB = ("x", "A", "B", "XpY",)
AmB = ("x", "A", "nB", "XpY",)
SL = ("L", "x", "S", "Y", )
SR = ("R", "x", "S", "Y", )

def elaborate(self, platform):
m = Module()

with m.Switch(self.ctrl.s):
with m.Case(self.MUX_S_L):
m.d.comb += self.s.eq(Cat(self.si, self.r[:-1]))
op = self.Op.expand(m, self.op)

s = Signal.like(self.o)
with m.Switch(op.s):
with m.Case(self.MuxS.L):
m.d.comb += s.eq(Cat(self.si, self.r[:-1]))
m.d.comb += self.so.eq(self.r[-1])
with m.Case(self.MUX_S_R):
m.d.comb += self.s.eq(Cat(self.r[ 1:], self.si))
with m.Case(self.MuxS.R):
m.d.comb += s.eq(Cat(self.r[ 1:], self.si))
m.d.comb += self.so.eq(self.r[ 0])

with m.Switch(self.ctrl.x):
with m.Case(self.MUX_X_AaB):
m.d.comb += self.x.eq(self.a & self.b)
with m.Case(self.MUX_X_AoB):
m.d.comb += self.x.eq(self.a | self.b)
with m.Case(self.MUX_X_AxB):
m.d.comb += self.x.eq(self.a ^ self.b)
with m.Case(self.MUX_X_A):
m.d.comb += self.x.eq(self.a)

with m.Switch(self.ctrl.y):
with m.Case(self.MUX_Y_0):
m.d.comb += self.y.eq(0)
with m.Case(self.MUX_Y_S):
m.d.comb += self.y.eq(self.s)
with m.Case(self.MUX_Y_B):
m.d.comb += self.y.eq(self.b)
with m.Case(self.MUX_Y_nB):
m.d.comb += self.y.eq(~self.b)
x = Signal.like(self.o)
with m.Switch(op.x):
with m.Case(self.MuxX.AaB):
m.d.comb += x.eq(self.a & self.b)
with m.Case(self.MuxX.AoB):
m.d.comb += x.eq(self.a | self.b)
with m.Case(self.MuxX.AxB):
m.d.comb += x.eq(self.a ^ self.b)
with m.Case(self.MuxX.A):
m.d.comb += x.eq(self.a)

y = Signal.like(self.o)
with m.Switch(op.y):
with m.Case(self.MuxY.Z):
m.d.comb += y.eq(0)
with m.Case(self.MuxY.S):
m.d.comb += y.eq(s)
with m.Case(self.MuxY.B):
m.d.comb += y.eq(self.b)
with m.Case(self.MuxY.nB):
m.d.comb += y.eq(~self.b)

p = Signal.like(self.o)
m.d.comb += Cat(p, self.co).eq(self.x + self.y + self.ci)
m.d.comb += Cat(p, self.co).eq(x + y + self.ci)

with m.Switch(self.ctrl.o):
with m.Case(self.MUX_O_XpY):
with m.Switch(op.o):
with m.Case(self.MuxO.XpY):
m.d.comb += self.o.eq(p)
with m.Case(self.MUX_O_Y):
m.d.comb += self.o.eq(self.y)
with m.Case(self.MuxO.Y):
m.d.comb += self.o.eq(y)

# http://teaching.idallen.com/cst8214/08w/notes/overflow.txt
with m.Switch(Cat(self.x[-1], self.y[-1], self.o[-1])):
with m.Switch(Cat(x[-1], y[-1], self.o[-1])):
with m.Case(0b100):
m.d.comb += self.vo.eq(1)
with m.Case(0b011):
83 changes: 83 additions & 0 deletions boneless/gateware/control.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import enum
from nmigen import *


__all__ = ["ControlEnum", "MultiControlEnum"]


# We have to do an annoying metaclass dance because there's no @classproperty.
class ControlEnumMeta(enum.EnumMeta):
@property
def width(cls):
return max(cls).bit_length()


@enum.unique
class ControlEnum(enum.IntEnum, metaclass=ControlEnumMeta):
@classmethod
def decoder(cls, value):
try:
return cls(value).name.replace("_", "-")
except ValueError:
return str(value)

@classmethod
def signal(cls, **kwargs):
return Signal(cls.width, decoder=cls.decoder, src_loc_at=1, **kwargs)

def __repr__(self):
return "<{}: {:0{}b}>".format(self.name, self.value, self.width)


# We have to do an annoying metaclass dance because we want to do something like:
#
# class MuxA(ControlEnum): ...
# class MuxB(ControlEnum): ...
# class Mode(MultiControlEnum):
# FOO = (MuxA.X, MuxB.Y)
#
# but by the time we're inside the body of `Mode` it is no longer possible to access the names from
# the outer scope, so we can't easily name `MuxA` for example, so we rewrite it as:
#
# class Mode(MultiControlEnum, layout=[MuxA, MuxB]):
# FOO = ("X", "Y")
class MultiControlEnumMeta(ControlEnumMeta):
@classmethod
def __prepare__(metacls, name, bases, **kwargs):
return super().__prepare__(name, bases)

def __new__(cls, name, bases, classdict, layout=None):
if layout is not None:
classdict, old_classdict = type(classdict)(), classdict

offsets = []
offset = 0
for enum in layout.values():
offsets.append(offset)
offset += enum.width

for key in old_classdict:
if key.startswith("_"):
classdict[key] = old_classdict[key]
else:
value = 0
for item, enum, offset in zip(old_classdict[key], layout.values(), offsets):
value |= enum[item] << offset
classdict[key] = value

@classmethod
def expand(cls, m, signal):
rec = Record([(name, enum.width) for (name, enum) in layout.items()],
src_loc_at=1)
for name, enum in layout.items():
rec[name].decoder = enum.decoder
m.d.comb += rec.eq(signal)
return rec
classdict["expand"] = expand

return super().__new__(cls, name, bases, classdict)


class MultiControlEnum(ControlEnum, metaclass=MultiControlEnumMeta):
def foo(self):
pass
Loading