Step Count and Memory Window enhancements

Introduces several changes requested by Mario Keller. The simulator now has a variable step count that can be selected by a drop-down box on the main window. This change also displays ASCII characters in the Memory window.
This commit is contained in:
Seth Morabito 2013-03-30 21:28:52 -07:00
parent 2835deb00f
commit 6a50476bfe
10 changed files with 235 additions and 110 deletions

View File

@ -1,12 +1,11 @@
SYMON - A 6502 System Simulator
===============================
**NOTE: THIS IS BETA QUALITY SOFTWARE UNDER ACTIVE DEVELOPMENT. Feedback is
welcome!**
**NOTE: THIS SOFTWARE IS UNDER ACTIVE DEVELOPMENT. Feedback is welcome!**
**Version:** 0.8.4
**Version:** 0.8.5
**Last Updated:** 4 March, 2013
**Last Updated:** 30 March, 2013
Copyright (c) 2008-2013 Seth J. Morabito <web@loomcom.com>
@ -98,7 +97,7 @@ Maven will build Symon, run unit tests, and produce a jar file in the
Symon is meant to be invoked directly from the jar file. To run with
Java 1.5 or greater, just type:
$ java -jar symon-0.8.4.jar
$ java -jar symon-0.8.5.jar
When Symon is running, you should be presented with a simple graphical
interface.
@ -140,6 +139,9 @@ running.
## 5.0 Revision History
- **0.8.5:** 30 March, 2013 - ASCII display for memory window.
Allows user to select a step count from a drop-down box.
- **0.8.4:** 4 March, 2013 - Fix for ZPX, ZPY display in the trace log
(change contributed by jsissom)
@ -169,7 +171,7 @@ running.
- Feedback (in the form of dialogs, status bar, etc).
- Better debugging tools from the UI, including breakpoints
and disassebly.
and disassembly.
- More accurate timing.

View File

@ -4,7 +4,7 @@
<groupId>com.loomcom.symon</groupId>
<artifactId>symon</artifactId>
<packaging>jar</packaging>
<version>0.8.4</version>
<version>0.8.5</version>
<name>symon</name>
<url>http://www.loomcom.com/symon</url>
<properties>
@ -38,7 +38,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -29,16 +29,12 @@ public interface Preferences {
public static final int DEFAULT_PROGRAM_LOAD_ADDRESS = 0x0300;
public static final int DEFAULT_BORDER_WIDTH = 10;
public static final boolean DEFAULT_HALT_ON_BREAK = true;
public JDialog getDialog();
public int getProgramStartAddress();
public int getBorderWidth();
public boolean getHaltOnBreak();
public void updateUi();

View File

@ -37,6 +37,8 @@ import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.util.Observable;
import java.util.Observer;
@ -51,7 +53,7 @@ import java.util.logging.Logger;
* and a simulated ACIA for serial I/O. The ACIA is attached to a dumb terminal
* with a basic 80x25 character display.
*/
public class Simulator implements Observer {
public class Simulator {
// Constants used by the simulated system. These define the memory map.
private static final int BUS_BOTTOM = 0x0000;
@ -71,8 +73,10 @@ public class Simulator implements Observer {
private static final int ROM_BASE = 0xC000;
private static final int ROM_SIZE = 0x4000;
private static final int DEFAULT_FONT_SIZE = 12;
private static final Font DEFAULT_FONT = new Font(Font.MONOSPACED, Font.PLAIN, DEFAULT_FONT_SIZE);
// UI constants
private static final int DEFAULT_FONT_SIZE = 12;
private static final Font DEFAULT_FONT = new Font(Font.MONOSPACED, Font.PLAIN, DEFAULT_FONT_SIZE);
private static final int CONSOLE_BORDER_WIDTH = 10;
// Since it is very expensive to update the UI with Swing's Event Dispatch Thread, we can't afford
// to refresh the status view on every simulated clock cycle. Instead, we will only refresh the status view
@ -99,6 +103,9 @@ public class Simulator implements Observer {
// requested
private int stepsSinceLastUpdate = 0;
// The number of steps to run per click of the "Step" button
private int stepsPerClick = 1;
/**
* The Main Window is the primary control point for the simulator.
* It is in charge of the menu, and sub-windows. It also shows the
@ -130,10 +137,16 @@ public class Simulator implements Observer {
private JButton runStopButton;
private JButton stepButton;
private JButton resetButton;
private JComboBox stepCountBox;
private JFileChooser fileChooser;
private PreferencesDialog preferences;
/**
* The list of step counts that will appear in the "Step" drop-down.
*/
private static final String[] STEPS = {"1", "5", "10", "20", "50", "100"};
public Simulator() throws MemoryRangeException, IOException {
this.acia = new Acia(ACIA_BASE);
this.via = new Via(VIA_BASE);
@ -172,10 +185,11 @@ public class Simulator implements Observer {
this.console = new com.loomcom.symon.ui.Console(80, 25, DEFAULT_FONT);
this.statusPane = new StatusPanel();
console.setBorderWidth(CONSOLE_BORDER_WIDTH);
// File Chooser
fileChooser = new JFileChooser(System.getProperty("user.dir"));
preferences = new PreferencesDialog(mainWindow, true);
preferences.addObserver(this);
// Panel for Console and Buttons
JPanel consoleContainer = new JPanel();
@ -189,8 +203,22 @@ public class Simulator implements Observer {
stepButton = new JButton("Step");
resetButton = new JButton("Reset");
stepCountBox = new JComboBox(STEPS);
stepCountBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
try {
JComboBox cb = (JComboBox) actionEvent.getSource();
stepsPerClick = Integer.parseInt((String) cb.getSelectedItem());
} catch (NumberFormatException ex) {
stepsPerClick = 1;
stepCountBox.setSelectedIndex(0);
}
}
});
buttonContainer.add(runStopButton);
buttonContainer.add(stepButton);
buttonContainer.add(stepCountBox);
buttonContainer.add(resetButton);
// Left side - console
@ -215,7 +243,7 @@ public class Simulator implements Observer {
stepButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
handleStep();
handleStep(stepsPerClick);
}
});
@ -290,11 +318,13 @@ public class Simulator implements Observer {
}
/**
* Step once, and immediately refresh the UI.
* Step the requested number of times, and immediately refresh the UI.
*/
private void handleStep() {
private void handleStep(int numSteps) {
try {
step();
for (int i = 0; i < numSteps; i++) {
step();
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (traceLog.isVisible()) {
@ -378,24 +408,6 @@ public class Simulator implements Observer {
});
}
/**
* The configuration has changed. Re-load.
*
* @param observable
* @param o
*/
public void update(Observable observable, Object o) {
// Instance equality should work here, there is only one instance.
if (observable == preferences) {
int oldBorderWidth = console.getBorderWidth();
if (oldBorderWidth != preferences.getBorderWidth()) {
// Resize the main window if the border width has changed.
console.setBorderWidth(preferences.getBorderWidth());
mainWindow.pack();
}
}
}
/**
* Main entry point to the simulator. Creates a simulator and shows the main
* window.
@ -441,6 +453,7 @@ public class Simulator implements Observer {
public void run() {
// Don't allow step while the simulator is running
stepButton.setEnabled(false);
stepCountBox.setEnabled(false);
menuBar.simulatorDidStart();
// Toggle the state of the run button
runStopButton.setText("Stop");
@ -461,6 +474,7 @@ public class Simulator implements Observer {
statusPane.updateState(cpu);
runStopButton.setText("Run");
stepButton.setEnabled(true);
stepCountBox.setEnabled(true);
if (traceLog.isVisible()) {
traceLog.refresh();
}

View File

@ -28,11 +28,19 @@ import com.loomcom.symon.exceptions.MemoryAccessException;
import com.loomcom.symon.util.HexUtil;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.MatteBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventObject;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -45,8 +53,22 @@ public class MemoryWindow extends JFrame implements ActionListener {
private MemoryTableModel memoryTableModel;
private JTable memoryTable;
private JTextField pageNumberTextField;
private JButton previousPageButton;
private JButton nextPageButton;
private static final Dimension MINIMUM_SIZE = new Dimension(380, 400);
private static final Dimension MINIMUM_SIZE = new Dimension(320, 600);
// The width of column 0 (address), in pixels
private static final int ADDR_COL_WIDTH = 48;
private static final int HEX_COL_WIDTH = 32;
// The width of the ASCII cells, in pixels
private static final int ASCII_COL_WIDTH = 8;
// The start/end columns of the ASCII view
private static final int ASCII_COL_START = 9;
private static final int ASCII_COL_END = 16;
/**
* Initialize a new MemoryWindow frame with the specified Bus.
@ -81,8 +103,12 @@ public class MemoryWindow extends JFrame implements ActionListener {
* Set the contents of the page number text field with the current
* page number, in hex.
*/
private void updatePageNumberTextField() {
pageNumberTextField.setText(HexUtil.byteToHex(getPageNumber()));
private void updateControls() {
int pageNumber = getPageNumber();
previousPageButton.setEnabled(pageNumber > 0x00);
nextPageButton.setEnabled(pageNumber < 0xff);
pageNumberTextField.setText(HexUtil.byteToHex(pageNumber));
}
/**
@ -90,35 +116,54 @@ public class MemoryWindow extends JFrame implements ActionListener {
*/
private void createUi() {
setTitle("Memory Contents");
this.memoryTable = new JTable(memoryTableModel);
this.memoryTable = new MemoryTable(memoryTableModel);
memoryTable.setDragEnabled(false);
memoryTable.setCellSelectionEnabled(false);
memoryTable.setShowGrid(true);
memoryTable.setShowHorizontalLines(true);
memoryTable.setShowVerticalLines(true);
memoryTable.setGridColor(Color.LIGHT_GRAY);
memoryTable.setIntercellSpacing(new Dimension(0, 0));
memoryTable.getTableHeader().setReorderingAllowed(false);
memoryTable.getTableHeader().setResizingAllowed(false);
memoryTable.getTableHeader().setVisible(false);
memoryTable.getColumnModel().getColumn(0).setMaxWidth(ADDR_COL_WIDTH);
for (int i = 1; i < ASCII_COL_START; i++) {
memoryTable.getColumnModel().getColumn(i).setMaxWidth(HEX_COL_WIDTH);
}
for (int i = ASCII_COL_START; i <= ASCII_COL_END; i++) {
memoryTable.getColumnModel().getColumn(i).setMaxWidth(ASCII_COL_WIDTH);
}
MemoryTableCellRenderer memoryTableCellRenderer = new MemoryTableCellRenderer();
memoryTableCellRenderer.setHorizontalAlignment(JLabel.CENTER);
memoryTable.setDefaultRenderer(String.class, memoryTableCellRenderer);
// Turn off tool-tips for the table.
ToolTipManager.sharedInstance().unregisterComponent(memoryTable);
ToolTipManager.sharedInstance().unregisterComponent(memoryTable.getTableHeader());
JLabel pageNumberLabel = new JLabel("Page Number");
JLabel pageNumberLabel = new JLabel("Page");
pageNumberTextField = new JTextField(8);
pageNumberTextField.addActionListener(this);
updatePageNumberTextField();
nextPageButton = new JButton("Next >>");
previousPageButton = new JButton("<< Prev");
nextPageButton.addActionListener(this);
previousPageButton.addActionListener(this);
updateControls();
JPanel controlPanel = new JPanel();
JPanel memoryPanel = new JPanel();
memoryPanel.setLayout(new BorderLayout());
memoryPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
controlPanel.add(previousPageButton);
controlPanel.add(pageNumberLabel);
controlPanel.add(pageNumberTextField);
controlPanel.add(nextPageButton);
JScrollPane scrollPane = new JScrollPane(memoryTable);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
@ -131,7 +176,8 @@ public class MemoryWindow extends JFrame implements ActionListener {
getContentPane().add(memoryPanel, BorderLayout.CENTER);
setMinimumSize(MINIMUM_SIZE);
setPreferredSize(MINIMUM_SIZE);
memoryPanel.setPreferredSize(memoryTable.getPreferredSize());
setPreferredSize(memoryPanel.getPreferredSize());
pack();
}
@ -142,8 +188,21 @@ public class MemoryWindow extends JFrame implements ActionListener {
* @param e The action event
*/
public void actionPerformed(ActionEvent e) {
if (e.getSource() == pageNumberTextField) {
if (e.getSource() == previousPageButton) {
int currentPage = getPageNumber();
if (currentPage > 0x00) {
setPageNumber(currentPage - 1);
updateControls();
memoryTable.updateUI();
}
} else if (e.getSource() == nextPageButton) {
int currentPage = getPageNumber();
if (currentPage < 0xff) {
setPageNumber(currentPage + 1);
updateControls();
memoryTable.updateUI();
}
} else if (e.getSource() == pageNumberTextField) {
String pageNumberInput = pageNumberTextField.getText();
try {
// Try to parse a hex value out of the pageNumber.
@ -156,7 +215,50 @@ public class MemoryWindow extends JFrame implements ActionListener {
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Can't parse page number " +
pageNumberInput);
}
updatePageNumberTextField();
updateControls();
}
}
/**
* A JTable that will automatically select all text in a cell
* being edited.
*/
private class MemoryTable extends JTable {
public MemoryTable(TableModel tableModel) {
super(tableModel);
}
@Override
public boolean editCellAt(int row, int col, EventObject e) {
boolean result = super.editCellAt(row, col, e);
final Component editor = getEditorComponent();
if (editor != null && editor instanceof JTextComponent) {
((JTextComponent) editor).selectAll();
}
return result;
}
}
private class MemoryTableCellRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int col) {
final Component cell = super.getTableCellRendererComponent(table, value,
isSelected, hasFocus,
row, col);
if (isSelected) {
cell.setBackground(Color.LIGHT_GRAY);
cell.setForeground(Color.BLACK);
}
return cell;
}
}
@ -168,7 +270,7 @@ public class MemoryWindow extends JFrame implements ActionListener {
private Bus bus;
private int pageNumber;
private static final int COLUMN_COUNT = 9;
private static final int COLUMN_COUNT = 17;
private static final int ROW_COUNT = 32;
public MemoryTableModel(Bus bus) {
@ -213,15 +315,19 @@ public class MemoryWindow extends JFrame implements ActionListener {
@Override
public boolean isCellEditable(int row, int column) {
return column > 0;
return (column > 0 && column < ASCII_COL_START);
}
public Object getValueAt(int row, int column) {
try {
if (column == 0) {
return HexUtil.wordToHex(fullAddress(row, 1));
} else {
} else if (column < 9) {
// Display hex value of the data
return HexUtil.byteToHex(bus.read(fullAddress(row, column)));
} else {
// Display the ASCII equivalent (if printable)
return HexUtil.byteToAscii(bus.read(fullAddress(row, column - 8)));
}
} catch (MemoryAccessException ex) {
return "??";
@ -234,7 +340,7 @@ public class MemoryWindow extends JFrame implements ActionListener {
try {
String hexValue = (String)o;
int fullAddress = fullAddress(row, column);
int newValue = Integer.parseInt(hexValue, 16);
int newValue = Integer.parseInt(hexValue, 16) & 0xff;
bus.write(fullAddress, newValue);
} catch (MemoryAccessException ex) {
;

View File

@ -40,10 +40,8 @@ public class PreferencesDialog extends Observable implements Preferences {
private JCheckBox haltOnBreakCheckBox;
private JTextField programLoadAddressField;
private JTextField borderWidthField;
private int programLoadAddress = DEFAULT_PROGRAM_LOAD_ADDRESS;
private int borderWidth = DEFAULT_BORDER_WIDTH;
private boolean haltOnBreak = DEFAULT_HALT_ON_BREAK;
public PreferencesDialog(Frame parent, boolean modal) {
@ -72,14 +70,11 @@ public class PreferencesDialog extends Observable implements Preferences {
final JLabel haltOnBreakLabel = new JLabel("Halt on BRK");
final JLabel programLoadAddressLabel = new JLabel("Program Load Address");
final JLabel borderWidthLabel = new JLabel("Console Border Width");
haltOnBreakCheckBox = new JCheckBox();
programLoadAddressField = new JTextField(8);
borderWidthField = new JTextField(8);
programLoadAddressLabel.setLabelFor(programLoadAddressField);
borderWidthLabel.setLabelFor(borderWidthField);
GridBagConstraints constraints = new GridBagConstraints();
@ -99,17 +94,9 @@ public class PreferencesDialog extends Observable implements Preferences {
constraints.gridx = 1;
settingsContainer.add(programLoadAddressField, constraints);
constraints.gridy = 2;
constraints.gridx = 0;
settingsContainer.add(borderWidthLabel, constraints);
constraints.gridx = 1;
settingsContainer.add(borderWidthField, constraints);
JButton applyButton = new JButton("Apply");
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
updateUi();
@ -121,7 +108,6 @@ public class PreferencesDialog extends Observable implements Preferences {
public void actionPerformed(ActionEvent actionEvent) {
haltOnBreak = haltOnBreakCheckBox.isSelected();
programLoadAddress = hexToInt(programLoadAddressField.getText());
borderWidth = Integer.parseInt(borderWidthField.getText());
updateUi();
// TODO: Actually check to see if values have changed, don't assume.
setChanged();
@ -143,13 +129,6 @@ public class PreferencesDialog extends Observable implements Preferences {
return programLoadAddress;
}
/**
* @return The width of the console border, in pixels.
*/
public int getBorderWidth() {
return borderWidth;
}
/**
* @return True if 'halt on break' is desired, false otherwise.
*/
@ -160,7 +139,6 @@ public class PreferencesDialog extends Observable implements Preferences {
public void updateUi() {
haltOnBreakCheckBox.setSelected(haltOnBreak);
programLoadAddressField.setText(intToHex(programLoadAddress));
borderWidthField.setText(Integer.toString(borderWidth));
}
private String intToHex(int i) {

View File

@ -42,38 +42,67 @@ package com.loomcom.symon.util;
*
*/
public class HexUtil {
private static final String[] HEX_CONSTANTS = {"00", "01", "02", "03", "04", "05", "06", "07",
"08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
"10", "11", "12", "13", "14", "15", "16", "17",
"18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
"20", "21", "22", "23", "24", "25", "26", "27",
"28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
"30", "31", "32", "33", "34", "35", "36", "37",
"38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
"40", "41", "42", "43", "44", "45", "46", "47",
"48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
"50", "51", "52", "53", "54", "55", "56", "57",
"58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
"60", "61", "62", "63", "64", "65", "66", "67",
"68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
"70", "71", "72", "73", "74", "75", "76", "77",
"78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
"80", "81", "82", "83", "84", "85", "86", "87",
"88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
"90", "91", "92", "93", "94", "95", "96", "97",
"98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
"A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7",
"B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7",
"C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
"D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7",
"E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
"F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"};
static final String NON_PRINTABLE = ".";
static final String[] ASCII_CONSTANTS = {" ", "!", "\"", "#", "$", "%", "&", "'",
"(", ")", "*", "+", ",", "-", ".", "/",
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", ":", ";", "<", "=", ">", "?",
"@", "A", "B", "C", "D", "E", "F", "G",
"H", "I", "J", "K", "L", "M", "N", "O",
"P", "Q", "R", "S", "T", "U", "V", "W",
"X", "Y", "Z", "[", "\\", "]", "^", "_",
"`", "a", "b", "c", "d", "e", "f", "g",
"h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w",
"x", "y", "z", "{", "|", "}", "~"};
static final String[] HEX_CONSTANTS = {"00", "01", "02", "03", "04", "05", "06", "07",
"08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
"10", "11", "12", "13", "14", "15", "16", "17",
"18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
"20", "21", "22", "23", "24", "25", "26", "27",
"28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
"30", "31", "32", "33", "34", "35", "36", "37",
"38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
"40", "41", "42", "43", "44", "45", "46", "47",
"48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
"50", "51", "52", "53", "54", "55", "56", "57",
"58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
"60", "61", "62", "63", "64", "65", "66", "67",
"68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
"70", "71", "72", "73", "74", "75", "76", "77",
"78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
"80", "81", "82", "83", "84", "85", "86", "87",
"88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
"90", "91", "92", "93", "94", "95", "96", "97",
"98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
"A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7",
"B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7",
"C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
"D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7",
"E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
"F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"};
/**
* Very fast 8-bit int to ASCII conversion.
* @param val The value of an ASCII character.
* @return A string representing the ASCII character.
*/
public static String byteToAscii(int val) {
if (val >= 32 && val <= 126) {
return ASCII_CONSTANTS[val - 32];
} else {
return NON_PRINTABLE;
}
}
/**
* Very fast 8-bit int to hex conversion, with zero-padded output.