/*
JPC: An x86 PC Hardware Emulator for a pure Java Virtual Machine
Release Version 2.4
A project from the Physics Dept, The University of Oxford
Copyright (C) 2007-2010 The University of Oxford
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as published by
the Free Software Foundation.
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; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Details (including contact information) can be found at:
jpc.sourceforge.net
or the developer website
sourceforge.net/projects/jpc/
Conceived and Developed by:
Rhys Newman, Ian Preston, Chris Dennis
End of licence header
*/
package org.jpc.debugger;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import org.jpc.debugger.util.*;
import org.jpc.emulator.memory.AddressSpace;
public class MemoryViewPanel extends JPanel
{
private JTable memoryBlockTable;
private AddressSpace memory;
private int tableSize;
protected int startAddress;
private MemoryTableModel model;
private boolean rowReversed;
private static Font f = new Font("Monospaced", Font.PLAIN, 12);
public MemoryViewPanel()
{
this(0);
}
public MemoryViewPanel(int initialAddress)
{
super(new BorderLayout());
this.memory = null;
startAddress = initialAddress;
tableSize = 0;
rowReversed = false;
model = new MemoryTableModel();
memoryBlockTable = new JTable(model);
memoryBlockTable.setRowHeight(18);
model.setupColumnWidths(memoryBlockTable);
memoryBlockTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
ValidatingTextField hex = new ValidatingTextField("0123456789abcdefABCDEF", '0', 8);
hex.setHorizontalAlignment(JLabel.LEFT);
hex.setFont(f);
memoryBlockTable.setDefaultRenderer(Object.class, new CellRenderer());
memoryBlockTable.setDefaultEditor(Object.class, new DefaultCellEditor(hex));
add("Center", new JScrollPane(memoryBlockTable));
}
public void setCellRenderer(TableCellRenderer cr)
{
memoryBlockTable.setDefaultRenderer(Object.class, cr);
memoryBlockTable.repaint();
}
public void refresh()
{
refresh(memory);
}
public void refresh(AddressSpace memory)
{
this.memory = memory;
if (memory == null)
tableSize = 0;
else
tableSize = AddressSpace.BLOCK_SIZE;
model.fireTableDataChanged();
}
protected Object formatMemoryDisplay(int address)
{
StringBuffer buf = new StringBuffer();
for (int i=0; i<4; i++)
{
int val = memory.getByte(address+i);
buf.append(zeroPadHex(0xFF & val, 2));
}
return buf;
}
protected Object formatAsciiDisplay(int address)
{
StringBuffer buffer = new StringBuffer();
for (int i=0; i<16; i++)
{
byte b = memory.getByte(address + i);
buffer.append(getASCII(b));
}
return buffer;
}
class MemoryTableModel extends BasicTableModel
{
MemoryTableModel()
{
super(new String[]{"Absolute Address", "0-3", "4-7", "8-B", "C-F", "ASCII"}, new int[]{100, 80, 80, 80, 80, 140});
}
public int getRowCount()
{
return tableSize / 16;
}
public Object getValueAt(int row, int column)
{
if (memory == null)
return null;
if (rowReversed)
row = getRowCount() - row - 1;
int index = row * 16 + startAddress;
switch (column)
{
case 0:
return zeroPadHex(index, 8);
case 5:
return formatAsciiDisplay(index);
default:
int address = index + (column - 1)*4;
return formatMemoryDisplay(address);
}
}
public boolean isCellEditable(int rowIndex, int columnIndex)
{
return (columnIndex > 0) && (columnIndex < 5);
}
public void setValueAt(Object obj, int row, int column)
{
if (memory == null)
return;
if (rowReversed)
row = getRowCount() - row - 1;
int address = 16 * row + (column - 1)*4 + startAddress;
try
{
StringBuffer buf = new StringBuffer(obj.toString());
while (buf.length() < 8)
buf.append('0');
long value = Long.parseLong(buf.toString(), 16);
for (int i=0; i<4; i++)
memory.setByte(address+i, (byte) (value >> (24 - 8*i)));
}
catch (Exception e) {}
JPC.getInstance().refresh();
}
}
public static class CellRenderer extends DefaultTableCellRenderer
{
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setFont(f);
setHorizontalAlignment(JLabel.LEFT);
if (column == 0)
{
setBackground(Color.pink);
setForeground(Color.blue);
}
else if (column == 5)
{
setBackground(Color.white);
setForeground(Color.blue);
}
else
{
setBackground(Color.white);
setForeground(Color.black);
}
return this;
}
}
public void setViewLimits(AddressSpace memory, int address, int limit)
{
startAddress = address;
tableSize = Math.max(limit, 16);
refresh(memory);
}
public void setCurrentAddress(AddressSpace memory, int address)
{
startAddress = address;
refresh(memory);
}
public void setTableSize(AddressSpace memory, int size)
{
tableSize = Math.max(size, 16);
refresh(memory);
}
public void setRowReversed(boolean value)
{
rowReversed = value;
refresh();
}
public static String zeroPadHex(int value, int size)
{
StringBuffer result = new StringBuffer(Integer.toHexString(value).toUpperCase());
while (result.length() < size)
result.insert(0, '0');
return result.toString();
}
public static char getASCII(byte b)
{
if ((b >= 32) && (b < 127))
return (char) b;
return ' ';
}
}