OpenASIP 2.2
Loading...
Searching...
No Matches
OpsetDialog.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2021 Tampere University.
3
4 This file is part of TTA-Based Codesign Environment (TCE).
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
23 */
24/**
25 * @file OpsetDialog.cc
26 *
27 * Implementation of OpsetDialog class.
28 *
29 * @author Veli-Pekka Jääskeläinen 2006 (vjaaskel-no.spam-cs.tut.fi)
30 * @note rating: red
31 */
32
33#include "OpsetDialog.hh"
34
35#include <wx/spinctrl.h>
36#include <wx/statline.h>
37#include <wx/textctrl.h>
38
39#include <algorithm>
40#include <string>
41
42#include "AddressSpace.hh"
43#include "ErrorDialog.hh"
44#include "ExecutionPipeline.hh"
45#include "FUPort.hh"
46#include "FunctionUnit.hh"
47#include "HWOperation.hh"
48#include "MathTools.hh"
49#include "Operand.hh"
50#include "Operation.hh"
51#include "OperationIndex.hh"
52#include "OperationModule.hh"
53#include "OperationPool.hh"
54#include "WxConversion.hh"
55
56using namespace TTAMachine;
57
58BEGIN_EVENT_TABLE(OpsetDialog, wxDialog)
59 EVT_LISTBOX(ID_LIST, OpsetDialog::onSelectOperation)
61 EVT_TEXT(ID_OP_FILTER, OpsetDialog::onOperationFilterChange)
63
64/**
65 * The constructor.
66 *
67 * @param parent Parent window of the dialog.
68 */
69OpsetDialog::OpsetDialog(wxWindow* parent):
70 wxDialog(parent, -1, _T("Choose operation & latency"),
71 wxDefaultPosition),
72 latency_(1), operation_("") {
73
74 createContents(this, true, true);
75 operationList_ = dynamic_cast<wxListBox*>(FindWindow(ID_LIST));
76 FindWindow(wxID_OK)->Disable();
77}
78
79/**
80 * The Destructor.
81 */
84
85/**
86 * Transfers data to the opset list.
87 */
88bool
90
91 operationList_->Clear();
92
93 // Cleanup operation pool cache so new operations
94 // appear w/o restarting prode.
96 OperationPool pool;
97 OperationIndex& index = pool.index();
98 std::set<TCEString> opset;
99 for (int m = 0; m < index.moduleCount(); m++) {
100 OperationModule& module = index.module(m);
101 for (int i = 0; i < index.operationCount(module); i++) {
102 std::string opName = index.operationName(i, module);
103 if (opNameFilter_.empty()
104 || opName.find(opNameFilter_) != std::string::npos) {
105 opset.insert(opName);
106 }
107 }
108 }
109
110 for (const auto& opName : opset) {
112 }
113
114 return true;
115}
116
117/**
118 * Reads user choices from the dialog widgets.
119 */
120bool
122 latency_ = dynamic_cast<wxSpinCtrl*>(FindWindow(ID_LATENCY))->GetValue();
123 operation_ = WxConversion::toString(operationList_->GetStringSelection());
124 return true;
125}
126
127/**
128 * Event handler for the operation list selections.
129 *
130 * Enables and disables the OK button.
131 * Displays operation description and ports count.
132 */
133void
135 FindWindow(wxID_OK)->Enable(operationList_->GetSelection() != wxNOT_FOUND);
136
137 operation_ = WxConversion::toString(operationList_->GetStringSelection());
138
139 if (operation_ == "")
140 return;
141
142 wxString opDesc;
143 wxString inputCount;
144 wxString outputCount;
145 try {
146 OperationPool pool;
147 const Operation& op = pool.operation(operation_.c_str());
149 inputCount = WxConversion::toWxString(op.numberOfInputs());
150 outputCount = WxConversion::toWxString(op.numberOfOutputs());
151 } catch (Exception&) {
153 "Error in loading the operation description.");
154 inputCount = WxConversion::toWxString("N/A");
155 outputCount = WxConversion::toWxString("N/A");
156 }
157 // Set operation description
158 wxTextCtrl *opDescription = dynamic_cast<wxTextCtrl*>(
160 opDescription->Clear();
161 opDescription->AppendText(opDesc);
162 // Set inputs and outputs count
163 wxStaticText *inputsLabel = dynamic_cast<wxStaticText*>(
165 inputsLabel->SetLabel(wxT("Inputs: ") + inputCount);
166 wxStaticText *outputsLabel = dynamic_cast<wxStaticText*>(
168 outputsLabel->SetLabel(wxT("Outputs: ") + outputCount);
169}
170
171
172/**
173 * Event handler for the OK button.
174 */
175void
176OpsetDialog::onOK(wxCommandEvent&) {
177 if (operationList_->GetSelection() == wxNOT_FOUND) {
178 wxString message = _T("No operation selected.");
179 ErrorDialog dialog(this, message);
180 dialog.ShowModal();
181 return;
182 }
184 EndModal(wxID_OK);
185}
186
187
188/**
189 * Event handler for opset filtering.
190 */
191void
193 std::string pattern(event.GetString().mb_str());
194 std::string::iterator it;
195 it = std::remove_if(pattern.begin(), pattern.end(), [](const char& c) {
196 return c == ' ';
197 });
198 pattern.erase(it, pattern.end());
199 for (auto& c : pattern) c = toupper(c);
200 opNameFilter_ = pattern;
202}
203
204
205/**
206 * Creates a new HWOperation based on user choices.
207 *
208 * @param fu Parent function unit of the new operation.
209 * @return Pointer to the created operation.
210 */
213
214 // Check that the function unit doesn't already have an operation with
215 // the selected name.
216 if (fu.hasOperation(operation_)) {
217 wxString message = _T("Function unit already contains operation '");
218 message.Append(WxConversion::toWxString(operation_));
219 message.Append(_T("'."));
220 ErrorDialog dialog(this, message);
221 dialog.ShowModal();
222 return NULL;
223 }
224
225 OperationPool pool;
226 const Operation& op = pool.operation(operation_.c_str());
227
228 HWOperation* operation = new HWOperation(operation_, fu);
229
230 // Read operation operand information from the operation pool.
231 std::map<int, std::set<int> > inputs;
232 std::map<int, std::set<int> > outputs;
233 wxString opWidths;
234
235 PortMap inputPorts;
236 PortMap outputPorts;
237 PortMap unconnectedPorts;
238
239 for (int i = 1; i <= op.numberOfInputs() + op.numberOfOutputs(); i++) {
240 const Operand& oper = op.operand(i);
241 opWidths.Append(WxConversion::toWxString(oper.width()));
242
243 if (oper.isInput()) {
244 int opWidth;
245 if (oper.isAddress()) {
247 opWidth = MathTools::requiredBits(fu.addressSpace()->end());
248 } else {
249 opWidth = oper.width();
250 }
251 inputs[opWidth].insert(oper.index());
252 opWidths.Append(WxConversion::toWxString("b input, "));
253 operation->pipeline()->addPortRead(oper.index(), 0, 1);
254 } else if (oper.isOutput()) {
255 outputs[oper.width()].insert(oper.index());
256 opWidths.Append(WxConversion::toWxString("b output, "));
257 if (!inputs.empty()) {
258 // 0 and 1 latency means that the output operand is written
259 // on cycle 0.
260 int latency = (latency_ > 0) ? latency_ - 1 : latency_;
261 operation->pipeline()->addPortWrite(oper.index(), latency, 1);
262 }
263 }
264 }
265
266 opWidths.RemoveLast(2);
267 opWidths.Append(_T("."));
268
269 // Try to bind operation operands to function unit ports.
270 for (int i = 0; i < fu.operationPortCount(); i++) {
271 const FUPort* port = fu.operationPort(i);
272
273 if (port->inputSocket() != NULL || port->isTriggering()) {
274 inputPorts[port->width()].insert(port);
275 } else if (port->outputSocket() != NULL) {
276 outputPorts[port->width()].insert(port);
277 } else {
278 unconnectedPorts[port->width()].insert(port);
279 }
280 }
281
282 bool triggerBound = false;
283 triggerBound |= bindPorts(*operation, inputs, inputPorts, !inputs.empty());
284 bindPorts(*operation, outputs, outputPorts, false);
285
286 bindPorts(*operation, inputs, unconnectedPorts, false);
287 bindPorts(*operation, outputs, unconnectedPorts, false);
288
289 // Display an error dialog and abort if the operands couldn't be bound
290 // to ports.
291 if (!inputs.empty() || !outputs.empty()
292 || (!inputs.empty() && !triggerBound)) {
293 wxString message;
294 if (!inputs.empty() && !triggerBound) {
295 message.Append(
296 _T("Could not bind operand to the trigger port. "));
297 message.Append(
298 _T("It may be too narrow or missing?\n"));
299 }
300
301 if (!inputs.empty()) {
302 message.Append(
303 _T("Not enough (wide enough?) input ports for the operation "
304 "input operands.\n"));
305 }
306 if (!outputs.empty()) {
307 message.Append(
308 _T("Not enough (wide enough?) output ports for the operation "
309 "output operands.\n"));
310 }
311 message.Append(WxConversion::toWxString("\n" + operation_));
312 message.Append(_T(" needs a "));
313 message.Append(opWidths);
314 ErrorDialog dialog(this, message);
315 dialog.ShowModal();
316 delete operation;
317 return NULL;
318 }
319
320 return operation;
321}
322/**
323 * Binds ports to operands of an instruction.
324 *
325 * Tries to use sensible port widths, ie smallest allowed.
326 *
327 * @param operation HWOperation being constructed
328 * @param operands width-based map of all operands
329 * @param ports width-based map of all ports
330 * @param needsTrigger if trigger neeed to be bound.
331 * @return true if did bind trigger, false if did not.
332 */
334 std::map<int, std::set<int> >& operands,
335 PortMap& ports,
336 bool needsTrigger) {
337 bool triggerBound = false;
338 int triggerWidth = 0;
339 const FUPort* triggerPort = NULL;
340
341 if (needsTrigger) {
342 triggerPort = findTriggerPort(ports);
343 if (triggerPort) {
344 triggerWidth = triggerPort->width();
345 }
346 }
347
348 while (!operands.empty() && !ports.empty()) {
349 std::map<int, std::set<int> >::iterator j = operands.begin();
350 int width = j->first;
351 for (PortMap::iterator k = ports.begin();
352 k != ports.end();) {
353 if (k->first >= width) {
354 std::set<int>& operandsOfSize = j->second;
355 std::set<int>::iterator operandIter = operandsOfSize.begin();
356 if (needsTrigger
357 && triggerPort != nullptr
358 && width <= triggerWidth
359 && operandsOfSize.size() == 1) {
360 std::map<int, std::set<int> >::iterator next = j;
361 next++;
362 if (next==operands.end() || next->first > triggerWidth) {
363 operation.bindPort(*operandIter, *triggerPort);
364 operands.erase(j->first);
365 ports.erase(triggerWidth);
366 needsTrigger = false;
367 triggerBound = true;
368 break;
369 }
370 }
371 PortSet& portsOfSize = k->second;
372 // Take the last element of the set
373 PortSet::iterator portIter = portsOfSize.end();
374 portIter--;
375 const TTAMachine::FUPort* fuPort = *portIter;
376 operation.bindPort(*operandIter, *fuPort);
377 if (fuPort->isTriggering()) {
378 needsTrigger = false;
379 triggerBound = true;
380 }
381 operandsOfSize.erase(operandIter);
382 if (operandsOfSize.empty()) {
383 operands.erase(j->first);
384 }
385 portsOfSize.erase(portIter);
386 if (portsOfSize.empty()) {
387 ports.erase(k->first);
388 }
389 break;
390 } else {
391 // port sizes of this size are too small for all in the future
392 ports.erase(k++);
393 }
394 }
395 }
396 return triggerBound;
397}
398
399/**
400 * Finds the trigger port from map of function unit ports.
401 */
404 for (PortMap::iterator i = ports.begin(); i != ports.end(); i++) {
405 PortSet& portsOfSize = i->second;
406 for (PortSet::iterator j = portsOfSize.begin();
407 j != portsOfSize.end(); j++) {
408 const TTAMachine::FUPort* port = *j;
409 if (port->isTriggering()) {
410 return port;
411 }
412 }
413 }
414 return NULL;
415}
416
417/**
418 * Creates the dialog widgets.
419 *
420 * @param parent Parent window of the widgets.
421 */
422wxSizer*
423OpsetDialog::createContents(wxWindow *parent, bool call_fit, bool set_sizer) {
424
425 wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);
426 // Sizer for leftSizer and rightSizer
427 wxBoxSizer *upperSizer = new wxBoxSizer(wxHORIZONTAL);
428
429 // Sizer for oplistbox, filterlabel and filterinput
430 wxBoxSizer *leftSizer = new wxBoxSizer(wxVERTICAL);
431 // List of operations
432 wxListBox *opListBox = new wxListBox(parent, ID_LIST, wxDefaultPosition,
433 wxSize(210, 150), 0, NULL, wxLB_SINGLE|wxLB_SORT);
434 leftSizer->Add(opListBox, 0, wxEXPAND|wxALL, 5);
435
436 // Sizer for opNameFilterLabel and opNameFilter
437 wxBoxSizer *filterSizer = new wxBoxSizer(wxHORIZONTAL);
438 // TextLabel "Filter:"
439 wxStaticText *opNameFilterLabel = new wxStaticText(parent,
440 ID_OP_FILTER_LABEL, wxT("Filter:"), wxDefaultPosition, wxDefaultSize,
441 0);
442 // Operation filter input
443 wxTextCtrl *opNameFilter = new wxTextCtrl(parent, ID_OP_FILTER, wxT(""),
444 wxDefaultPosition, wxDefaultSize, 0);
445 filterSizer->Add(opNameFilterLabel, 0, 0);
446 filterSizer->Add(opNameFilter, 1, wxEXPAND);
447 leftSizer->Add(filterSizer, 0, wxEXPAND|wxALL, 5);
448
449 // Sizer for latencyLabel and latencySpinner
450 wxBoxSizer *latencySizer = new wxBoxSizer(wxHORIZONTAL);
451 // TextLabel "Latency"
452 wxStaticText *latencyLabel = new wxStaticText(parent, ID_TEXT,
453 wxT("Latency:"), wxDefaultPosition, wxDefaultSize, 0);
454 // Latency spinner
455 wxSpinCtrl *latencySpinner = new wxSpinCtrl(parent, ID_LATENCY, wxT("1"),
456 wxDefaultPosition, wxSize(-1,-1), 0, 1, 100, 1);
457 latencySizer->Add(latencyLabel, 1, 0);
458 latencySizer->Add(latencySpinner, 1);
459 leftSizer->Add(latencySizer, 0, wxEXPAND|wxALL, 5);
460
461 // Sizer for operation information
462 wxStaticBoxSizer *rightSizer = new wxStaticBoxSizer(wxVERTICAL, parent,
463 wxT("Operation description"));
464 // Selected operation description
465 wxTextCtrl *opDescription = new wxTextCtrl(parent, ID_OP_DESCRIPTION,
466 wxT(""), wxDefaultPosition, wxSize(210, -1),
467 wxTE_MULTILINE|wxTE_READONLY);
468
469 // Sizer for Inputs/Outputs
470 wxBoxSizer *insOutsSizer = new wxBoxSizer(wxHORIZONTAL);
471 // Output count label
472 wxStaticText *inputsLabel = new wxStaticText(parent, ID_OP_INPUTS,
473 wxT("Inputs:"), wxDefaultPosition, wxDefaultSize, 0);
474 // Outputs count label
475 wxStaticText *outputsLabel = new wxStaticText(parent, ID_OP_OUTPUTS,
476 wxT("Outputs: "), wxDefaultPosition, wxDefaultSize, 0);
477 insOutsSizer->Add(inputsLabel, 1);
478 insOutsSizer->Add(outputsLabel, 1);
479 rightSizer->Add(opDescription, 1, wxEXPAND|wxALL, 5);
480 rightSizer->Add(insOutsSizer, 0, wxEXPAND|wxALL, 5);
481
482 upperSizer->Add(leftSizer, 0, wxALL, 5);
483 upperSizer->Add(rightSizer, 1, wxEXPAND|wxALL, 5);
484
485 mainSizer->Add(upperSizer, 1, wxEXPAND);
486
487 // Static line
488 wxStaticLine *horisontalLine = new wxStaticLine(parent, ID_LINE,
489 wxDefaultPosition, wxSize(20,-1), wxLI_HORIZONTAL);
490 mainSizer->Add(horisontalLine, 0, wxEXPAND|wxALL, 5);
491
492 // Sizer for Cancel and OK buttons
493 wxBoxSizer *buttonsSizer = new wxBoxSizer(wxHORIZONTAL);
494 // Cancel button
495 wxButton *cancelButton = new wxButton(parent, wxID_CANCEL, wxT("&Cancel"),
496 wxDefaultPosition, wxDefaultSize, 0);
497 buttonsSizer->Add(cancelButton, 0, wxALIGN_CENTER|wxALL, 5);
498 // OK button
499 wxButton *okButton = new wxButton(parent, wxID_OK, wxT("&OK"),
500 wxDefaultPosition, wxDefaultSize, 0);
501 buttonsSizer->Add(okButton, 0, wxALIGN_CENTER|wxALL, 5);
502
503 mainSizer->Add(buttonsSizer, 0, 0, 5);
504
505 if (set_sizer) {
506 parent->SetSizer(mainSizer);
507 if (call_fit) {
508 mainSizer->SetSizeHints( parent );
509 }
510 }
511
512 return mainSizer;
513}
#define assert(condition)
END_EVENT_TABLE() using namespace IDF
EVT_BUTTON(ID_EDIT_ARCH_PORT, FUImplementationDialog::onEditArchitecturePort) EVT_BUTTON(ID_ADD_EXTERNAL_PORT
static int requiredBits(unsigned long int number)
virtual bool isAddress() const
Definition Operand.cc:328
virtual bool isInput() const
Definition Operand.cc:145
virtual bool isOutput() const
Definition Operand.cc:155
virtual int index() const
Definition Operand.cc:135
virtual int width() const
Definition Operand.cc:318
std::string operationName(int i, const OperationModule &om)
int operationCount(const OperationModule &om)
int moduleCount() const
static void cleanupCache()
virtual TCEString description() const
Definition Operation.cc:103
virtual int numberOfInputs() const
Definition Operation.cc:192
virtual int numberOfOutputs() const
Definition Operation.cc:202
virtual Operand & operand(int id) const
Definition Operation.cc:541
std::map< int, PortSet > PortMap
std::set< const TTAMachine::FUPort *, TTAMachine::MachinePart::Comparator > PortSet
wxListBox * operationList_
Operation list widget.
const TTAMachine::FUPort * findTriggerPort(PortMap &ports)
void onOperationFilterChange(wxCommandEvent &event)
wxSizer * createContents(wxWindow *parent, bool call_fit, bool set_sizer)
virtual bool TransferDataFromWindow()
virtual bool TransferDataToWindow()
TCEString operation_
Name of the selected operation.
std::string opNameFilter_
A string to filter opset list.
TTAMachine::HWOperation * createOperation(TTAMachine::FunctionUnit &fu)
void onOK(wxCommandEvent &event)
virtual ~OpsetDialog()
bool bindPorts(TTAMachine::HWOperation &operation, std::map< int, std::set< int > > &operands, PortMap &ports, bool needsTrigger)
void onSelectOperation(wxCommandEvent &event)
int latency_
Chosen latency.
virtual ULongWord end() const
virtual int width() const
void addPortRead(int operand, int start, int duration)
void addPortWrite(int operand, int start, int duration)
virtual bool isTriggering() const
Definition FUPort.cc:182
virtual AddressSpace * addressSpace() const
virtual FUPort * operationPort(const std::string &name) const
virtual bool hasOperation(const std::string &name) const
virtual int operationPortCount() const
virtual bool hasAddressSpace() const
ExecutionPipeline * pipeline() const
virtual void bindPort(int operand, const FUPort &port)
virtual Socket * outputSocket() const
Definition Port.cc:281
virtual Socket * inputSocket() const
Definition Port.cc:261
static wxString toWxString(const std::string &source)
static std::string toString(const wxString &source)