/*******************************************************************************
* openDLX - A DLX/MIPS processor simulator.
* Copyright (C) 2013 The openDLX project, University of Augsburg, Germany
* Project URL: <https://sourceforge.net/projects/opendlx>
* Development branch: <https://github.com/smetzlaff/openDLX>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program, see <LICENSE>. If not, see
* <http://www.gnu.org/licenses/>.
******************************************************************************/
package openDLX.gui.internalframes.concreteframes;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.util.ArrayList;
import java.util.HashMap;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import openDLX.OpenDLXSimulator;
import openDLX.asm.DLXAssembler;
import openDLX.datatypes.uint32;
import openDLX.exception.MemoryException;
import openDLX.gui.GUI_CONST;
import openDLX.gui.MainFrame;
import openDLX.gui.internalframes.OpenDLXSimInternalFrame;
import openDLX.gui.internalframes.renderer.ClockCycleFrameTableCellRenderer;
import openDLX.gui.internalframes.util.NotSelectableTableModel;
import openDLX.util.ClockCycleLog;
@SuppressWarnings("serial")
public final class ClockCycleFrame extends OpenDLXSimInternalFrame implements GUI_CONST
{
private final OpenDLXSimulator openDLXSim;
//frame text
private final String addrHeaderText = "Address";
private final String instHeaderText = "Instructions/Cycles";
//default size values
private final int instructionNameMaxColWidth = 150;
private int block = 80;
//tables, scrollpane and table models
private JTable table, codeTable, addrTable;
private NotSelectableTableModel model, codeModel, addrModel;
private JScrollPane clockCycleScrollPane;
private JScrollPane addrScrollPane;
private JScrollPane codeScrollPane;
private JScrollBar clockCycleScrollBarVertical;
private JScrollBar addrScrollBar;
private JScrollBar codeScrollBar;
//private JScrollBar clockCycleScrollBarHorizontal;
public ClockCycleFrame(String title)
{
super(title, true);
openDLXSim = MainFrame.getInstance().getOpenDLXSim();
initialize();
}
@Override
public void initialize()
{
super.initialize();
setLayout(new BorderLayout());
//Code Table
codeModel = new NotSelectableTableModel();
codeTable = new JTable(codeModel);
codeTable.setFocusable(false);
codeTable.setShowGrid(false);
codeTable.getTableHeader().setReorderingAllowed(false);
codeTable.setShowHorizontalLines(true);
codeTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
codeModel.addColumn(instHeaderText);
TableColumnModel tcm = codeTable.getColumnModel();
tcm.getColumn(0).setMaxWidth(instructionNameMaxColWidth);
tcm.getColumn(0).setMinWidth(instructionNameMaxColWidth);
codeScrollPane = new JScrollPane(codeTable);
codeScrollPane.setPreferredSize(new Dimension(tcm.getColumn(0).getMaxWidth(),
codeScrollPane.getPreferredSize().height));
codeScrollBar = codeScrollPane.getVerticalScrollBar();
codeScrollBar.addAdjustmentListener(new AdjustmentListener()
{
@Override
public void adjustmentValueChanged(AdjustmentEvent e)
{
clockCycleScrollBarVertical.setValue(e.getValue());
addrScrollBar.setValue(e.getValue());
}
});
//Address Table
addrModel = new NotSelectableTableModel();
addrTable = new JTable(addrModel);
addrTable.setFocusable(false);
addrTable.setShowGrid(false);
addrTable.getTableHeader().setReorderingAllowed(false);
addrTable.setShowHorizontalLines(true);
addrTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
addrModel.addColumn(addrHeaderText);
TableColumnModel tcm2 = addrTable.getColumnModel();
tcm2.getColumn(0).setMaxWidth(instructionNameMaxColWidth);
tcm2.getColumn(0).setMinWidth(instructionNameMaxColWidth);
addrScrollPane = new JScrollPane(addrTable);
addrScrollPane.setPreferredSize(new Dimension(tcm2.getColumn(0).getMaxWidth(),
addrScrollPane.getPreferredSize().height));
addrScrollBar = addrScrollPane.getVerticalScrollBar();
addrScrollBar.addAdjustmentListener(new AdjustmentListener()
{
@Override
public void adjustmentValueChanged(AdjustmentEvent e)
{
clockCycleScrollBarVertical.setValue(e.getValue());
codeScrollBar.setValue(e.getValue());
}
});
//scroll pane and frame
clockCycleScrollPane = makeTableScrollPane();
add(addrScrollPane, BorderLayout.EAST);
add(codeScrollPane, BorderLayout.WEST);
add(clockCycleScrollPane, BorderLayout.CENTER);
pack();
setVisible(true);
}
private JScrollPane makeTableScrollPane()
{
//Clock Cycle Table
model = new NotSelectableTableModel();
table = new JTable(model);
table.setFocusable(false);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.getTableHeader().setReorderingAllowed(false);
table.setDefaultRenderer(Object.class, new ClockCycleFrameTableCellRenderer());
clockCycleScrollPane = new JScrollPane(table);
clockCycleScrollBarVertical = clockCycleScrollPane.getVerticalScrollBar();
clockCycleScrollBarVertical.addAdjustmentListener(new AdjustmentListener()
{
@Override
public void adjustmentValueChanged(AdjustmentEvent e)
{
addrScrollBar.setValue(e.getValue());
codeScrollBar.setValue(e.getValue());
}
});
// scrolling synchronously causes view violations
// requires a more complex/sophisticated approach
// clockCycleScrollBarHorizontal = clockCycleScrollPane.getHorizontalScrollBar();
/* clockCycleScrollBarHorizontal.addAdjustmentListener(new AdjustmentListener()
{
@Override
public void adjustmentValueChanged(AdjustmentEvent e)
{
clockCycleScrollBarVertical.setValue(e.getValue());
}
});*/
clockCycleScrollPane.setPreferredSize(new Dimension(3 * block,
clockCycleScrollPane.getPreferredSize().height));
return clockCycleScrollPane;
}
@Override
public void update()
{
//clear table
addrModel.setRowCount(0);
codeModel.setRowCount(0);
model.setColumnCount(0);
model.setRowCount(0);
DLXAssembler asm = new DLXAssembler();
int i = 0;
for (uint32 addr : ClockCycleLog.code)
{
try
{
uint32 inst = openDLXSim.getPipeline().getInstructionMemory().read_u32(addr);
String instStr = asm.Instr2Str(inst.getValue());
addrModel.addRow(new String[] { addr.getValueAsHexString() });
codeModel.addRow(new String[] { instStr });
model.addColumn(i);
model.addRow(new String[] { "" });
final HashMap<uint32, String> h = ClockCycleLog.log.get(i);
for (uint32 checkAddr : h.keySet())
{
final ArrayList<uint32> forbidden = new ArrayList<>();
for (int k = addrModel.getRowCount() - 1; k >= 0; --k)
{
if (addrModel.getValueAt(k, 0).equals(checkAddr.getValueAsHexString())
&& !forbidden.contains(checkAddr)
&& !instStr.contains("bubble"))
{
model.setValueAt(h.get(checkAddr), k, i);
forbidden.add(checkAddr);
}
}
}
++i;
}
catch (MemoryException e)
{
MainFrame.getInstance().getPipelineExceptionHandler().handlePipelineExceptions(e);
}
}
for (int j = 0; j < table.getColumnModel().getColumnCount(); ++j)
{
TableColumn column = table.getColumnModel().getColumn(j);
column.setMaxWidth(30);
column.setResizable(false);
}
// clockCycleScrollBarHorizontal.setValue(clockCycleScrollBarHorizontal.getMaximum());
table.scrollRectToVisible(table.getCellRect(table.getRowCount() - 1, table.getColumnCount() - 1, true));
codeTable.scrollRectToVisible(codeTable.getCellRect(table.getRowCount() - 1, 0, true));
addrTable.scrollRectToVisible(addrTable.getCellRect(addrTable.getRowCount() - 1, 0, true));
}
@Override
public void clean()
{
setVisible(false);
dispose();
}
}