Skip to content

Commit

Permalink
fix simulation error
Browse files Browse the repository at this point in the history
  • Loading branch information
tomcl committed Nov 13, 2020
1 parent a8e1906 commit 7c1d966
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 21 deletions.
8 changes: 4 additions & 4 deletions src/Renderer/UI/SimulationView.fs
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ let private viewSimulationInputs
let newBit = match bit with
| Zero -> One
| One -> Zero
feedSimulationInput simulationGraph
(ComponentId inputId) [newBit]
(fst <| feedSimulationInput simulationGraph
(ComponentId inputId) [newBit])
|> SetSimulationGraph |> dispatch
)
] [ str <| bitToString bit ]
Expand All @@ -156,8 +156,8 @@ let private viewSimulationInputs
// Close simulation notifications.
CloseSimulationNotification |> dispatch
// Feed input.
feedSimulationInput simulationGraph
(ComponentId inputId) bits
(fst <| feedSimulationInput simulationGraph
(ComponentId inputId) bits)
|> SetSimulationGraph |> dispatch
))
]
Expand Down
2 changes: 1 addition & 1 deletion src/Simulator/DependencyMerger.fs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ let private makeCustomReducer
graphInputs
|> List.find (fun (_, ComponentLabel inpLabel, _) ->
inpLabel = inputLabel)
feedSimulationInput graph inputId wireData
fst <| feedSimulationInput graph inputId wireData
)
let outputs =
extractOutputValuesAsMap graph graphOutputs outputLabels
Expand Down
117 changes: 101 additions & 16 deletions src/Simulator/Runner.fs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ open Helpers
open SimulatorTypes
open SynchronousUtils

let mutable simTrace = None
let mutable simTrace = None //Some ["adder40";"4bitbusmux20";"dff430"]

// During simulation, a Component Reducer function will produce the output only
// when all of the expected inputs have a value. Once this happens, it will
Expand Down Expand Up @@ -45,16 +45,23 @@ let traceReduction action (comp:SimulationComponent) (reducerInput:ReducerInput)
action (shortPSComp comp) reducerOutput.Outputs reducerInput.Inputs reducerOutput.NewState
| _ -> ()


let makeProp comp outputMap =
Map.toList outputMap
|> List.map (fun (oNumb,wireDat) -> comp.Id,oNumb)
|> Set

/// Take the Input, and feed it to the Component with the specified Id.
/// This function should be used to feed combinational logic inputs, not to
/// trigger a clock tick.
/// If the Component is then ready to produce an output, propagate this output
/// by recursively feeding it as an input to the connected Components.
let rec private feedInput
(withStats: bool)
(graph : SimulationGraph)
(compId : ComponentId)
(input : InputPortNumber * WireData)
: SimulationGraph =
: SimulationGraph * Set<ComponentId*OutputPortNumber> =
// Extract component.
let comp = match graph.TryFind compId with
| None -> failwithf "what? Could not find component %A in simulationStep" compId
Expand Down Expand Up @@ -87,7 +94,7 @@ let rec private feedInput
traceReduction "comb-feedin" comp reducerInput reducerOutput

match reducerOutput.Outputs with
| None -> graph // Keep on waiting for more inputs.
| None -> graph, Set.empty // Keep on waiting for more inputs.
| Some outputMap ->
// Received enough inputs and produced an output.

Expand All @@ -96,36 +103,104 @@ let rec private feedInput
let diffedOutputMap = diffReducerInputsOrOutputs outputMap oldOutputMap

// Propagate each output produced.
let graph = feedReducerOutput comp graph diffedOutputMap
let graph, compset = feedReducerOutput withStats comp graph diffedOutputMap
// Update the CustomSimulationGraph and return the new simulation graph.
let comp = { comp with CustomSimulationGraph = reducerOutput.NewCustomSimulationGraph }
graph.Add (comp.Id, comp)
graph.Add (comp.Id, comp), if withStats then Set.union (makeProp comp diffedOutputMap) compset else Set.empty

/// Propagate each output produced by a simulation component to all the
/// components connected to its output ports.
/// Return the updated simulationGraph.
and private feedReducerOutput
(withStats: bool)
(comp : SimulationComponent)
(graph : SimulationGraph)
(outputMap : Map<OutputPortNumber, WireData>)
: SimulationGraph =
(graph, outputMap) ||> Map.fold (fun graph outPortNumber wireData ->
: SimulationGraph * Set<ComponentId*OutputPortNumber> =
((graph,Set.empty), outputMap) ||> Map.fold (fun (graph,compset) outPortNumber wireData ->
match comp.Outputs.TryFind outPortNumber with
| None when comp.Type = IOLabel -> graph // special case, these components can generate output that is connected to nothing!
| None when comp.Type = IOLabel -> graph, Set.empty // special case, these components can generate output that is connected to nothing!
| None -> failwithf "what? Reducer produced inexistent output portNumber %A in component %A" outPortNumber comp
| Some targets ->
let lookup (cid,pNum) = graph.[cid].Label,pNum
//printfn "\tComb outputs fed to -> %A" (List.map lookup targets)
// Trigger simulation step with the newly produced input in
// every target.
(graph, targets) ||> List.fold (fun graph (nextCompId, nextPortNumber) ->
feedInput graph nextCompId (nextPortNumber, wireData)
((graph,compset), targets) ||> List.fold (fun (graph,compset) (nextCompId, nextPortNumber) ->
let graph, compset' = feedInput withStats graph nextCompId (nextPortNumber, wireData)
graph, if withStats then Set.union compset' compset else Set.empty
)
)


let clockedComps (graph:SimulationGraph) =
graph
|> Map.toArray
|> Array.filter (fun (_,comp) -> couldBeSynchronousComponent comp.Type)
|> Array.sortBy (fun (cid,comp) -> match comp.Type with Custom _ -> 1 | _ -> 0)

let calculateStateChanges (graph : SimulationGraph) : SimulationGraph * OutputChange list =
let clockedCompsBeforeTick = clockedComps graph
// For each clocked component, feed the clock tick together with the inputs
// snapshotted just before the clock tick.
((graph,[]), clockedCompsBeforeTick) ||> Array.fold (fun (graph,changes) (compId,comp) ->
let reducerInput = {
Inputs = comp.Inputs
CustomSimulationGraph = comp.CustomSimulationGraph
IsClockTick = Yes comp.State
}
// comp>Reducer recursively calls feedClockTick (and hence calculateStateChanges) if comp is a custom component
// in that case the recursive call does all the result of internal state change
// subgraph update for the Tick - propagateStateChanges will not do that
// The change in the subgraph is Ok here because it does not affect the evaluation of any other components at this
// level until the output changes are propagated.
// Note that the subgraphs may still need later changes as a result of the delayed processing of higher-level
// output changes. This change propagation must go through the whole design including subsheets again!
let reducerTickOutput = comp.Reducer reducerInput
traceReduction (sprintf "clockTick %A" reducerInput.IsClockTick) comp reducerInput reducerTickOutput

match reducerTickOutput.Outputs with
| None -> failwithf "what? A clocked component should ALWAYS produce outputs after a clock tick: %A" comp
| Some outputMap ->
// Note that updating the CustomSimulationGraph is necessary since
// we may be dealing with custom clocked components, which means
// the feedClockTick operaion changes the graph of that custom
// component.
let comp = { comp with CustomSimulationGraph = reducerTickOutput.NewCustomSimulationGraph
State = reducerTickOutput.NewState }
let change = {CComp = comp; COutputs = outputMap}
Map.add comp.Id comp graph, (change :: changes)
// Feed the newly produced outputs into the combinational logic.
)

let propagateStateChanges (graph : SimulationGraph) (changes: OutputChange list) : SimulationGraph * Set<ComponentId*OutputPortNumber> =
// For each output change recorded in changes, update graph as follows
// Update the inputs driven by the changed wires
// Recursively propagate changes through graph
// record outputs changed and do not propagate chnages that have already touched as result of propagation
((graph,Set.empty), changes) ||> List.fold (fun (graph,compset) (change) ->
let comp = change.CComp

let outputMap =
change.COutputs
|> Map.filter (fun outPNum wData -> not <| Set.contains (comp.Id,outPNum) compset)
if simTrace <> None then
printfn "|prop|----> %A (%A)" comp.Label outputMap
// Note that here we update component inputs in the graph as we propagate changes.
// component inputs in comp are not uptodate, but this does not matter, they are not used
let graph, compset' = feedReducerOutput true comp graph outputMap
graph, Set.union compset compset'
)

let feedClockTick (graph : SimulationGraph) : SimulationGraph =
calculateStateChanges graph
||> propagateStateChanges
|> fst

(*
/// Send one global clock tick to all clocked components, and return the updated
/// simulationGraph.
let feedClockTick (graph : SimulationGraph) : SimulationGraph =
let feedClockTickOld (graph : SimulationGraph) : SimulationGraph =
// Take a snapshot of each clocked component with its inputs just before the
// clock tick.
let clockedCompsBeforeTick =
Expand All @@ -141,8 +216,18 @@ let feedClockTick (graph : SimulationGraph) : SimulationGraph =
CustomSimulationGraph = comp.CustomSimulationGraph
IsClockTick = Yes comp.State
}
let reducerTickOutput = comp.Reducer reducerInput
let comp = match graph.TryFind comp.Id with
| None -> failwith "what? Impossible case in feedClockTick"
| Some comp -> comp
let reducerInput = {
Inputs = comp.Inputs
CustomSimulationGraph = comp.CustomSimulationGraph
IsClockTick = No
}
let reducerOutput = comp.Reducer reducerInput
traceReduction (sprintf "clockTick %A" reducerInput.IsClockTick) comp reducerInput reducerOutput
match reducerOutput.Outputs with
| None -> failwithf "what? A clocked component should ALWAYS produce outputs after a clock tick: %A" comp
| Some outputMap ->
Expand Down Expand Up @@ -170,12 +255,12 @@ let feedClockTick (graph : SimulationGraph) : SimulationGraph =
let graph = graph.Add (comp.Id, comp)
// Feed the newly produced outputs into the combinational logic.
feedReducerOutput comp graph outputMap
)
) *)

/// Feed zero to a simulation input.
/// This function is supposed to be used with Components of type Input.
let feedSimulationInput graph inputId wireData =
feedInput graph inputId (InputPortNumber 0, wireData)
feedInput false graph inputId (InputPortNumber 0, wireData)

/// Feed in constant outputs so that they propagated to things connected to them
/// This function is supposed to be used with Components of type Constant
Expand All @@ -194,7 +279,7 @@ let rec feedSimulationConstants (graph:SimulationGraph) =
let feedConstant graph (comp:SimulationComponent) =
match comp.Type with
| Constant _ ->
feedReducerOutput comp graph (Map.ofList [OutputPortNumber 0, getWireData comp])
fst <| feedReducerOutput false comp graph (Map.ofList [OutputPortNumber 0, getWireData comp])
| Custom cComp ->
Option.map feedSimulationConstants comp.CustomSimulationGraph
|> (fun graphOpt -> {comp with CustomSimulationGraph = graphOpt})
Expand All @@ -216,7 +301,7 @@ let InitialiseGraphWithZeros
// Feed zero to all simulation inputs.
(graph, inputIds) ||> List.fold (fun graph (inputId, _, width) ->
let data = List.replicate width Zero
feedSimulationInput graph inputId data
fst <| feedSimulationInput graph inputId data
)
|> feedSimulationConstants

Expand Down
7 changes: 7 additions & 0 deletions src/Simulator/SimulatorTypes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type IsClockTick =
| No
| Yes of SimulationComponentState // Pass the state only for clock ticks.


/// Like Component but with additional dynamic info used by simulator
/// Clocked components have state data.
/// All components have optional data on inputs that propagates
Expand Down Expand Up @@ -93,6 +94,12 @@ and ReducerOutput = {
NewState: SimulationComponentState // Will be saved only after clock ticks.
}

/// contains info needed to propagate wire value changes through a simulation.
and OutputChange = {
CComp: SimulationComponent
COutputs: Map<OutputPortNumber, WireData>
}

/// For every IO node, keep track of its Id, Label and wire width.
/// - Id: to feed values into the simulationGraph.
/// - Label: to display a nice form to the user.
Expand Down

0 comments on commit 7c1d966

Please sign in to comment.