Skip to content

Commit

Permalink
Systoliccleanup (#134)
Browse files Browse the repository at this point in the history
systolic cleanup to remove state and unused functionality
  • Loading branch information
jameshegarty committed Feb 7, 2019
1 parent 9f25683 commit 2a8d953
Show file tree
Hide file tree
Showing 4 changed files with 418 additions and 517 deletions.
29 changes: 9 additions & 20 deletions modules/modules.lua
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,6 @@ local function waitOnInputSystolic( systolicModule, fns, passthroughFns )

err( systolicModule:getDelay(prefix.."ready")==0, "ready bit should not be pipelined")

local asstInst = res:add( S.module.assert( "waitOnInput valid bit doesn't match ready bit", true ):instantiate("asstInst") )
local printInst
if DARKROOM_VERBOSE then printInst = res:add( S.module.print( types.tuple{types.bool(),types.bool(),types.bool(),types.bool()}, "WaitOnInput "..systolicModule.name.." ready %d validIn %d runable %d RST %d", true ):instantiate(prefix.."printInst") ) end

Expand All @@ -355,7 +354,7 @@ local function waitOnInputSystolic( systolicModule, fns, passthroughFns )

local pipelines = {}
-- Actually, it's ok for (ready==false and valid(inp)==true) to be true. We do not have to read when ready==false, we can just ignore it.
-- table.insert( pipelines, asstInst:process(S.__not(S.__and(S.eq(inner:ready(),S.constant(false,types.bool())),S.index(sinp,1)))):disablePipelining() )

if DARKROOM_VERBOSE then table.insert( pipelines, printInst:process( S.tuple{inner[prefix.."ready"](inner),S.index(sinp,1), runable, RST} ) ) end

local CE = S.CE("CE")
Expand Down Expand Up @@ -2443,7 +2442,6 @@ modules.changeRate = memoize(function(A, H, inputRate, outputRate, framed, frame
end

res.stateful = true
-- res.delay = (math.log(maxRate/inputRate)/math.log(2)) + (math.log(maxRate/outputRate)/math.log(2))
res.delay = 0
res.name = J.verilogSanitize("ChangeRate_"..tostring(A).."_from"..inputRate.."_to"..outputRate.."_H"..H.."_framed"..tostring(framed))

Expand All @@ -2460,8 +2458,6 @@ modules.changeRate = memoize(function(A, H, inputRate, outputRate, framed, frame
local rvalid = S.parameter("reset", types.bool() )
local pinp = S.parameter("process_input", rigel.lower(res.inputType) )

--local regs = J.map( J.range(maxRate), function(i) return systolicModule:add(S.module.reg(A,true):instantiate("Buffer_"..i)) end )

if inputRate>outputRate then

-- 8 to 4
Expand Down Expand Up @@ -2536,7 +2532,7 @@ modules.linebuffer = memoize(function( A, w, h, T, ymin, framed, X )
function res.makeSystolic()
local systolicModule = Ssugar.moduleConstructor(res.name)
local sinp = S.parameter("process_input", rigel.lower(res.inputType) )
local addr = systolicModule:add( S.module.regBy( types.uint(16), fpgamodules.incIfWrap( types.uint(16), (w/T)-1), true, nil, 0 ):instantiate("addr") )
local addr = systolicModule:add( fpgamodules.regBy( types.uint(16), fpgamodules.incIfWrap( types.uint(16), (w/T)-1), true, nil, 0 ):instantiate("addr") )

local outarray = {}
local evicted
Expand Down Expand Up @@ -2804,10 +2800,11 @@ end)
-- if nilhandshake is false or nil, and f input type is nil, we produce type nil->Handshake(A)
-- Handshake(nil) provides a ready bit but no data, vs nil, which provides nothing.
-- (nilhandshake also applies the same way to the output type)
modules.makeHandshake = memoize(function( f, tmuxRates, nilhandshake )
modules.makeHandshake = memoize(function( f, tmuxRates, nilhandshake, X )
assert( rigel.isFunction(f) )
if nilhandshake==nil then nilhandshake=false end
err( type(nilhandshake)=="boolean", "makeHandshake: nilhandshake must be nil or boolean")
assert( X==nil )

local res = { kind="makeHandshake", fn = f, tmuxRates = tmuxRates }

Expand All @@ -2818,15 +2815,7 @@ modules.makeHandshake = memoize(function( f, tmuxRates, nilhandshake )
res.outputType = rigel.HandshakeTmuxed (f.outputType, #tmuxRates )
assert( SDFRate.isSDFRate(tmuxRates) )
res.sdfInput, res.sdfOutput = SDF(tmuxRates), SDF(tmuxRates)

-- function res:sdfTransfer( I, loc )
-- err(#I[1]==#tmuxRates, "MakeHandshake: incorrect number of input streams. Is "..(#I[1]).." but expected "..(#tmuxRates) )
-- return I
-- end

else
--rigel.expectBasic(f.inputType)
--rigel.expectBasic(f.outputType)
err( types.isBasic(f.inputType) or f.inputType:is("StaticFramed"),"makeHandshake: fn input type should be basic or StaticFramed")
err( types.isBasic(f.outputType) or f.outputType:is("StaticFramed"),"makeHandshake: fn output type should be basic or StaticFramed")

Expand Down Expand Up @@ -2862,7 +2851,7 @@ modules.makeHandshake = memoize(function( f, tmuxRates, nilhandshake )
end

res.stateful = true -- for the shift register of valid bits
res.name = "MakeHandshake_HST_"..tostring(nilhandshake).."_"..f.name
res.name = J.sanitize("MakeHandshake_HST_"..tostring(nilhandshake).."_"..f.name)

res.globals={}
for k,_ in pairs(f.globals) do res.globals[k]=1 end
Expand All @@ -2884,7 +2873,7 @@ modules.makeHandshake = memoize(function( f, tmuxRates, nilhandshake )

local SRdefault = false
if tmuxRates~=nil then SRdefault = #tmuxRates end
local SR = systolicModule:add( fpgamodules.shiftRegister( rigel.extractValid(res.inputType), f.systolicModule:getDelay("process"), SRdefault, true ):instantiate("validBitDelay_"..f.systolicModule.name) )
local SR = systolicModule:add( fpgamodules.shiftRegister( rigel.extractValid(res.inputType), f.systolicModule:getDelay("process"), SRdefault, true ):instantiate( J.sanitize("validBitDelay_"..f.systolicModule.name) ) )
local inner = systolicModule:add(f.systolicModule:instantiate("inner"))
local pinp = S.parameter("process_input", rigel.lower(res.inputType) )
local rst = S.parameter("reset",types.bool())
Expand Down Expand Up @@ -4518,15 +4507,15 @@ modules.constSeqInner = memoize(function( value, A, w, h, T, X )
err( W == math.floor(W), "constSeq T must divide array size")
res.outputType = types.array2d(A,W,h)
res.stateful = true
--if T==1 then res.stateful=false end

res.sdfInput, res.sdfOutput = SDF{1,1}, SDF{1,1} -- well, technically this produces 1 output for every (nil) input

-- TODO: FIX: replace this with an actual hash function... it seems likely this can lead to collisions
local vh = J.to_string(value)
if #vh>100 then vh = string.sub(vh,0,100) end

-- some different types can have the same lua array representation (i.e. different array shapes), so we need to include both
res.name = verilogSanitize("constSeq_"..tostring(A).."_"..vh.."_T"..tostring(1/T).."_w"..tostring(w).."_h"..tostring(h))
res.name = verilogSanitize("constSeq_"..tostring(A).."_"..tostring(vh).."_T"..tostring(1/T).."_w"..tostring(w).."_h"..tostring(h))
res.delay = 0

if terralib~=nil then res.terraModule = MT.constSeq(res, value, A, w, h, T,W ) end
Expand Down Expand Up @@ -4611,7 +4600,7 @@ modules.fwriteSeq = memoize(function( filename, ty, filenameVerilog, passthrough
function res.makeSystolic()
local systolicModule = Ssugar.moduleConstructor(res.name)

local sfile = systolicModule:add( S.module.file( filenameVerilog, ty, true, passthrough ):instantiate("fwritefile") )
local sfile = systolicModule:add( S.module.file( filenameVerilog, ty, true, passthrough, false ):instantiate("fwritefile") )

local printInst
if DARKROOM_VERBOSE then printInst = systolicModule:add( S.module.print( ty, "fwrite O %h", true):instantiate("printInst") ) end
Expand Down
63 changes: 61 additions & 2 deletions src/fpgamodules.lua
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ modules.fifo = memoize(function(ty,items,verbose,nostall)
local fifo = Ssugar.moduleConstructor( J.sanitize("fifo_"..tostring(ty).."_"..items.."_nostall"..tostring(nostall)) )
-- writeAddr, readAddr hold the address we will read/write from NEXT time we do a read/write
local addrBits = (math.ceil(math.log(items)/math.log(2)))+1 -- the +1 is so that we can disambiguate wraparoudn
local writeAddr = fifo:add( systolic.module.regBy( types.uint(addrBits), modules.incIfWrap(types.uint(addrBits),items-1), true,nil,0 ):instantiate("writeAddr"))
local readAddr = fifo:add( systolic.module.regBy( types.uint(addrBits), modules.incIfWrap(types.uint(addrBits),items-1), true,nil,0 ):instantiate("readAddr"))
local writeAddr = fifo:add( modules.regBy( types.uint(addrBits), modules.incIfWrap(types.uint(addrBits),items-1), true,nil,0 ):instantiate("writeAddr"))
local readAddr = fifo:add( modules.regBy( types.uint(addrBits), modules.incIfWrap(types.uint(addrBits),items-1), true,nil,0 ):instantiate("readAddr"))
local bits = ty:verilogBits()
local bytes = bits/8
bytes = math.ceil(bytes) -- bits may not be byte aligned
Expand Down Expand Up @@ -924,4 +924,63 @@ function modules.div(ty)
return divMod
end

modules.regBy = memoize(function( ty, setby, CE, init, resetValue, hasSet, X)
err( types.isType(ty), "systolic.module.regBy, type must be type" )
assert( systolic.isModule(setby) )
assert( setby:getDelay( "process" ) == 0 )
assert( CE==nil or type(CE)=="boolean" )
if init~=nil then ty:checkLuaValue(init) end
if resetValue~=nil then ty:checkLuaValue(resetValue) end
if hasSet==nil then hasSet=false end
err( type(hasSet)=="boolean", "systolic.module.regBy: hasSet must be boolean but is "..tostring(hasSet))
assert(X==nil)

local R = systolic.module.reg( ty, CE, init, nil, resetValue ):instantiate("R")
local inner = setby:instantiate("regby_inner")
local fns = {}
fns.get = systolic.lambda("get", systolic.parameter("getinp",types.null()), R:get(), "GET_OUTPUT" )

-- check setby type
--err(#setby.functions==1, "regBy setby module should only have process function")
assert(setby.functions.process:isPure())
local setbytype = setby:lookupFunction("process"):getInput().type
assert(setbytype:isTuple())
local setbyTypeA = setbytype.list[1]
local setbyTypeB = setbytype.list[2]
err( setbyTypeA==ty, "regby type does not match type on setby function" )

local CEVar
if CE then CEVar = systolic.CE("CE") end

-- if we include the set function, and both set and setBy are called in the same cycle, set gets prescedence
local sinp, setvalid
if hasSet then
sinp = systolic.parameter("set_inp",ty)
setvalid = systolic.parameter("set_valid",types.bool())
fns.set = systolic.lambda("set", sinp, nil, "SET_OUTPUT",{}, setvalid, CEVar )
end

local sbinp = systolic.parameter("setby_inp",setbyTypeB)
local setbyvalidparam = systolic.parameter("setby_valid",types.bool())
local setbyvalid = setbyvalidparam
local setbyout = inner:process(systolic.tuple{R:get(),sbinp},systolic.null(),CEVar)

if hasSet then
setbyvalid = systolic.__or(setbyvalid,setvalid)
setbyout = systolic.select(setvalid,sinp,setbyout)
end

fns.setBy = systolic.lambda("setby", sbinp, setbyout, "SETBY_OUTPUT",{R:set(setbyout,setbyvalid,CEVar)}, setbyvalidparam, CEVar )

if resetValue~=nil then
local resetvalid = systolic.parameter("reset_valid",types.bool())
fns.reset = systolic.lambda("reset", systolic.parameter("reset_input",types.null()), R:reset(nil,resetvalid), "RESET_OUTPUT",{}, resetvalid )
end

local name = J.sanitize("RegBy_"..setby.name.."_CE"..tostring(CE).."_init"..tostring(init).."_reset"..tostring(resetValue))
local M = systolic.module.new( name, fns, {R,inner}, true, nil,nil,{get=0,reset=0,setBy=0,set=0} )
assert(systolic.isModule(M))
return M
end)

return modules

0 comments on commit 2a8d953

Please sign in to comment.