mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
Merge remote-tracking branch 'origin/GT-3049_ghidorahrex_HCS12'
This commit is contained in:
commit
4a6e6697f4
21 changed files with 8220 additions and 21 deletions
|
@ -0,0 +1,142 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
* REVIEWED: YES
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.cmd.disassemble;
|
||||||
|
|
||||||
|
import ghidra.framework.model.DomainObject;
|
||||||
|
import ghidra.program.disassemble.DisassemblerContextImpl;
|
||||||
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.lang.Register;
|
||||||
|
import ghidra.program.model.lang.RegisterValue;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command object for performing HCS12/XGate disassembly
|
||||||
|
*/
|
||||||
|
public class Hcs12DisassembleCommand extends DisassembleCommand {
|
||||||
|
|
||||||
|
private boolean xgMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for Hcs12DisassembleCommand.
|
||||||
|
* @param startSet set of addresses to be the start of a disassembly. The
|
||||||
|
* Command object will attempt to start a disassembly at each address in this set.
|
||||||
|
* @param restrictedSet addresses that can be disassembled.
|
||||||
|
* a null set implies no restrictions
|
||||||
|
* @param xgMode pass true if the disassembling in XGATE Mode
|
||||||
|
*/
|
||||||
|
public Hcs12DisassembleCommand(AddressSetView startSet, AddressSetView restrictedSet,
|
||||||
|
boolean xgMode) {
|
||||||
|
super("Disassemble " + (xgMode ? "XGate" : "HCS12"), startSet, restrictedSet, true);
|
||||||
|
this.xgMode = xgMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for DisassembleCommand.
|
||||||
|
* @param startSet set of addresses to be the start of a disassembly. The
|
||||||
|
* Command object will attempt to start a disassembly at each address in this set.
|
||||||
|
* @param restrictedSet addresses that can be disassembled.
|
||||||
|
* a null set implies no restrictions
|
||||||
|
* @param xgMode pass true if the disassembling in XGATE Mode
|
||||||
|
*/
|
||||||
|
public Hcs12DisassembleCommand(Address start, AddressSetView restrictedSet, boolean xgMode) {
|
||||||
|
this(new AddressSet(start, start), restrictedSet, xgMode);
|
||||||
|
useDefaultRepeatPatternBehavior = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSeedContext(DisassemblerContextImpl seedContext) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInitialContext(RegisterValue initialContextValue) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @see ghidra.framework.cmd.BackgroundCommand#applyTo(ghidra.framework.model.DomainObject, ghidra.util.task.TaskMonitor)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
synchronized public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
|
||||||
|
Program program = (Program) obj;
|
||||||
|
|
||||||
|
disassemblyPerformed = false;
|
||||||
|
unalignedStart = false;
|
||||||
|
|
||||||
|
// get the XGATE mode register and set accordingly
|
||||||
|
Register xgmodeReg = program.getProgramContext().getRegister("XGATE");
|
||||||
|
RegisterValue xgmodeValue = null;
|
||||||
|
|
||||||
|
// if doing xgate, and have no XGmode reg, no way to do disassemble in xgate
|
||||||
|
if (xgmodeReg == null) {
|
||||||
|
if (xgMode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
xgmodeValue = new RegisterValue(xgmodeReg, BigInteger.valueOf(xgMode ? 0x1 : 0x0));
|
||||||
|
super.setInitialContext(xgmodeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
int alignment = 1;
|
||||||
|
|
||||||
|
// Set XGate Mode context on undefined code units only
|
||||||
|
try {
|
||||||
|
if (startSet != null) {
|
||||||
|
|
||||||
|
// Align startSet so that context only affected at possible instruction starts
|
||||||
|
|
||||||
|
AddressSet alignedSet = new AddressSet();
|
||||||
|
for (AddressRange range : startSet) {
|
||||||
|
Address min = range.getMinAddress();
|
||||||
|
long minOfffset = min.getOffset();
|
||||||
|
if (minOfffset != min.getOffset()) {
|
||||||
|
min = min.getNewAddress(minOfffset);
|
||||||
|
}
|
||||||
|
Address max = range.getMaxAddress();
|
||||||
|
long maxOffset = max.getOffset();
|
||||||
|
if (maxOffset < minOfffset) {
|
||||||
|
// skip short unaligned range
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (maxOffset != max.getOffset()) {
|
||||||
|
max = max.getNewAddress(maxOffset);
|
||||||
|
}
|
||||||
|
alignedSet.addRange(min, max);
|
||||||
|
}
|
||||||
|
if (alignedSet.isEmpty()) {
|
||||||
|
unalignedStart = true;
|
||||||
|
return false; // alignedSet does not contain any aligned starts
|
||||||
|
}
|
||||||
|
startSet = program.getListing().getUndefinedRanges(alignedSet, true, monitor);
|
||||||
|
if (startSet.isEmpty()) {
|
||||||
|
return true; // startSet does not contain any aligned undefined starts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (CancelledException e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return doDisassembly(monitor, program, alignment);
|
||||||
|
}
|
||||||
|
}
|
|
@ -83,6 +83,8 @@ public class DisassemblerPlugin extends Plugin {
|
||||||
private DockingAction contextAction;
|
private DockingAction contextAction;
|
||||||
private DockingAction armDisassembleAction;
|
private DockingAction armDisassembleAction;
|
||||||
private DockingAction armThumbDisassembleAction;
|
private DockingAction armThumbDisassembleAction;
|
||||||
|
private DockingAction hcs12DisassembleAction;
|
||||||
|
private DockingAction xgateDisassembleAction;
|
||||||
private DockingAction mipsDisassembleAction;
|
private DockingAction mipsDisassembleAction;
|
||||||
private DockingAction mips16DisassembleAction;
|
private DockingAction mips16DisassembleAction;
|
||||||
private DockingAction ppcDisassembleAction;
|
private DockingAction ppcDisassembleAction;
|
||||||
|
@ -172,6 +174,8 @@ public class DisassemblerPlugin extends Plugin {
|
||||||
contextAction = new ContextAction(this, GROUP_NAME);
|
contextAction = new ContextAction(this, GROUP_NAME);
|
||||||
armDisassembleAction = new ArmDisassembleAction(this, GROUP_NAME, false);
|
armDisassembleAction = new ArmDisassembleAction(this, GROUP_NAME, false);
|
||||||
armThumbDisassembleAction = new ArmDisassembleAction(this, GROUP_NAME, true);
|
armThumbDisassembleAction = new ArmDisassembleAction(this, GROUP_NAME, true);
|
||||||
|
hcs12DisassembleAction = new Hcs12DisassembleAction(this, GROUP_NAME, false);
|
||||||
|
xgateDisassembleAction = new Hcs12DisassembleAction(this, GROUP_NAME, true);
|
||||||
mipsDisassembleAction = new MipsDisassembleAction(this, GROUP_NAME, false);
|
mipsDisassembleAction = new MipsDisassembleAction(this, GROUP_NAME, false);
|
||||||
mips16DisassembleAction = new MipsDisassembleAction(this, GROUP_NAME, true);
|
mips16DisassembleAction = new MipsDisassembleAction(this, GROUP_NAME, true);
|
||||||
ppcDisassembleAction = new PowerPCDisassembleAction(this, GROUP_NAME, false);
|
ppcDisassembleAction = new PowerPCDisassembleAction(this, GROUP_NAME, false);
|
||||||
|
@ -183,6 +187,8 @@ public class DisassemblerPlugin extends Plugin {
|
||||||
tool.addAction(disassembleStaticAction);
|
tool.addAction(disassembleStaticAction);
|
||||||
tool.addAction(armDisassembleAction);
|
tool.addAction(armDisassembleAction);
|
||||||
tool.addAction(armThumbDisassembleAction);
|
tool.addAction(armThumbDisassembleAction);
|
||||||
|
tool.addAction(hcs12DisassembleAction);
|
||||||
|
tool.addAction(xgateDisassembleAction);
|
||||||
tool.addAction(mipsDisassembleAction);
|
tool.addAction(mipsDisassembleAction);
|
||||||
tool.addAction(mips16DisassembleAction);
|
tool.addAction(mips16DisassembleAction);
|
||||||
tool.addAction(ppcDisassembleAction);
|
tool.addAction(ppcDisassembleAction);
|
||||||
|
@ -350,6 +356,30 @@ public class DisassemblerPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void disassembleHcs12Callback(ListingActionContext context, boolean xgMode) {
|
||||||
|
ProgramSelection currentSelection = context.getSelection();
|
||||||
|
ProgramLocation currentLocation = context.getLocation();
|
||||||
|
Program currentProgram = context.getProgram();
|
||||||
|
Hcs12DisassembleCommand cmd = null;
|
||||||
|
|
||||||
|
if ((currentSelection != null) && (!currentSelection.isEmpty())) {
|
||||||
|
cmd = new Hcs12DisassembleCommand(currentSelection, null, xgMode);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Address addr = currentLocation.getAddress();
|
||||||
|
try {
|
||||||
|
currentProgram.getMemory().getByte(addr);
|
||||||
|
cmd = new Hcs12DisassembleCommand(addr, null, xgMode);
|
||||||
|
}
|
||||||
|
catch (MemoryAccessException e) {
|
||||||
|
tool.setStatusInfo("Can't disassemble unitialized memory!", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cmd != null) {
|
||||||
|
tool.executeBackgroundCommand(cmd, currentProgram);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void disassembleMipsCallback(ListingActionContext context, boolean mips16) {
|
public void disassembleMipsCallback(ListingActionContext context, boolean mips16) {
|
||||||
ProgramSelection currentSelection = context.getSelection();
|
ProgramSelection currentSelection = context.getSelection();
|
||||||
ProgramLocation currentLocation = context.getLocation();
|
ProgramLocation currentLocation = context.getLocation();
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.disassembler;
|
||||||
|
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
|
||||||
|
import docking.action.KeyBindingData;
|
||||||
|
import docking.action.MenuData;
|
||||||
|
import ghidra.app.context.ListingActionContext;
|
||||||
|
import ghidra.app.context.ListingContextAction;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.lang.*;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action for HCS12 mode disassembly
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Hcs12DisassembleAction extends ListingContextAction {
|
||||||
|
private DisassemblerPlugin plugin;
|
||||||
|
private boolean disassembleXgate = false;
|
||||||
|
|
||||||
|
public Hcs12DisassembleAction(DisassemblerPlugin plugin, String groupName, boolean disassembleXgate) {
|
||||||
|
super("Disassemble " + (disassembleXgate ? "HCS12" : "XGate"), plugin.getName());
|
||||||
|
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.disassembleXgate = disassembleXgate;
|
||||||
|
|
||||||
|
setPopupMenuData( new MenuData(
|
||||||
|
new String[]{"Disassemble - "+ (disassembleXgate ? "XGate" : "HCS12") },
|
||||||
|
null,
|
||||||
|
groupName ) );
|
||||||
|
|
||||||
|
int keyEvent = (disassembleXgate ? KeyEvent.VK_F12 : KeyEvent.VK_F11);
|
||||||
|
setKeyBindingData( new KeyBindingData( keyEvent, 0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ListingActionContext context) {
|
||||||
|
plugin.disassembleHcs12Callback(context, disassembleXgate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabledForContext(ListingActionContext context) {
|
||||||
|
|
||||||
|
// Action only intended for use where Xgate instructions are available.
|
||||||
|
// The presence of the XGATE context register can be used for this
|
||||||
|
// determination.
|
||||||
|
|
||||||
|
Address address = context.getAddress();
|
||||||
|
if ( address == null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Program program = context.getProgram();
|
||||||
|
Language lang = program.getLanguage();
|
||||||
|
Processor proc = lang.getProcessor();
|
||||||
|
|
||||||
|
if (!"HCS12".equals(proc.toString())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Register register = context.getProgram().getProgramContext().getRegister("XGATE");
|
||||||
|
if (register == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugin.checkDisassemblyEnabled(context, address, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -143,6 +143,29 @@ public class ElfLoadAdapter {
|
||||||
// segment is not marked execute, use the data space by default
|
// segment is not marked execute, use the data space by default
|
||||||
return program.getLanguage().getDefaultDataSpace();
|
return program.getLanguage().getDefaultDataSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the preferred load address for a program segment
|
||||||
|
* @param elfLoadHelper load helper object
|
||||||
|
* @param elfProgramHeader elf program segment header
|
||||||
|
* @return preferred load address
|
||||||
|
*/
|
||||||
|
public Address getPreferredSegmentAddress(ElfLoadHelper elfLoadHelper, ElfProgramHeader elfProgramHeader) {
|
||||||
|
|
||||||
|
Program program = elfLoadHelper.getProgram();
|
||||||
|
|
||||||
|
AddressSpace space =
|
||||||
|
getPreferredSegmentAddressSpace(elfLoadHelper, elfProgramHeader);
|
||||||
|
|
||||||
|
long addrWordOffset = elfProgramHeader.getVirtualAddress();
|
||||||
|
|
||||||
|
if (space == program.getAddressFactory().getDefaultAddressSpace()) {
|
||||||
|
addrWordOffset += elfLoadHelper.getImageBaseWordAdjustmentOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return space.getTruncatedAddress(addrWordOffset, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the default alignment within the default address space.
|
* Get the default alignment within the default address space.
|
||||||
|
@ -174,6 +197,27 @@ public class ElfLoadAdapter {
|
||||||
// segment is not marked execute, use the data space by default
|
// segment is not marked execute, use the data space by default
|
||||||
return program.getLanguage().getDefaultDataSpace();
|
return program.getLanguage().getDefaultDataSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the preferred load address for a program section
|
||||||
|
* @param elfLoadHelper load helper object
|
||||||
|
* @param elfSectionHeader elf program section header
|
||||||
|
* @return preferred load address
|
||||||
|
*/
|
||||||
|
public Address getPreferredSectionAddress(ElfLoadHelper elfLoadHelper,
|
||||||
|
ElfSectionHeader elfSectionHeader) {
|
||||||
|
Program program = elfLoadHelper.getProgram();
|
||||||
|
|
||||||
|
AddressSpace space = getPreferredSectionAddressSpace(elfLoadHelper, elfSectionHeader);
|
||||||
|
|
||||||
|
long addrWordOffset = elfSectionHeader.getAddress();
|
||||||
|
|
||||||
|
if (space == program.getAddressFactory().getDefaultAddressSpace()) {
|
||||||
|
addrWordOffset += elfLoadHelper.getImageBaseWordAdjustmentOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return space.getTruncatedAddress(addrWordOffset, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this extension can handle the specified elf header. If this method returns
|
* Check if this extension can handle the specified elf header. If this method returns
|
||||||
|
@ -429,5 +473,4 @@ public class ElfLoadAdapter {
|
||||||
public Class<? extends ElfRelocation> getRelocationClass(ElfHeader elfHeader) {
|
public Class<? extends ElfRelocation> getRelocationClass(ElfHeader elfHeader) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2170,16 +2170,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||||
private Address getPreferredSegmentLoadAddress(ElfProgramHeader elfProgramHeader)
|
private Address getPreferredSegmentLoadAddress(ElfProgramHeader elfProgramHeader)
|
||||||
throws AddressOutOfBoundsException {
|
throws AddressOutOfBoundsException {
|
||||||
|
|
||||||
AddressSpace space =
|
return elf.getLoadAdapter().getPreferredSegmentAddress(this, elfProgramHeader);
|
||||||
elf.getLoadAdapter().getPreferredSegmentAddressSpace(this, elfProgramHeader);
|
|
||||||
|
|
||||||
long addrWordOffset = elfProgramHeader.getVirtualAddress();
|
|
||||||
|
|
||||||
if (space == getDefaultAddressSpace()) {
|
|
||||||
addrWordOffset += getImageBaseWordAdjustmentOffset();
|
|
||||||
}
|
|
||||||
|
|
||||||
return space.getTruncatedAddress(addrWordOffset, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2216,15 +2207,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||||
private Address getPreferredSectionLoadAddress(ElfSectionHeader elfSectionHeader)
|
private Address getPreferredSectionLoadAddress(ElfSectionHeader elfSectionHeader)
|
||||||
throws AddressOutOfBoundsException {
|
throws AddressOutOfBoundsException {
|
||||||
|
|
||||||
AddressSpace space = getPreferredSectionAddressSpace(elfSectionHeader);
|
return elf.getLoadAdapter().getPreferredSectionAddress(this, elfSectionHeader);
|
||||||
|
|
||||||
long addrWordOffset = elfSectionHeader.getAddress();
|
|
||||||
|
|
||||||
if (space == getDefaultAddressSpace()) {
|
|
||||||
addrWordOffset += getImageBaseWordAdjustmentOffset();
|
|
||||||
}
|
|
||||||
|
|
||||||
return space.getTruncatedAddress(addrWordOffset, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -83,8 +83,9 @@ public class CommitParamsAction extends AbstractDecompilerAction {
|
||||||
if (hfunc.getFunction().getSignatureSource() == SourceType.USER_DEFINED) {
|
if (hfunc.getFunction().getSignatureSource() == SourceType.USER_DEFINED) {
|
||||||
source = SourceType.USER_DEFINED;
|
source = SourceType.USER_DEFINED;
|
||||||
}
|
}
|
||||||
HighFunctionDBUtil.commitParamsToDatabase(hfunc, true, source);
|
|
||||||
HighFunctionDBUtil.commitReturnToDatabase(hfunc, source);
|
HighFunctionDBUtil.commitReturnToDatabase(hfunc, source);
|
||||||
|
HighFunctionDBUtil.commitParamsToDatabase(hfunc, true, source);
|
||||||
}
|
}
|
||||||
catch (DuplicateNameException e) {
|
catch (DuplicateNameException e) {
|
||||||
throw new AssertException("Unexpected exception", e);
|
throw new AssertException("Unexpected exception", e);
|
||||||
|
|
|
@ -415,6 +415,8 @@ public class VariableUtilities {
|
||||||
" bytes: " + curStorage.toString());
|
" bytes: " + curStorage.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vnAddr = newReg.getAddress();
|
||||||
if (bigEndian) {
|
if (bigEndian) {
|
||||||
vnAddr = vnAddr.add(newReg.getMinimumByteSize() - size);
|
vnAddr = vnAddr.add(newReg.getMinimumByteSize() - size);
|
||||||
return new Varnode(vnAddr, size);
|
return new Varnode(vnAddr, size);
|
||||||
|
|
0
Ghidra/Processors/HCS12/Module.manifest
Normal file
0
Ghidra/Processors/HCS12/Module.manifest
Normal file
5
Ghidra/Processors/HCS12/build.gradle
Normal file
5
Ghidra/Processors/HCS12/build.gradle
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
|
||||||
|
apply from: "$rootProject.projectDir/gradle/processorProject.gradle"
|
||||||
|
apply plugin: 'eclipse'
|
||||||
|
eclipse.project.name = 'Processors HCS12'
|
||||||
|
|
13
Ghidra/Processors/HCS12/certification.manifest
Normal file
13
Ghidra/Processors/HCS12/certification.manifest
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
##VERSION: 2.0
|
||||||
|
.project||NONE||||END|
|
||||||
|
Module.manifest||GHIDRA||||END|
|
||||||
|
build.gradle||GHIDRA||||END|
|
||||||
|
data/build.xml||GHIDRA||||END|
|
||||||
|
data/languages/HCS12.cspec||GHIDRA||||END|
|
||||||
|
data/languages/HCS12.ldefs||GHIDRA||||END|
|
||||||
|
data/languages/HCS12.opinion||GHIDRA||||END|
|
||||||
|
data/languages/HCS12.pspec||GHIDRA||||END|
|
||||||
|
data/languages/HCS12.slaspec||GHIDRA||||END|
|
||||||
|
data/languages/HCS_HC12.sinc||GHIDRA||||END|
|
||||||
|
data/languages/XGATE.sinc||GHIDRA||||END|
|
||||||
|
data/manuals/HCS12.idx||GHIDRA||||END|
|
152
Ghidra/Processors/HCS12/data/languages/HCS12.cspec
Normal file
152
Ghidra/Processors/HCS12/data/languages/HCS12.cspec
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<compiler_spec>
|
||||||
|
<data_organization> <!-- These tags need to be verified -->
|
||||||
|
<absolute_max_alignment value="0" />
|
||||||
|
<machine_alignment value="1" />
|
||||||
|
<default_alignment value="1" />
|
||||||
|
<pointer_size value="2" />
|
||||||
|
<wchar_size value="4" />
|
||||||
|
<short_size value="2" />
|
||||||
|
<integer_size value="4" />
|
||||||
|
<long_size value="4" />
|
||||||
|
<long_long_size value="8" />
|
||||||
|
<float_size value="4" />
|
||||||
|
<double_size value="8" />
|
||||||
|
<long_double_size value="8" />
|
||||||
|
</data_organization>
|
||||||
|
|
||||||
|
<global>
|
||||||
|
<range space="RAM" first="0x00" last="0x0f"/>
|
||||||
|
<range space="RAM" first="0x11" last="0x15"/>
|
||||||
|
<range space="RAM" first="0x18" last="0x2f"/>
|
||||||
|
<range space="RAM" first="0x31" last="0xffff"/>
|
||||||
|
</global>
|
||||||
|
|
||||||
|
<stackpointer register="SP" space="RAM" growth="negative"/>
|
||||||
|
|
||||||
|
<default_proto>
|
||||||
|
<prototype name="__asmA" extrapop="2" stackshift="2" strategy="register">
|
||||||
|
<input>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="A"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="B"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="2" maxsize="2">
|
||||||
|
<register name="D"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="2">
|
||||||
|
<register name="IY"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="2">
|
||||||
|
<register name="IX"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="500" align="1">
|
||||||
|
<addr offset="2" space="stack"/>
|
||||||
|
</pentry>
|
||||||
|
</input>
|
||||||
|
<output>
|
||||||
|
<pentry minsize="1" maxsize="2">
|
||||||
|
<register name="D"/>
|
||||||
|
</pentry>
|
||||||
|
</output>
|
||||||
|
<unaffected>
|
||||||
|
<register name="SP"/>
|
||||||
|
<register name="EPAGE"/>
|
||||||
|
<register name="PPAGE"/>
|
||||||
|
<register name="RPAGE"/>
|
||||||
|
<register name="GPAGE"/>
|
||||||
|
</unaffected>
|
||||||
|
</prototype>
|
||||||
|
</default_proto>
|
||||||
|
|
||||||
|
|
||||||
|
<prototype name="__asmA_longcall" extrapop="3" stackshift="3" strategy="register">
|
||||||
|
<input>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="A"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="B"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="2" maxsize="2">
|
||||||
|
<register name="D"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="2">
|
||||||
|
<register name="IY"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="2">
|
||||||
|
<register name="IX"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="500" align="1">
|
||||||
|
<addr offset="3" space="stack"/>
|
||||||
|
</pentry>
|
||||||
|
</input>
|
||||||
|
<output>
|
||||||
|
<pentry minsize="1" maxsize="2">
|
||||||
|
<register name="D"/>
|
||||||
|
</pentry>
|
||||||
|
</output>
|
||||||
|
<unaffected>
|
||||||
|
<register name="SP"/>
|
||||||
|
<register name="EPAGE"/>
|
||||||
|
<register name="PPAGE"/>
|
||||||
|
<register name="RPAGE"/>
|
||||||
|
<register name="GPAGE"/>
|
||||||
|
</unaffected>
|
||||||
|
</prototype>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<resolveprototype name="__asmA_longcall/__asmA">
|
||||||
|
<model name="__asmA_longcall"/> <!-- The default case -->
|
||||||
|
<model name="__asmA"/>
|
||||||
|
</resolveprototype>
|
||||||
|
<eval_current_prototype name="__asmA_longcall/__asmA"/>
|
||||||
|
|
||||||
|
<prototype name="__asm_xgate" extrapop="0" stackshift="0" strategy="register">
|
||||||
|
<input>
|
||||||
|
<pentry minsize="1" maxsize="2">
|
||||||
|
<register name="R2"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="2">
|
||||||
|
<register name="R3"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="3" maxsize="4">
|
||||||
|
<addr space="join" piece1="R2" piece2="R3"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="2">
|
||||||
|
<register name="R4"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="3" maxsize="4">
|
||||||
|
<addr space="join" piece1="R3" piece2="R4"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="500" align="2">
|
||||||
|
<addr offset="2" space="stack"/>
|
||||||
|
</pentry>
|
||||||
|
</input>
|
||||||
|
<output>
|
||||||
|
<pentry minsize="1" maxsize="2">
|
||||||
|
<register name="R2"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="4" maxsize="4">
|
||||||
|
<addr space="join" piece1="R2" piece2="R3"/>
|
||||||
|
</pentry>
|
||||||
|
</output>
|
||||||
|
<unaffected>
|
||||||
|
<register name="R1"/>
|
||||||
|
<register name="SP"/>
|
||||||
|
<register name="R7"/>
|
||||||
|
<register name="PPAGE"/>
|
||||||
|
</unaffected>
|
||||||
|
<pcode inject="uponentry">
|
||||||
|
<!-- Special injection at start of function, really R7 is the stack pointer, but
|
||||||
|
decompiler can only handle one stack pointer. (Hack) -->
|
||||||
|
<body>
|
||||||
|
R7 = SP;
|
||||||
|
</body>
|
||||||
|
</pcode>
|
||||||
|
</prototype>
|
||||||
|
</compiler_spec>
|
17
Ghidra/Processors/HCS12/data/languages/HCS12.ldefs
Normal file
17
Ghidra/Processors/HCS12/data/languages/HCS12.ldefs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<language_definitions>
|
||||||
|
<language processor="HCS12"
|
||||||
|
endian="big"
|
||||||
|
size="24"
|
||||||
|
variant="default"
|
||||||
|
version="1.0"
|
||||||
|
slafile="HCS12.sla"
|
||||||
|
processorspec="HCS12.pspec"
|
||||||
|
manualindexfile="../manuals/HCS12.idx"
|
||||||
|
id="HCS12:BE:24:default">
|
||||||
|
<description>HCS12X Microcontroller Family</description>
|
||||||
|
<compiler name="default" spec="HCS12.cspec" id="default"/>
|
||||||
|
<external_name tool="gnu" name="m9s12x"/>
|
||||||
|
</language>
|
||||||
|
</language_definitions>
|
6
Ghidra/Processors/HCS12/data/languages/HCS12.opinion
Normal file
6
Ghidra/Processors/HCS12/data/languages/HCS12.opinion
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<opinions>
|
||||||
|
<constraint loader="Executable and Linking Format (ELF)" compilerSpecID="default">
|
||||||
|
<constraint primary="53" processor="HCS12" endian="big" size="24" variant="default"/>
|
||||||
|
</constraint>
|
||||||
|
</opinions>
|
||||||
|
|
96
Ghidra/Processors/HCS12/data/languages/HCS12.pspec
Normal file
96
Ghidra/Processors/HCS12/data/languages/HCS12.pspec
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
This is the processor specification for the MC9S12C and MC9S12GC processor families.
|
||||||
|
It is based upon the MC9S12C128 and MC9S12GC128 variants.
|
||||||
|
-->
|
||||||
|
<processor_spec>
|
||||||
|
<programcounter register="PC"/>
|
||||||
|
|
||||||
|
<segmentop space="RAM" userop="segment" farpointer="no">
|
||||||
|
<pcode>
|
||||||
|
<input name="inner" size="2"/>
|
||||||
|
<input name="base" size="3"/>
|
||||||
|
<output name="res" size="3"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
res = base ^ zext(inner);
|
||||||
|
]]></body>
|
||||||
|
</pcode>
|
||||||
|
<constresolve>
|
||||||
|
<register name="physPage"/>
|
||||||
|
</constresolve>
|
||||||
|
</segmentop>
|
||||||
|
|
||||||
|
<context_data>
|
||||||
|
<tracked_set space="RAM">
|
||||||
|
<set name="PPAGE" val="0xfe"/>
|
||||||
|
<set name="RPAGE" val="0xfd"/>
|
||||||
|
<set name="EPAGE" val="0xfe"/>
|
||||||
|
</tracked_set>
|
||||||
|
</context_data>
|
||||||
|
<default_symbols>
|
||||||
|
<symbol name="VECTOR_Reset" address="FFFE" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_ClockMonitorFailReset" address="FFFC" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_COPFailureReset" address="FFFA" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_UnimplementedInstructionTrap" address="FFF8" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_SWI" address="FFF6" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_XIRQ" address="FFF4" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_IRQ" address="FFF2" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_RealTimeInterrupt" address="FFF0" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_StandardTimerChannel0" address="FFEE" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_StandardTimerChannel1" address="FFEC" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_StandardTimerChannel2" address="FFEA" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_StandardTimerChannel3" address="FFE8" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_StandardTimerChannel4" address="FFE6" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_StandardTimerChannel5" address="FFE4" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_StandardTimerChannel6" address="FFE2" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_StandardTimerChannel7" address="FFE0" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_StandardTimerOverflow" address="FFDE" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_PulseAccumulatorAOverflow" address="FFDC" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_PulseAccumulatorInputEdge" address="FFDA" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_SPI" address="FFD8" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_SCI" address="FFD6" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFD4" address="FFD4" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_ATD" address="FFD2" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFD0" address="FFD0" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_PortJ" address="FFCE" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFCC" address="FFCC" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFCA" address="FFCA" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFC8" address="FFC8" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_CRG_PLL_Lock" address="FFC6" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_CRGSelfClockMode" address="FFC4" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFC2" address="FFC2" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFC0" address="FFC0" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFBE" address="FFBE" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFBC" address="FFBC" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFBA" address="FFBA" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_FLASH" address="FFB8" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_CANwake-up" address="FFB6" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_CANerrors" address="FFB4" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_CANreceive" address="FFB2" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_CANtransmit" address="FFB0" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFAE" address="FFAE" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFAC" address="FFAC" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFAA" address="FFAA" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFA8" address="FFA8" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFA6" address="FFA6" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFA4" address="FFA4" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFA2" address="FFA2" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FFA0" address="FFA0" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF9E" address="FF9E" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF9C" address="FF9C" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF9A" address="FF9A" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF98" address="FF98" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF96" address="FF96" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF94" address="FF94" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF92" address="FF92" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF90" address="FF90" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_PortP" address="FF8E" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_PWM_EmergencyShutdown" address="FF8C" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_VREG_LVI" address="FF8A" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF88" address="FF88" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF86" address="FF86" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF84" address="FF84" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF82" address="FF82" entry="true" type="code_ptr"/>
|
||||||
|
<symbol name="VECTOR_Reserved_FF80" address="FF80" entry="true" type="code_ptr"/>
|
||||||
|
</default_symbols>
|
||||||
|
</processor_spec>
|
9
Ghidra/Processors/HCS12/data/languages/HCS12.slaspec
Normal file
9
Ghidra/Processors/HCS12/data/languages/HCS12.slaspec
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# sleigh specification file for Freescale HCS12 (68HCS12)
|
||||||
|
|
||||||
|
@define HCS12 "1"
|
||||||
|
@define HCS12X "1"
|
||||||
|
|
||||||
|
@define MAXFLASHPage "0xFF"
|
||||||
|
|
||||||
|
@include "HCS_HC12.sinc"
|
||||||
|
@include "XGATE.sinc"
|
5791
Ghidra/Processors/HCS12/data/languages/HCS_HC12.sinc
Normal file
5791
Ghidra/Processors/HCS12/data/languages/HCS_HC12.sinc
Normal file
File diff suppressed because it is too large
Load diff
993
Ghidra/Processors/HCS12/data/languages/XGATE.sinc
Normal file
993
Ghidra/Processors/HCS12/data/languages/XGATE.sinc
Normal file
|
@ -0,0 +1,993 @@
|
||||||
|
# sleigh specification file for XGATE MCU peripheral co-processor
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# Registers
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
# register R0 always contains the value 0
|
||||||
|
define register offset=0x100 size=2 [R0 R1 R2 R3 R4 R5 R6 R7];
|
||||||
|
define register offset=0x100 size=1 [R0.H R0.L R1.H R1.L R2.H R2.L R3.H R3.L R4.H R4.L R5.H R5.L R6.H R6.L R7.H R7.L];
|
||||||
|
define register offset=0x110 size=2 [XPC XCCR];
|
||||||
|
define register offset=0x120 size=1 [XC XV XZ XN];
|
||||||
|
|
||||||
|
# Individual status bits within the XCCR
|
||||||
|
@define XN "XN" # XCCR[3,1] # Negative Flag
|
||||||
|
@define XZ "XZ" # XCCR[2,1] # Zero Flag
|
||||||
|
@define XV "XV" # XCCR[1,1] # Overflow Flag
|
||||||
|
@define XC "XC" # XCCR[0,1] # Carry Flag
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# Tokens
|
||||||
|
################################################################
|
||||||
|
define token XOpWord16 (16)
|
||||||
|
xop16 = (0,15)
|
||||||
|
opcode = (11,15)
|
||||||
|
reg8 = (8,10)
|
||||||
|
reg8_lo = (8,10)
|
||||||
|
reg8_hi = (8,10)
|
||||||
|
imm3 = (8,10)
|
||||||
|
op9_10 = (9,10)
|
||||||
|
bit_10 = (10,10)
|
||||||
|
immrel9 = (0,9) signed
|
||||||
|
immrel8 = (0,8) signed
|
||||||
|
xop8 = (0,7)
|
||||||
|
reg5 = (5,7)
|
||||||
|
ximm4 = (4,7)
|
||||||
|
ximm8 = (0,7)
|
||||||
|
op4 = (0,4)
|
||||||
|
op3 = (0,3)
|
||||||
|
offs5 = (0,5)
|
||||||
|
reg2 = (2,4)
|
||||||
|
op2 = (0,1)
|
||||||
|
;
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# Attach variables
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
attach variables [reg8 reg5 reg2] [R0 R1 R2 R3 R4 R5 R6 R7];
|
||||||
|
|
||||||
|
attach variables [reg8_lo ] [R0.L R1.L R2.L R3.L R4.L R5.L R6.L R7.L];
|
||||||
|
attach variables [reg8_hi ] [R0.H R1.H R2.H R3.H R4.H R5.H R6.H R7.H];
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# Pseudo Instructions
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
define pcodeop findFirstOne;
|
||||||
|
define pcodeop leftShiftCarry;
|
||||||
|
define pcodeop rightShiftCarry;
|
||||||
|
define pcodeop parity;
|
||||||
|
define pcodeop clearSemaphore;
|
||||||
|
define pcodeop setSemaphore;
|
||||||
|
define pcodeop setInterruptFlag;
|
||||||
|
define pcodeop TerminateThread;
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# Macros Instructions
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
macro default_flags(result)
|
||||||
|
{
|
||||||
|
$(XZ) = (result == 0);
|
||||||
|
$(XN) = (result s< 0);
|
||||||
|
$(XV) = 0;
|
||||||
|
#$(XC) not affected
|
||||||
|
}
|
||||||
|
|
||||||
|
macro addition_flags(operand1, operand2, result)
|
||||||
|
{
|
||||||
|
$(XN) = (result s< 0);
|
||||||
|
$(XZ) = ((result == 0) & ($(XZ)==1));
|
||||||
|
$(XV) = (((operand1 & operand2 & ~result) | (~operand1 & ~operand2 & result)) & 0x8000) != 0;
|
||||||
|
$(XC) = (((operand1 & operand2) | (operand2 & ~result) | (~result & operand1)) & 0x8000) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro subtraction_flags(register, operand, result) {
|
||||||
|
$(XN) = (result s< 0);
|
||||||
|
$(XZ) = (result == 0);
|
||||||
|
$(XV) = ( ((register & ~operand & ~result) | (~register & operand & result)) & 0x8000 ) != 0;
|
||||||
|
$(XC) = ( ((~register & operand) | (operand & result) | (~register & result)) & 0x8000 ) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro subtraction_flagsB(register, operand, result) {
|
||||||
|
$(XN) = (result s< 0);
|
||||||
|
$(XZ) = (result == 0);
|
||||||
|
$(XV) = ( ((register & ~operand & ~result) | (~register & operand & result)) & 0x80 ) != 0;
|
||||||
|
$(XC) = ( ((~register & operand) | (operand & result) | (result & ~register)) & 0x80 ) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro subtraction_flagsC(register, operand, result) {
|
||||||
|
$(XN) = (result s< 0);
|
||||||
|
$(XZ) = ( (result == 0) & ($(XZ) == 1));
|
||||||
|
$(XV) = ( ((register & ~operand & ~result) | (~register & operand & result)) & 0x8000 ) != 0;
|
||||||
|
$(XC) = ( ((~register & operand) | (operand & result) | (~register & result)) & 0x8000 ) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro shiftFlags(result,old)
|
||||||
|
{
|
||||||
|
$(XN) = (result s< 0);
|
||||||
|
$(XZ) = (result == 0);
|
||||||
|
tmp:2 = (old >> 15) ^ (result >> 15);
|
||||||
|
$(XV) = tmp(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro getbit(res,in,bitnum) {
|
||||||
|
res = ((in >> bitnum) & 1) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# computes a fake PPAGE page mapping based on the 16 bit input address
|
||||||
|
# The XGATE memory is mapped to the pages of physical memory
|
||||||
|
# Warning: This might not be the correct mapping on all XGATE processors
|
||||||
|
#
|
||||||
|
# 0000-07ff = 0x00_0000 - 0x00_07ff
|
||||||
|
# 0800-7fff = 0x78_0800 - XGFLASH_HIGH
|
||||||
|
# 8000-ffff = 0x0f_0800 - 0x0f_ffff
|
||||||
|
#
|
||||||
|
macro computePage(addr) {
|
||||||
|
local isReg:1 = addr < 0x800;
|
||||||
|
local isFlash:1 = addr >= 0x800 & addr < 0x7fff;
|
||||||
|
local isRam:1 = addr >= 0x8000;
|
||||||
|
physPage = (zext(isReg) * 0x0)+ (zext(isFlash) * (0x78 << 16)) + (zext(isRam) * (0xf<<16));
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# Constructors
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
#rel9 defined in HCS_HC12.sinc
|
||||||
|
# range -256 through +255
|
||||||
|
with : XGATE=1 {
|
||||||
|
rel9: reloc is immrel8 [ reloc = inst_next + (immrel8 * 2); ] { export * reloc; }
|
||||||
|
|
||||||
|
# range -512 through +512
|
||||||
|
rel10: reloc is immrel9 [ reloc = inst_next + (immrel9 * 2); ] { export * reloc; }
|
||||||
|
|
||||||
|
rd : reg8 is reg8 { export reg8; }
|
||||||
|
|
||||||
|
rs1: reg5 is reg5 & reg5=0 { export 0:2; }
|
||||||
|
rs1: reg5 is reg5 { export reg5; }
|
||||||
|
|
||||||
|
rs2: reg2 is reg2 & reg2=0 { export 0:2; }
|
||||||
|
rs2: reg2 is reg2 { export reg2; }
|
||||||
|
|
||||||
|
|
||||||
|
rd_lo: reg8 is reg8 & reg8_lo { export reg8_lo; }
|
||||||
|
rd_hi: reg8 is reg8 & reg8_hi { export reg8_hi; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Add with carry
|
||||||
|
:ADC rd, rs1, rs2 is opcode=0x3 & rd & rs1 & rs2 & op2=0x3
|
||||||
|
{
|
||||||
|
local result:2 = rs1 + rs2 + zext($(XC));
|
||||||
|
rd = result;
|
||||||
|
|
||||||
|
addition_flags(rs1, rs2, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add without carry
|
||||||
|
:ADD rd, rs1, rs2 is opcode=0x3 & rd & rs1 & rs2 & op2=0x2
|
||||||
|
{
|
||||||
|
local result:2 = rs1 + rs2;
|
||||||
|
rd = result;
|
||||||
|
|
||||||
|
addition_flags(rs1, rs2, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add immediate 8-bit constant (high byte)
|
||||||
|
:ADDH rd, ximm8 is opcode=0x1d & rd & ximm8
|
||||||
|
{
|
||||||
|
local val:2 = ximm8 << 8;
|
||||||
|
local result:2 = rd + val;
|
||||||
|
|
||||||
|
addition_flags(rd, val, result);
|
||||||
|
|
||||||
|
rd = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add immediate 8-bit constant (low byte)
|
||||||
|
:ADDL rd, ximm8 is opcode=0x1c & rd & ximm8
|
||||||
|
{
|
||||||
|
local result:2 = rd + ximm8;
|
||||||
|
|
||||||
|
$(XN) = (result s< 0);
|
||||||
|
$(XZ) = ((result == 0) & ($(XZ)==1));
|
||||||
|
$(XV) = ((~rd & result) & 0x8000) != 0;
|
||||||
|
$(XC) = ((rd & ~result) & 0x8000) != 0;
|
||||||
|
rd = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logical AND
|
||||||
|
:AND rd, rs1, rs2 is opcode=0x2 & rd & rs1 & rs2 & op2=0x0
|
||||||
|
{
|
||||||
|
rd = rs1 & rs2;
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logical AND immediate 8-bit constant (high byte)
|
||||||
|
:ANDH rd, ximm8 is opcode=0x11 & rd & ximm8 & rd_hi
|
||||||
|
{
|
||||||
|
rd_hi = rd_hi & ximm8;
|
||||||
|
|
||||||
|
default_flags(rd_hi);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logical AND immediate 8-bit constant (low byte)
|
||||||
|
:ANDL rd, ximm8 is opcode=0x10 & rd & ximm8 & rd_lo
|
||||||
|
{
|
||||||
|
rd_lo = rd_lo & ximm8;
|
||||||
|
|
||||||
|
default_flags(rd_lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Arithmetic Shift Right
|
||||||
|
:ASR rd, ximm4 is opcode=0x1 & rd & ximm4 & op3=0x9
|
||||||
|
{
|
||||||
|
getbit($(XC), rd, ximm4-1);
|
||||||
|
rd = rd s>> ximm4;
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
:ASR rd, rs1 is opcode=0x1 & rd & rs1 & op4=0x11
|
||||||
|
{
|
||||||
|
getbit($(XC), rd, rs1-1);
|
||||||
|
rd = rd s>> rs1;
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch if Carry Cleared
|
||||||
|
:BCC rel9 is opcode=0x4 & op9_10=0x0 & rel9
|
||||||
|
{
|
||||||
|
if ($(XC) == 0) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Branch if Carry Set
|
||||||
|
:BCS rel9 is opcode=0x4 & op9_10=0x1 & rel9
|
||||||
|
{
|
||||||
|
if ($(XC) == 1) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch of Equal
|
||||||
|
:BEQ rel9 is opcode=0x4 & op9_10=0x3 & rel9
|
||||||
|
{
|
||||||
|
if ($(XZ) == 1) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Bit Field Extract
|
||||||
|
:BFEXT rd, rs1, rs2 is opcode=0xc & rd & rs1 & rs2 & op2=0x3
|
||||||
|
{
|
||||||
|
local origin:2 = rs2 & 0xf;
|
||||||
|
local width:2 = (rs2 >> 4) & 0xf;
|
||||||
|
local mask:2 = (0xffff >> (16-(width + 1))) << origin;
|
||||||
|
local result:2 = (rs1 & mask) >> origin;
|
||||||
|
|
||||||
|
rd = result;
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Bit Field Find First One
|
||||||
|
:BFFO rd, rs1 is opcode=0x1 & rd & rs1 & op4=0x10
|
||||||
|
{
|
||||||
|
# 15 - count leading zeros
|
||||||
|
tmp:2 = rs1;
|
||||||
|
$(XC) = (rd == 0);
|
||||||
|
#TODO: implement findFirstOne behavior
|
||||||
|
rd = findFirstOne(tmp);
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Bit Field Insert
|
||||||
|
:BFINS rd, rs1, rs2 is opcode=0xd & rd & rs1 & rs2 & op2=0x3
|
||||||
|
{
|
||||||
|
local origin:2 = rs2 & 0xf;
|
||||||
|
local width:2 = (rs2 >> 4) & 0xf;
|
||||||
|
local mask:2 = (0xffff >> (16-(width + 1))) << origin;
|
||||||
|
local result:2 = (rs1 & mask);
|
||||||
|
|
||||||
|
rd = (rd & ~mask) | result;
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Bit Field Insert and Invert
|
||||||
|
:BFINSI rd, rs1, rs2 is opcode=0xe & rd & rs1 & rs2 & op2=0x3
|
||||||
|
{
|
||||||
|
local origin:2 = rs2 & 0xf;
|
||||||
|
local width:2 = (rs2 >> 4) & 0xf;
|
||||||
|
local mask:2 = (0xffff >> (16-(width + 1))) << origin;
|
||||||
|
local result:2 = (~rs1 & mask);
|
||||||
|
|
||||||
|
rd = (rd & ~mask) | result;
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Bit Field Insert and XNOR
|
||||||
|
:BFINSX rd, rs1, rs2 is opcode=0xf & rd & rs1 & rs2 & op2=0x3
|
||||||
|
{
|
||||||
|
local origin:2 = rs2 & 0xf;
|
||||||
|
local width:2 = (rs2 >> 4) & 0xf;
|
||||||
|
local mask:2 = (0xffff >> (16-(width + 1))) << origin;
|
||||||
|
local result:2 = (~(rs1 ^ rd) & mask);
|
||||||
|
|
||||||
|
rd = (rd & ~mask) | result;
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch if Greater than or Equal to Zero
|
||||||
|
:BGE rel9 is opcode=0x6 & op9_10=0x2 & rel9
|
||||||
|
{
|
||||||
|
if (($(XN) ^ $(XV)) == 0) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch if Greater than Zero
|
||||||
|
:BGT rel9 is opcode=0x7 & op9_10=0x0 & rel9
|
||||||
|
{
|
||||||
|
if (($(XZ) | ($(XN) ^ $(XV))) == 0) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch if Higher
|
||||||
|
:BHI rel9 is opcode=0x6 & op9_10=0x0 & rel9
|
||||||
|
{
|
||||||
|
if (($(XC) | $(XZ)) == 0) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
#:BHS rel9 is opcode=0x4 & op9_10=0x0 & rel9 see BCC
|
||||||
|
|
||||||
|
# Bit Test immediate 8-bit constant (high byte)
|
||||||
|
:BITH rd, ximm8 is opcode=0x13 & rd & ximm8 & rd_hi
|
||||||
|
{
|
||||||
|
local val = rd_hi & ximm8;
|
||||||
|
|
||||||
|
default_flags(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Bit Test immediate 8-bit constant (low byte)
|
||||||
|
:BITL reg8, ximm8 is opcode=0x12 & reg8 & ximm8 & rd_lo
|
||||||
|
{
|
||||||
|
local val = rd_lo & ximm8;
|
||||||
|
|
||||||
|
default_flags(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch if Less or Equal to Zero
|
||||||
|
:BLE rel9 is opcode=0x7 & op9_10=0x1 & rel9
|
||||||
|
{
|
||||||
|
if ($(XZ) | ($(XN) ^ $(XV))) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
#:BLO rel9 is opcode=0x4 & op9_10=0x1 & rel9 See BCS
|
||||||
|
|
||||||
|
# Branch if Lower or Same
|
||||||
|
:BLS rel9 is opcode=0x6 & op9_10=0x1 & rel9
|
||||||
|
{
|
||||||
|
if (($(XC) | $(XZ)) == 1) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch of Lower than Zero
|
||||||
|
:BLT rel9 is opcode=0x6 & op9_10=0x3 & rel9
|
||||||
|
{
|
||||||
|
if (($(XN) ^ $(XV)) == 1) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch if Minus
|
||||||
|
:BMI rel9 is opcode=0x5 & op9_10=0x1 & rel9
|
||||||
|
{
|
||||||
|
if ($(XN) == 1) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch if Not Equal
|
||||||
|
:BNE rel9 is opcode=0x4 & op9_10=0x2 & rel9
|
||||||
|
{
|
||||||
|
if ($(XZ) == 0) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch if Plus
|
||||||
|
:BPL rel9 is opcode=0x5 & op9_10=0x0 & rel9
|
||||||
|
{
|
||||||
|
if ($(XN) == 0) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch Always
|
||||||
|
:BRA rel10 is opcode=0x7 & bit_10=0x1 & rel10
|
||||||
|
{
|
||||||
|
goto rel10;
|
||||||
|
}
|
||||||
|
# Break
|
||||||
|
:BRK is xop16=0x0
|
||||||
|
{
|
||||||
|
# put xgate into debug mode and set breakpoint
|
||||||
|
goto inst_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch if Overflow Cleared
|
||||||
|
:BVC rel9 is opcode=0x5 & op9_10=0x2 & rel9
|
||||||
|
{
|
||||||
|
if ($(XV) == 0) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Branch if Overflow Set
|
||||||
|
:BVS rel9 is opcode=0x5 & op9_10=0x3 & rel9
|
||||||
|
{
|
||||||
|
if ($(XV) == 2) goto rel9;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compare
|
||||||
|
# synonym for SUB R0, RS1, RS2
|
||||||
|
:CMP rs1, rs2 is opcode=0x3 & reg8=0x0 & rs1 & rs2 & op2=0x0
|
||||||
|
{
|
||||||
|
tmp:2 = rs1 - rs2;
|
||||||
|
subtraction_flags(rs1, rs2, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compare Immediate 8-bit constant (low byte)
|
||||||
|
:CMPL rd, ximm8 is opcode=0x1a & rd & ximm8
|
||||||
|
{
|
||||||
|
local val:1 = rd:1;
|
||||||
|
local tmp:1 = val - ximm8;
|
||||||
|
local xtmp:1 = ximm8;
|
||||||
|
subtraction_flagsB(val, xtmp, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
# One's Complement
|
||||||
|
:COM rd, rs2 is opcode=0x2 & rd & reg5=0x0 & rs2 & op2=0x3
|
||||||
|
{
|
||||||
|
local val:2 = ~rs2;
|
||||||
|
rd = val;
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
:COM rd is opcode=0x2 & rd & reg5=0x0 & rs2 & reg8=reg2 & op2=0x3
|
||||||
|
{
|
||||||
|
local val:2 = ~rs2;
|
||||||
|
rd = val;
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compare with Carry
|
||||||
|
:CPC rs1, rs2 is opcode=0x3 & reg8=0x0 & rs1 & rs2 & op2=0x1
|
||||||
|
{
|
||||||
|
local tmp:2 = rs1 - rs2 - zext($(XC));
|
||||||
|
subtraction_flags(rs1, rs2, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compare Immediate 8-bit constant with carry (high byte)
|
||||||
|
:CPCH rd, ximm8 is opcode=0x1b & rd & ximm8
|
||||||
|
{
|
||||||
|
local val:2 = rd >> 8;
|
||||||
|
local tmp:1 = val(1) - ximm8 - $(XC);
|
||||||
|
local xtmp:1 = ximm8;
|
||||||
|
subtraction_flagsB(val(1), xtmp, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clear Semaphore
|
||||||
|
:CSEM rd is opcode=0x0 & rd & xop8=0xf0
|
||||||
|
{
|
||||||
|
# treat as NOP
|
||||||
|
clearSemaphore(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
:CSEM imm3 is opcode=0x0 & imm3 & xop8=0xf1
|
||||||
|
{
|
||||||
|
local sem:1 = imm3;
|
||||||
|
clearSemaphore(sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Logical Shift Left with Carry
|
||||||
|
:CSL rd, ximm4 is opcode=0x1 & rd & ximm4 & op3=0xa
|
||||||
|
{
|
||||||
|
local Ctmp:2 = zext($(XC));
|
||||||
|
local shift:2 = ((ximm4-1)%16+1);
|
||||||
|
local oldRd:2 = rd >> 15;
|
||||||
|
getbit($(XC), rd, 16-shift);
|
||||||
|
leftShiftCarry(rd,Ctmp,shift,rd);
|
||||||
|
shiftFlags(rd,oldRd);
|
||||||
|
}
|
||||||
|
|
||||||
|
:CSL rd, rs1 is opcode=0x1 & rd & rs1 & op4=0x12
|
||||||
|
{
|
||||||
|
local Ctmp:2 = zext($(XC));
|
||||||
|
#if rs1 > 16, then rs1 = 16
|
||||||
|
local rsgt:2 = zext(rs1>16);
|
||||||
|
local rslt:2 = zext(rs1<16);
|
||||||
|
local shift:2 = rs1*rsgt + 16*rslt;
|
||||||
|
local oldRd:2 = rd >> 15;
|
||||||
|
getbit($(XC), rd, 16-shift);
|
||||||
|
leftShiftCarry(rd,Ctmp,shift,rd);
|
||||||
|
shiftFlags(rd,oldRd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logical Shift Right with Carry
|
||||||
|
:CSR rd, ximm4 is opcode=0x1 & rd & ximm4 & op3=0xb
|
||||||
|
{
|
||||||
|
local Ctmp:2 = zext($(XC));
|
||||||
|
local shift:2 = ((ximm4-1)%16+1);
|
||||||
|
local oldRd:2 = rd >> 15;
|
||||||
|
getbit($(XC), rd, shift-1);
|
||||||
|
rightShiftCarry(rd,Ctmp,shift,rd);
|
||||||
|
shiftFlags(rd,oldRd);
|
||||||
|
}
|
||||||
|
|
||||||
|
:CSR rd, rs1 is opcode=0x1 & rd & rs1 & op4=0x13
|
||||||
|
{
|
||||||
|
local Ctmp:2 = zext($(XC));
|
||||||
|
#if rs1 > 16, then rs1 = 16
|
||||||
|
local rsgt:2 = zext(rs1>16);
|
||||||
|
local rslt:2 = zext(rs1<16);
|
||||||
|
local shift:2 = rs1*rsgt + 16*rslt;
|
||||||
|
local oldRd:2 = rd >> 15;
|
||||||
|
getbit($(XC), rd, shift-1);
|
||||||
|
rightShiftCarry(rd,Ctmp,shift,rd);
|
||||||
|
shiftFlags(rd,oldRd);
|
||||||
|
}
|
||||||
|
|
||||||
|
:CSR rd, rs1 is opcode=0x1 & rd & rs1 & reg5=0 & op4=0x13
|
||||||
|
{
|
||||||
|
$(XN) = (rd s< 0);
|
||||||
|
$(XZ) = (rd == 0);
|
||||||
|
$(XV) = 0;
|
||||||
|
# $(XC) is unaffected
|
||||||
|
}
|
||||||
|
|
||||||
|
# Jump and Link
|
||||||
|
:JAL rd is opcode=0x0 & rd & xop8=0xf6
|
||||||
|
{
|
||||||
|
local dest:2 = rd;
|
||||||
|
rd = inst_next;
|
||||||
|
call [dest];
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load byte from memory (low byte)
|
||||||
|
:LDB rd, (rs1, offs5) is opcode=0x8 & rd & rs1 & offs5
|
||||||
|
{
|
||||||
|
local addr = rs1 + offs5;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:1 = *:1 (dst);
|
||||||
|
rd = (rd & 0xff00) | zext(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
:LDB rd, (rs1, rs2) is opcode=0xc & rd & rs1 & rs2 & op2=0x0
|
||||||
|
{
|
||||||
|
local addr = rs1 + rs2;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:1 = *:1 (dst);
|
||||||
|
rd = (rd & 0xff00) | zext(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
:LDB rd, (rs1, rs2+) is opcode=0xc & rd & rs1 & rs2 & op2=0x1
|
||||||
|
{
|
||||||
|
local addr = rs1 + rs2;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:1 = *:1 (dst);
|
||||||
|
rd = (rd & 0xff00) | zext(val);
|
||||||
|
rs1 = rs1 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:LDB rd, (rs1, -rs2) is opcode=0xc & rd & rs1 & rs2 & op2=0x2
|
||||||
|
{
|
||||||
|
rs2 = rs2 - 1;
|
||||||
|
local addr = rs1 + rs2;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:1 = *:1 (dst);
|
||||||
|
rd = (rd & 0xff00) | zext(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Load Immediate 8-bit constant (high byte)
|
||||||
|
:LDH rd, ximm8 is opcode=0x1f & rd & ximm8 & rd_hi
|
||||||
|
{
|
||||||
|
rd_hi = ximm8 << 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Load Immediate 8-bit constant (low byte)
|
||||||
|
:LDL rd, ximm8 is opcode=0x1e & rd & ximm8
|
||||||
|
{
|
||||||
|
rd = ximm8;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load Word from Memory
|
||||||
|
:LDW rd, (rs1, offs5) is opcode=0x9 & rd & rs1 & offs5
|
||||||
|
{
|
||||||
|
local addr = rs1 + offs5;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:2 = *:2 (dst);
|
||||||
|
rd = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
:LDW rd, (rs1, rs2) is opcode=0xd & rd & rs1 & rs2 & op2=0x0
|
||||||
|
{
|
||||||
|
local addr = rs1 + rs2;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:2 = *:2 (dst);
|
||||||
|
rd = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
:LDW rd, (rs1, rs2+) is opcode=0xd & rd & rs1 & rs2 & op2=0x1
|
||||||
|
{
|
||||||
|
local addr = rs1 + rs2;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:2 = *:2 (dst);
|
||||||
|
rd = val;
|
||||||
|
rs1 = rs1 + 2;
|
||||||
|
}
|
||||||
|
:LDW rd, (rs1, -rs2) is opcode=0xd & rd & rs1 & rs2 & op2=0x2
|
||||||
|
{
|
||||||
|
rs2 = rs2 - 2;
|
||||||
|
local addr = rs1 + rs2;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:2 = *:2 (dst);
|
||||||
|
rd = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logical Shift Left
|
||||||
|
:LSL rd, ximm4 is opcode=0x1 & rd & ximm4 & op3=0xc
|
||||||
|
{
|
||||||
|
local shift:2 = ((ximm4-1)%16+1);
|
||||||
|
getbit($(XC), rd, 16-shift);
|
||||||
|
local oldRd:2 = rd >> 15;
|
||||||
|
rd = rd << shift;
|
||||||
|
shiftFlags(rd,oldRd);
|
||||||
|
}
|
||||||
|
|
||||||
|
:LSL rd, rs1 is opcode=0x1 & rd & rs1 & op4=0x14
|
||||||
|
{
|
||||||
|
getbit($(XC), rd, 16-rs1);
|
||||||
|
local oldRd:2 = rd >> 15;
|
||||||
|
rd = rd << rs1;
|
||||||
|
shiftFlags(rd,oldRd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logical Shift Right
|
||||||
|
:LSR rd, ximm4 is opcode=0x1 & rd & ximm4 & op3=0xd
|
||||||
|
{
|
||||||
|
getbit($(XC), rd, ximm4-1);
|
||||||
|
local oldRd:2 = rd >> 15;
|
||||||
|
rd = rd >> ximm4;
|
||||||
|
shiftFlags(rd,oldRd);
|
||||||
|
}
|
||||||
|
|
||||||
|
:LSR rd, rs1 is opcode=0x1 & rd & rs1 & op4=0x15
|
||||||
|
{
|
||||||
|
getbit($(XC), rd, rs1-1);
|
||||||
|
local oldRd:2 = (rd >> 15);
|
||||||
|
rd = rd >> rs1;
|
||||||
|
shiftFlags(rd,oldRd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Move Register Content
|
||||||
|
# Synonym for OR RD, R0, RS
|
||||||
|
:MOV rd, rs2 is opcode=0x2 & rd & reg5=0 & rs2 & op2=0x2
|
||||||
|
{
|
||||||
|
rd = rs2;
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Two's Complement
|
||||||
|
:NEG rd, rs2 is opcode=0x3 & rd & reg5=0x0 & rs2 & op2=0x0
|
||||||
|
{
|
||||||
|
local tmp:2 = -rs2;
|
||||||
|
rd = tmp;
|
||||||
|
$(XN) = (rd s< 0);
|
||||||
|
$(XZ) = (rd == 0);
|
||||||
|
$(XV) = (((rs2 & rd) & 0x8000) != 0);
|
||||||
|
$(XC) = (((rs2 | rd) & 0x8000) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
:NEG rd is opcode=0x3 & rd & reg5=0x0 & rs2 & reg2=reg8 & op2=0x0
|
||||||
|
{
|
||||||
|
local tmp:2 = -rs2;
|
||||||
|
rd = tmp;
|
||||||
|
$(XN) = (rd s< 0);
|
||||||
|
$(XZ) = (rd == 0);
|
||||||
|
$(XV) = (((rs2 & rd) & 0x8000) != 0);
|
||||||
|
$(XC) = (((rs2 | rd) & 0x8000) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
# No Op
|
||||||
|
:NOP is xop16=0x100 {}
|
||||||
|
|
||||||
|
# Logical OR
|
||||||
|
:OR rd, rs1, rs2 is opcode=0x2 & rd & rs1 & rs2 & op2=0x2
|
||||||
|
{
|
||||||
|
local result:2 = rs1 | rs2;
|
||||||
|
rd = result;
|
||||||
|
|
||||||
|
default_flags(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logical OR Immediate 8-bit Constant (high byte)
|
||||||
|
:ORH rd, ximm8 is opcode=0x15 & rd & ximm8 & rd_hi
|
||||||
|
{
|
||||||
|
rd_hi = rd_hi | ximm8;
|
||||||
|
|
||||||
|
default_flags(rd_hi);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logical OR Immediate 8-bit Constant (low byte)
|
||||||
|
:ORL rd, ximm8 is opcode=0x14 & rd & ximm8 & rd_lo
|
||||||
|
{
|
||||||
|
rd_lo = rd_lo | ximm8;
|
||||||
|
|
||||||
|
default_flags(rd_lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Calculate Parity
|
||||||
|
:PAR rd is opcode=0x0 & rd & xop8=0xf5
|
||||||
|
{
|
||||||
|
parity(rd, $(XC));
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Rotate Left
|
||||||
|
:ROL rd, ximm4 is opcode=0x1 & rd & ximm4 & op3=0xe
|
||||||
|
{
|
||||||
|
local cnt:2 = ximm4;
|
||||||
|
rd = (rd << cnt) | (rd >> (16 - cnt));
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
:ROL rd, rs1 is opcode=0x1 & rd & rs1 & op4=0x16
|
||||||
|
{
|
||||||
|
local cnt:2 = rs1 & 0xf;
|
||||||
|
rd = (rd << cnt) | (rd >> (16 - cnt));
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Rotate Right
|
||||||
|
:ROR rd, ximm4 is opcode=0x1 & rd & ximm4 & op3=0xf
|
||||||
|
{
|
||||||
|
local cnt:2 = ximm4;
|
||||||
|
rd = (rd >> cnt) | (rd << (16 - rd));
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
:ROR rd, rs1 is opcode=0x1 & rd & rs1 & op4=0x17
|
||||||
|
{
|
||||||
|
local cnt:2 = rs1 & 0xf;
|
||||||
|
rd = (rd >> cnt) | (rd << (16 - rd));
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
# Return to Scheduler
|
||||||
|
# Implement as NOP for now
|
||||||
|
:RTS is xop16=0x0200 {
|
||||||
|
XPC = TerminateThread();
|
||||||
|
return [XPC];
|
||||||
|
}
|
||||||
|
|
||||||
|
# Subtract with Carry
|
||||||
|
:SBC rd, rs1, rs2 is opcode=0x3 & rd & rs1 & rs2 & op2=0x1
|
||||||
|
{
|
||||||
|
local result:2 = rs1 - rs2 - zext($(XC));
|
||||||
|
rd = result;
|
||||||
|
subtraction_flagsC(rs1, rs2, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sign Extent Byte to Word
|
||||||
|
:SEX rd is opcode=0x0 & rd & xop8=0xf4
|
||||||
|
{
|
||||||
|
local result:1 = rd:1 & 0xff;
|
||||||
|
rd = sext(result);
|
||||||
|
|
||||||
|
default_flags(rd);
|
||||||
|
}
|
||||||
|
# Set Interrupt Flag
|
||||||
|
# TODO: implement interrupt flags
|
||||||
|
:SIF is xop16=0x0300
|
||||||
|
{
|
||||||
|
setInterruptFlag();
|
||||||
|
}
|
||||||
|
|
||||||
|
:SIF rd is opcode=0x0 & rd & xop8=0xf7
|
||||||
|
{
|
||||||
|
setInterruptFlag();
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set Semaphore
|
||||||
|
# TODO: implement semaphores
|
||||||
|
:SSEM imm3 is opcode=0x0 & imm3 & xop8=0xf2
|
||||||
|
{
|
||||||
|
local sem:1 = imm3;
|
||||||
|
setSemaphore(sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
:SSEM rd is opcode=0x0 & rd & xop8=0xf3
|
||||||
|
{
|
||||||
|
setSemaphore(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Store Byte to Memory (low byte)
|
||||||
|
:STB rd, (rs1, offs5) is opcode=0xa & rd & rs1 & offs5
|
||||||
|
{
|
||||||
|
local addr = rs1 + offs5;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:1 = rd:1;
|
||||||
|
*dst = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
:STB rd, (rs1, rs2) is opcode=0xe & rd & rs1 & rs2 & op2=0x0
|
||||||
|
{
|
||||||
|
local addr = rs1 + rs2;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:1 = rd:1;
|
||||||
|
*dst = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
:STB rd, (rs1, rs2+) is opcode=0xe & rd & rs1 & rs2 & op2=0x1
|
||||||
|
{
|
||||||
|
local addr = rs1 + rs2;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:1 = rd:1;
|
||||||
|
*dst = val;
|
||||||
|
rs2 = rs2 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:STB rd, (rs1, -rs2) is opcode=0xe & rd & rs1 & rs2 & op2=0x2
|
||||||
|
{
|
||||||
|
rs2 = rs2 - 1;
|
||||||
|
local addr = rs1 + rs2;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:1 = rd:1;
|
||||||
|
*dst = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Store Word to Memory
|
||||||
|
:STW rd, (rs1, offs5) is opcode=0xb & rd & rs1 & offs5
|
||||||
|
{
|
||||||
|
local addr = rs1 + offs5;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:2 = rd;
|
||||||
|
*dst = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
:STW rd, (rs1, rs2) is opcode=0xf & rd & rs1 & rs2 & op2=0x0
|
||||||
|
{
|
||||||
|
local addr = rs1 + rs2;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:2 = rd;
|
||||||
|
*dst = val;
|
||||||
|
rs2 = rs2 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:STW rd, (rs1, rs2+) is opcode=0xf & rd & rs1 & rs2 & op2=0x1
|
||||||
|
{
|
||||||
|
local addr = rs1 + rs2;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:2 = rd;
|
||||||
|
*dst = val;
|
||||||
|
rs2 = rs2 + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
:STW rd, (rs1, -rs2) is opcode=0xf & rd & rs1 & rs2 & op2=0x2
|
||||||
|
{
|
||||||
|
rs2 = rs2 - 2;
|
||||||
|
local addr = rs1 + rs2;
|
||||||
|
computePage(addr);
|
||||||
|
local dst:3 = segment(PPAGE,addr);
|
||||||
|
local val:2 = rd;
|
||||||
|
*dst = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Subtract without Carry
|
||||||
|
:SUB rd, rs1, rs2 is opcode=0x3 & rd & rs1 & rs2 & op2=0x0
|
||||||
|
{
|
||||||
|
local result:2 = rs1 - rs2;
|
||||||
|
rd = result;
|
||||||
|
|
||||||
|
subtraction_flags(rs1, rs2, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Subtract Immediate 8-bit constant (high byte)
|
||||||
|
:SUBH rd, ximm8 is opcode=0x19 & rd & ximm8
|
||||||
|
{
|
||||||
|
local val:2 = ximm8 << 8;
|
||||||
|
local result:2 = rd - val;
|
||||||
|
|
||||||
|
subtraction_flags(rd, val, result);
|
||||||
|
|
||||||
|
rd = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Subtract Immediate 8-bit constant (low byte)
|
||||||
|
:SUBL rd, ximm8 is opcode=0x18 & rd & ximm8
|
||||||
|
{
|
||||||
|
local val:2 = ximm8;
|
||||||
|
local result:2 = rd - val;
|
||||||
|
|
||||||
|
$(XN) = (result s< 0);
|
||||||
|
$(XZ) = ((result == 0) & ($(XZ)==1));
|
||||||
|
$(XV) = ((~rd & result) & 0x8000) != 0;
|
||||||
|
$(XC) = ((rd & ~result) & 0x8000) != 0;
|
||||||
|
rd = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Transfer from and to Special Registers
|
||||||
|
:TFR rd, XCCR is opcode=0x0 & rd & xop8=0xf8 & XCCR
|
||||||
|
{
|
||||||
|
local val:1 = ((($(XN) << 1) | $(XZ) << 1) | $(XV) << 1) | $(XC);
|
||||||
|
rd = zext(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
:TFR XCCR, rd is opcode=0x0 & rd & xop8=0xf9 & XCCR
|
||||||
|
{
|
||||||
|
XCCR = rd & 0xf;
|
||||||
|
$(XN) = rd[3,1];
|
||||||
|
$(XZ) = rd[2,1];
|
||||||
|
$(XV) = rd[1,1];
|
||||||
|
$(XC) = rd[0,1];
|
||||||
|
}
|
||||||
|
|
||||||
|
:TFR rd, XPC is opcode=0x0 & rd & xop8=0xfa & XPC
|
||||||
|
{
|
||||||
|
rd = inst_next + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test Register
|
||||||
|
# Synonym for SUB R0, RS, R0
|
||||||
|
:TST rs1 is opcode=0x3 & reg8=0x0 & rs1 & reg2=0x0 & op2=0x0
|
||||||
|
{
|
||||||
|
local result:2 = rs1;
|
||||||
|
|
||||||
|
subtraction_flags(rs1,0,result);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logical Exclusive NOR
|
||||||
|
:XNOR rd, rs1, rs2 is opcode=0x2 & rd & rs1 & rs2 & op2=0x3
|
||||||
|
{
|
||||||
|
local result:2 = ~(rs1 ^ rs2);
|
||||||
|
rd = result;
|
||||||
|
|
||||||
|
default_flags(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logical Exclusive NOR Immediate 8-bit constant (high byte)
|
||||||
|
:XNORH rd, ximm8 is opcode=0x17 & rd & ximm8 & rd_hi
|
||||||
|
{
|
||||||
|
rd_hi = ~(rd_hi ^ ximm8);
|
||||||
|
|
||||||
|
default_flags(rd_hi);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logical Exclusive NOR Immediate 8-bit constant (low byte)
|
||||||
|
:XNORL rd, ximm8 is opcode=0x16 & rd & ximm8 & rd_lo
|
||||||
|
{
|
||||||
|
rd_lo= ~(rd_lo^ ximm8);
|
||||||
|
|
||||||
|
default_flags(rd_lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
356
Ghidra/Processors/HCS12/data/manuals/HCS12.idx
Normal file
356
Ghidra/Processors/HCS12/data/manuals/HCS12.idx
Normal file
|
@ -0,0 +1,356 @@
|
||||||
|
@S12XCPUV2.pdf[ CPU12/CPU12X Reference Manual, Rev. v01.04 21 Apr. 2016, nxp.com ]
|
||||||
|
ABA, 84
|
||||||
|
ABX, 85
|
||||||
|
ABY, 86
|
||||||
|
ADCA, 87
|
||||||
|
ADCB, 88
|
||||||
|
ADDA, 89
|
||||||
|
ADDB, 90
|
||||||
|
ADDD, 91
|
||||||
|
ADDX, 92
|
||||||
|
ADDY, 93
|
||||||
|
ADED, 94
|
||||||
|
ADEX, 95
|
||||||
|
ADEY, 96
|
||||||
|
ANDA, 97
|
||||||
|
ANDB, 98
|
||||||
|
ANDCC, 99
|
||||||
|
ANDX, 100
|
||||||
|
ANDY, 101
|
||||||
|
ASL, 102
|
||||||
|
ASLA, 103
|
||||||
|
ASLB, 104
|
||||||
|
ASLD, 105
|
||||||
|
ASLW, 106
|
||||||
|
ASLX, 107
|
||||||
|
ASLY, 108
|
||||||
|
ASR, 109
|
||||||
|
ASRA, 110
|
||||||
|
ASRB, 111
|
||||||
|
ASRW, 112
|
||||||
|
ASRX, 113
|
||||||
|
ASRY, 114
|
||||||
|
BCC, 115
|
||||||
|
BCLR, 116
|
||||||
|
BCS, 117
|
||||||
|
BEQ, 118
|
||||||
|
BGE, 119
|
||||||
|
BGND, 120
|
||||||
|
BGT, 121
|
||||||
|
BHI, 122
|
||||||
|
BHS, 123
|
||||||
|
BITA, 124
|
||||||
|
BITB, 125
|
||||||
|
BITX, 126
|
||||||
|
BITY, 127
|
||||||
|
BLE, 128
|
||||||
|
BLO, 129
|
||||||
|
BLS, 130
|
||||||
|
BLT, 131
|
||||||
|
BMI, 132
|
||||||
|
BNE, 133
|
||||||
|
BPL, 134
|
||||||
|
BRA, 135
|
||||||
|
BRCLR, 136
|
||||||
|
BRN, 137
|
||||||
|
BRSET, 138
|
||||||
|
BSET, 139
|
||||||
|
BSR, 140
|
||||||
|
BTAS, 141
|
||||||
|
BVC, 142
|
||||||
|
BVS, 143
|
||||||
|
CALL, 144
|
||||||
|
CBA, 145
|
||||||
|
CLC, 146
|
||||||
|
CLI, 147
|
||||||
|
CLR, 148
|
||||||
|
CLRA, 149
|
||||||
|
CLRB, 150
|
||||||
|
CLRW, 151
|
||||||
|
CLRX, 152
|
||||||
|
CLRY, 153
|
||||||
|
CLV, 154
|
||||||
|
CMPA, 155
|
||||||
|
CMPB, 156
|
||||||
|
COM, 157
|
||||||
|
COMA, 158
|
||||||
|
COMB, 159
|
||||||
|
COMW, 160
|
||||||
|
COMX, 161
|
||||||
|
COMY, 162
|
||||||
|
CPD, 163
|
||||||
|
CPED, 164
|
||||||
|
CPES, 165
|
||||||
|
CPEX, 166
|
||||||
|
CPEY, 167
|
||||||
|
CPS, 168
|
||||||
|
CPX, 169
|
||||||
|
CPY, 170
|
||||||
|
DAA, 171
|
||||||
|
DBEQ, 172
|
||||||
|
DBNE, 173
|
||||||
|
DEC, 174
|
||||||
|
DECA, 175
|
||||||
|
DECB, 176
|
||||||
|
DECW, 177
|
||||||
|
DECX, 178
|
||||||
|
DECY, 179
|
||||||
|
DES, 180
|
||||||
|
DEX, 181
|
||||||
|
DEY, 182
|
||||||
|
EDIV, 183
|
||||||
|
EDIVS, 184
|
||||||
|
EMACS, 185
|
||||||
|
EMAXD, 186
|
||||||
|
EMAXM, 187
|
||||||
|
EMIND, 188
|
||||||
|
EMINM, 189
|
||||||
|
EMUL, 190
|
||||||
|
EMULS, 191
|
||||||
|
EORA, 192
|
||||||
|
EORB, 193
|
||||||
|
EORX, 194
|
||||||
|
EORY, 195
|
||||||
|
ETBL, 196
|
||||||
|
EXG, 197
|
||||||
|
FDIV, 199
|
||||||
|
GLDAA, 200
|
||||||
|
GLDAB, 201
|
||||||
|
GLDD, 202
|
||||||
|
GLDS, 203
|
||||||
|
GLDX, 204
|
||||||
|
GLDY, 205
|
||||||
|
GSTAA, 206
|
||||||
|
GSTAB, 207
|
||||||
|
GSTD, 208
|
||||||
|
GSTS, 209
|
||||||
|
GSTX, 210
|
||||||
|
GSTY, 211
|
||||||
|
IBEQ, 212
|
||||||
|
IBNE, 213
|
||||||
|
IDIV, 214
|
||||||
|
IDIVS, 215
|
||||||
|
INC, 216
|
||||||
|
INCA, 217
|
||||||
|
INCB, 218
|
||||||
|
INCW, 219
|
||||||
|
INCX, 220
|
||||||
|
INCY, 221
|
||||||
|
INS, 222
|
||||||
|
INX, 223
|
||||||
|
INY, 224
|
||||||
|
JMP, 225
|
||||||
|
JSR, 226
|
||||||
|
LBCC, 227
|
||||||
|
LBCS, 228
|
||||||
|
LBEQ, 229
|
||||||
|
LBGE, 230
|
||||||
|
LBGT, 231
|
||||||
|
LBHI, 232
|
||||||
|
LBHS, 233
|
||||||
|
LBLE, 234
|
||||||
|
LBLO, 235
|
||||||
|
LBLS, 236
|
||||||
|
LBLT, 237
|
||||||
|
LBMI, 238
|
||||||
|
LBNE, 239
|
||||||
|
LBPL, 240
|
||||||
|
LBRA, 241
|
||||||
|
LBRN, 242
|
||||||
|
LBVC, 243
|
||||||
|
LBVS, 244
|
||||||
|
LDAA, 245
|
||||||
|
LDAB, 246
|
||||||
|
LDD, 247
|
||||||
|
LDS, 248
|
||||||
|
LDX, 249
|
||||||
|
LDY, 250
|
||||||
|
LEAS, 251
|
||||||
|
LEAX, 252
|
||||||
|
LEAY, 253
|
||||||
|
LSL, 254
|
||||||
|
LSLA, 255
|
||||||
|
LSLB, 256
|
||||||
|
LSLD, 257
|
||||||
|
LSLW, 258
|
||||||
|
LSLX, 259
|
||||||
|
LSLY, 260
|
||||||
|
LSR, 261
|
||||||
|
LSRA, 262
|
||||||
|
LSRB, 263
|
||||||
|
LSRD, 264
|
||||||
|
LSRW, 265
|
||||||
|
LSRX, 266
|
||||||
|
LSRY, 267
|
||||||
|
MAXA, 268
|
||||||
|
MAXM, 269
|
||||||
|
MEM, 270
|
||||||
|
MINA, 271
|
||||||
|
MINM, 272
|
||||||
|
MOVB, 273
|
||||||
|
MOVW, 280
|
||||||
|
MUL, 287
|
||||||
|
NEG, 288
|
||||||
|
NEGA, 289
|
||||||
|
NEGB, 290
|
||||||
|
NEGW, 291
|
||||||
|
NEGX, 292
|
||||||
|
NEGY, 293
|
||||||
|
NOP, 294
|
||||||
|
ORAA, 295
|
||||||
|
ORAB, 296
|
||||||
|
ORCC, 297
|
||||||
|
ORX, 298
|
||||||
|
ORY, 299
|
||||||
|
PSHA, 300
|
||||||
|
PSHB, 301
|
||||||
|
PSHC, 302
|
||||||
|
PSHCW, 303
|
||||||
|
PSHD, 304
|
||||||
|
PSHX, 305
|
||||||
|
PSHY, 306
|
||||||
|
PULA, 307
|
||||||
|
PULB, 308
|
||||||
|
PULC, 309
|
||||||
|
PULCW, 310
|
||||||
|
PULD, 311
|
||||||
|
PULX, 312
|
||||||
|
PULY, 313
|
||||||
|
REV, 314
|
||||||
|
REVW, 316
|
||||||
|
ROL, 318
|
||||||
|
ROLA, 319
|
||||||
|
ROLB, 320
|
||||||
|
ROLW, 321
|
||||||
|
ROLX, 322
|
||||||
|
ROLY, 323
|
||||||
|
ROR, 324
|
||||||
|
RORA, 325
|
||||||
|
RORB, 326
|
||||||
|
RORW, 327
|
||||||
|
RORX, 328
|
||||||
|
RORY, 329
|
||||||
|
RTC, 330
|
||||||
|
RTI, 331
|
||||||
|
RTS, 332
|
||||||
|
SBA, 333
|
||||||
|
SBCA, 334
|
||||||
|
SBCB, 335
|
||||||
|
SBED, 336
|
||||||
|
SBEX, 337
|
||||||
|
SBEY, 338
|
||||||
|
SEC, 339
|
||||||
|
SEI, 340
|
||||||
|
SEV, 341
|
||||||
|
SEX, 342
|
||||||
|
STAA, 343
|
||||||
|
STAB, 344
|
||||||
|
STD, 345
|
||||||
|
STOP, 346
|
||||||
|
STS, 348
|
||||||
|
STX, 349
|
||||||
|
STY, 350
|
||||||
|
SUBA, 351
|
||||||
|
SUBB, 352
|
||||||
|
SUBD, 353
|
||||||
|
SUBX, 354
|
||||||
|
SUBY, 355
|
||||||
|
SWI, 356
|
||||||
|
SYS, 357
|
||||||
|
TAB, 358
|
||||||
|
TAP, 359
|
||||||
|
TBA, 360
|
||||||
|
TBEQ, 361
|
||||||
|
TBL, 362
|
||||||
|
TBNE, 363
|
||||||
|
TFR, 364
|
||||||
|
TPA, 366
|
||||||
|
TRAP, 367
|
||||||
|
TST, 368
|
||||||
|
TSTA, 369
|
||||||
|
TSTB, 370
|
||||||
|
TSTW, 371
|
||||||
|
TSTX, 372
|
||||||
|
TSTY, 373
|
||||||
|
TSX, 374
|
||||||
|
TSY, 375
|
||||||
|
TXS, 376
|
||||||
|
TYS, 377
|
||||||
|
WAI, 378
|
||||||
|
WAV, 379
|
||||||
|
XGDX, 380
|
||||||
|
XGDY, 381
|
||||||
|
|
||||||
|
@MC9S12XEP100RMV1.pdf[ MC9S12XEP100 Reference Manual, Rev. 1.25 02/2013, nxp.com ]
|
||||||
|
ADC, 389
|
||||||
|
ADD, 390
|
||||||
|
ADDH, 391
|
||||||
|
ADDL, 392
|
||||||
|
AND, 393
|
||||||
|
ANDH, 394
|
||||||
|
ANDL, 395
|
||||||
|
ASR, 396
|
||||||
|
BCC, 397
|
||||||
|
BCS, 398
|
||||||
|
BEQ, 399
|
||||||
|
BFEXT, 400
|
||||||
|
BFFO, 401
|
||||||
|
BFINS, 402
|
||||||
|
BFINSI, 403
|
||||||
|
BFINSX, 404
|
||||||
|
BGE, 405
|
||||||
|
BGT, 406
|
||||||
|
BHI, 407
|
||||||
|
BHS, 408
|
||||||
|
BITH, 409
|
||||||
|
BITL, 410
|
||||||
|
BLE, 411
|
||||||
|
BLO, 412
|
||||||
|
BLS, 413
|
||||||
|
BLT, 414
|
||||||
|
BMI, 415
|
||||||
|
BNE, 416
|
||||||
|
BPL, 417
|
||||||
|
BRA, 418
|
||||||
|
BRK, 419
|
||||||
|
BVC, 420
|
||||||
|
BVS, 421
|
||||||
|
CMP, 422
|
||||||
|
CMPL, 423
|
||||||
|
COM, 424
|
||||||
|
CPC, 425
|
||||||
|
CPCH, 426
|
||||||
|
CSEM, 427
|
||||||
|
CSL, 428
|
||||||
|
CSR, 429
|
||||||
|
JAL, 430
|
||||||
|
LDB, 431
|
||||||
|
LDH, 432
|
||||||
|
LDL, 433
|
||||||
|
LDW, 434
|
||||||
|
LSL, 435
|
||||||
|
LSR, 436
|
||||||
|
MOV, 437
|
||||||
|
NEG, 438
|
||||||
|
NOP, 439
|
||||||
|
OR, 440
|
||||||
|
ORH, 441
|
||||||
|
ORL, 442
|
||||||
|
PAR, 443
|
||||||
|
ROL, 444
|
||||||
|
ROR, 445
|
||||||
|
RTS, 446
|
||||||
|
SBC, 447
|
||||||
|
SEX, 448
|
||||||
|
SIF, 449
|
||||||
|
SSEM, 450
|
||||||
|
STB, 451
|
||||||
|
STW, 452
|
||||||
|
SUB, 453
|
||||||
|
SUBH, 454
|
||||||
|
SUBL, 455
|
||||||
|
TFR, 456
|
||||||
|
TST, 457
|
||||||
|
XNOR, 458
|
||||||
|
XNORH, 459
|
||||||
|
XNORL, 460
|
|
@ -0,0 +1,165 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.analysis;
|
||||||
|
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressSetView;
|
||||||
|
import ghidra.program.model.lang.Processor;
|
||||||
|
import ghidra.program.model.listing.Instruction;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.pcode.PcodeOp;
|
||||||
|
import ghidra.program.model.symbol.RefType;
|
||||||
|
import ghidra.program.model.symbol.SourceType;
|
||||||
|
import ghidra.program.util.ContextEvaluator;
|
||||||
|
import ghidra.program.util.SymbolicPropogator;
|
||||||
|
import ghidra.program.util.VarnodeContext;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
public class HCS12ConstantAnalyzer extends ConstantPropagationAnalyzer {
|
||||||
|
|
||||||
|
private final static String PROCESSOR_NAME = "HCS12";
|
||||||
|
|
||||||
|
public HCS12ConstantAnalyzer() {
|
||||||
|
super(PROCESSOR_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAnalyze(Program program) {
|
||||||
|
boolean canAnalyze = program.getLanguage().getProcessor()
|
||||||
|
.equals(Processor.findOrPossiblyCreateProcessor(PROCESSOR_NAME));
|
||||||
|
|
||||||
|
if (!canAnalyze) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long hcs12TranslatePagedAddress(long addrWordOffset) {
|
||||||
|
|
||||||
|
long page = (addrWordOffset >> 16) & 0xff;
|
||||||
|
|
||||||
|
long addr = addrWordOffset & 0xffff;
|
||||||
|
|
||||||
|
// Register address
|
||||||
|
if ( (addr & 0xfC00) == 0x0) {
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EPage address
|
||||||
|
if ((addr & 0xfc00) ==0x800) {
|
||||||
|
return 0x100000 | ((page << 10) | (addr & 0x3ff));
|
||||||
|
}
|
||||||
|
|
||||||
|
// EPage FF fixed address
|
||||||
|
if ((addr & 0xfc00) ==0xC00) {
|
||||||
|
return (0x4FF << 10) | (addr & 0x3ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPage address
|
||||||
|
if ((addr & 0xf000) ==0x1000) {
|
||||||
|
return (page << 12) | (addr & 0xfff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPage FE fixed address
|
||||||
|
if ((addr & 0xf000) ==0x2000) {
|
||||||
|
return (0xFE << 12) | (addr & 0xfff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPage FF fixed address
|
||||||
|
if ((addr & 0xf000) ==0x3000) {
|
||||||
|
return (0xFF << 12) | (addr & 0xfff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PPage FD fixed address
|
||||||
|
if ((addr & 0xc000) ==0x4000) {
|
||||||
|
return 0x400000 | (0xFD << 14) | (addr & 0x3fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PPage address
|
||||||
|
if ((addr & 0xc000) ==0x8000) {
|
||||||
|
return 0x400000 | (page << 14) | (addr & 0x3fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PPage FF fixed address
|
||||||
|
if ((addr & 0xc000) ==0xC000) {
|
||||||
|
return 0x400000 | (0xFF << 14) | (addr & 0x3fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AddressSetView flowConstants(final Program program, Address flowStart, AddressSetView flowSet,
|
||||||
|
final SymbolicPropogator symEval, final TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
|
// follow all flows building up context
|
||||||
|
// use context to fill out addresses on certain instructions
|
||||||
|
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop,
|
||||||
|
Address address, int size, RefType refType) {
|
||||||
|
|
||||||
|
if ((refType.isRead() || refType.isWrite()) &&
|
||||||
|
adjustPagedAddress(instr, address, refType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return super.evaluateReference(context, instr, pcodeop, address, size, refType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Address evaluateConstant(VarnodeContext context, Instruction instr, int pcodeop, Address constant,
|
||||||
|
int size, RefType refType) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return super.evaluateConstant(context, instr, pcodeop, constant, size, refType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean adjustPagedAddress(Instruction instr, Address address, RefType refType) {
|
||||||
|
PcodeOp[] pcode = instr.getPcode();
|
||||||
|
for (PcodeOp op : pcode) {
|
||||||
|
int numin = op.getNumInputs();
|
||||||
|
if (numin < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (op.getOpcode() != PcodeOp.CALLOTHER) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String opName = instr.getProgram().getLanguage().getUserDefinedOpName(
|
||||||
|
(int) op.getInput(0).getOffset());
|
||||||
|
if (opName != null && opName.equals("segment") && numin > 2) {
|
||||||
|
// assume this is a poorly created segment op addr
|
||||||
|
long high = address.getOffset() >> 16;
|
||||||
|
long low = address.getOffset() & 0xffff;
|
||||||
|
address = address.getNewAddress((high << 14) | (low & 0x3fff));
|
||||||
|
makeReference(instr, address, refType);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle the reference on the correct read or write operand
|
||||||
|
private void makeReference(Instruction instr, Address address, RefType refType) {
|
||||||
|
int index = (refType.isRead() ? 1 : 0);
|
||||||
|
instr.addOperandReference(index, address, refType, SourceType.ANALYSIS);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.analysis;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import ghidra.app.services.AbstractAnalyzer;
|
||||||
|
import ghidra.app.services.AnalysisPriority;
|
||||||
|
import ghidra.app.services.AnalyzerType;
|
||||||
|
import ghidra.app.util.importer.MessageLog;
|
||||||
|
import ghidra.program.model.address.AddressSetView;
|
||||||
|
import ghidra.program.model.lang.Processor;
|
||||||
|
import ghidra.program.model.lang.Register;
|
||||||
|
import ghidra.program.model.lang.RegisterValue;
|
||||||
|
import ghidra.program.model.listing.Function;
|
||||||
|
import ghidra.program.model.listing.FunctionIterator;
|
||||||
|
import ghidra.program.model.listing.Instruction;
|
||||||
|
import ghidra.program.model.listing.InstructionIterator;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.symbol.SourceType;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
public class HCS12ConventionAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
|
private static final String NAME = "HCS12 Calling Convention";
|
||||||
|
private static final String DESCRIPTION = "Analyzes HCS12 programs with paged memory access to identify a calling convention for each function. This analyzer looks at the type of return used for the function to identify the calling convention.";
|
||||||
|
|
||||||
|
Register xgate = null;
|
||||||
|
|
||||||
|
public HCS12ConventionAnalyzer() {
|
||||||
|
super(NAME, DESCRIPTION, AnalyzerType.FUNCTION_ANALYZER);
|
||||||
|
setPriority(AnalysisPriority.FUNCTION_ANALYSIS);
|
||||||
|
setDefaultEnablement(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAnalyze(Program program) {
|
||||||
|
// Only analyze HCS12 Programs
|
||||||
|
Processor processor = program.getLanguage().getProcessor();
|
||||||
|
|
||||||
|
boolean canDo = processor.equals(Processor.findOrPossiblyCreateProcessor("HCS12"));
|
||||||
|
if (canDo) {
|
||||||
|
xgate = program.getRegister("XGATE");
|
||||||
|
}
|
||||||
|
|
||||||
|
return canDo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkReturn(Program program, Instruction instr) {
|
||||||
|
String mnemonic = instr.getMnemonicString().toLowerCase();
|
||||||
|
|
||||||
|
if (instr == null || !instr.getFlowType().isTerminal()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if XGATE set on instruction is XGATE
|
||||||
|
RegisterValue xgateValue = program.getProgramContext().getRegisterValue(xgate, instr.getMinAddress());
|
||||||
|
if (xgateValue != null && xgateValue.hasValue() && xgateValue.getUnsignedValue().equals(BigInteger.ONE)) {
|
||||||
|
setPrototypeModel(program, instr, "__asm_xgate");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the correct convention
|
||||||
|
if (mnemonic.equals("rtc")) {
|
||||||
|
setPrototypeModel(program, instr, "__asmA_longcall");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mnemonic.equals("rts")) {
|
||||||
|
setPrototypeModel(program, instr, "__asmA");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPrototypeModel(Program program, Instruction instr, String convention) {
|
||||||
|
if (convention == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Function func = program.getFunctionManager().getFunctionContaining(instr.getMinAddress());
|
||||||
|
if (func == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (func.getSignatureSource() != SourceType.DEFAULT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
func.setCallingConvention(convention);
|
||||||
|
} catch (InvalidInputException e) {
|
||||||
|
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
|
||||||
|
throws CancelledException {
|
||||||
|
|
||||||
|
// get all functions within the set
|
||||||
|
FunctionIterator functions = program.getFunctionManager().getFunctions(set, true);
|
||||||
|
for (Function function : functions) {
|
||||||
|
|
||||||
|
// for each function body, search instructions
|
||||||
|
AddressSetView body = function.getBody();
|
||||||
|
InstructionIterator instructions = program.getListing().getInstructions(body, true);
|
||||||
|
for (Instruction instr : instructions) {
|
||||||
|
if (instr.getFlowType().isTerminal()) {
|
||||||
|
checkReturn(program, instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.bin.format.elf.extend;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.format.elf.ElfConstants;
|
||||||
|
import ghidra.app.util.bin.format.elf.ElfHeader;
|
||||||
|
import ghidra.app.util.bin.format.elf.ElfLoadHelper;
|
||||||
|
import ghidra.app.util.bin.format.elf.ElfProgramHeader;
|
||||||
|
import ghidra.app.util.bin.format.elf.ElfProgramHeaderType;
|
||||||
|
import ghidra.app.util.bin.format.elf.ElfSectionHeader;
|
||||||
|
import ghidra.app.util.bin.format.elf.ElfSectionHeaderType;
|
||||||
|
import ghidra.app.util.bin.format.elf.ElfSymbol;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressSpace;
|
||||||
|
import ghidra.program.model.lang.Language;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
|
public class HCS12X_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
|
// Elf Program Header Extensions
|
||||||
|
public static final ElfProgramHeaderType PT_HCS12_ARCHEXT =
|
||||||
|
new ElfProgramHeaderType(0x70000000, "PT_HCS12X_ARCHEXT", "HCS12X extension");
|
||||||
|
|
||||||
|
// Elf Section Header Extensions
|
||||||
|
public static final ElfSectionHeaderType SHT_HCS12_ATTRIBUTES =
|
||||||
|
new ElfSectionHeaderType(0x70000003, "SHT_AHCS12_ATTRIBUTES", "Attribute section");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canHandle(ElfHeader elf) {
|
||||||
|
return elf.e_machine() == ElfConstants.EM_68HC12;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canHandle(ElfLoadHelper elfLoadHelper) {
|
||||||
|
Language language = elfLoadHelper.getProgram().getLanguage();
|
||||||
|
return canHandle(elfLoadHelper.getElfHeader()) &&
|
||||||
|
"HCS12".equals(language.getProcessor().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDataTypeSuffix() {
|
||||||
|
return "_HCS12";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Address getPreferredSegmentAddress(ElfLoadHelper elfLoadHelper, ElfProgramHeader elfProgramHeader) {
|
||||||
|
|
||||||
|
AddressSpace space =
|
||||||
|
getPreferredSegmentAddressSpace(elfLoadHelper, elfProgramHeader);
|
||||||
|
|
||||||
|
if (space.equals(AddressSpace.OTHER_SPACE)) {
|
||||||
|
return space.getAddress(elfProgramHeader.getVirtualAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
Program program = elfLoadHelper.getProgram();
|
||||||
|
|
||||||
|
long addrWordOffset = elfProgramHeader.getVirtualAddress();
|
||||||
|
|
||||||
|
if (space == program.getAddressFactory().getDefaultAddressSpace()) {
|
||||||
|
addrWordOffset += elfLoadHelper.getImageBaseWordAdjustmentOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
addrWordOffset = hcs12TranslatePagedAddress(addrWordOffset);
|
||||||
|
|
||||||
|
return space.getTruncatedAddress(addrWordOffset, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Address getPreferredSectionAddress(ElfLoadHelper elfLoadHelper,
|
||||||
|
ElfSectionHeader elfSectionHeader) {
|
||||||
|
|
||||||
|
// don't translate non-allocated sections
|
||||||
|
if (!elfSectionHeader.isAlloc()) {
|
||||||
|
return super.getPreferredSectionAddress(elfLoadHelper, elfSectionHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
Program program = elfLoadHelper.getProgram();
|
||||||
|
|
||||||
|
AddressSpace space = getPreferredSectionAddressSpace(elfLoadHelper, elfSectionHeader);
|
||||||
|
|
||||||
|
long addrWordOffset = elfSectionHeader.getAddress();
|
||||||
|
|
||||||
|
if (space == program.getAddressFactory().getDefaultAddressSpace()) {
|
||||||
|
addrWordOffset += elfLoadHelper.getImageBaseWordAdjustmentOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
addrWordOffset = hcs12TranslatePagedAddress(addrWordOffset);
|
||||||
|
|
||||||
|
return space.getTruncatedAddress(addrWordOffset, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long hcs12TranslatePagedAddress(long addrWordOffset) {
|
||||||
|
|
||||||
|
long page = (addrWordOffset >> 16) & 0xff;
|
||||||
|
|
||||||
|
long addr = addrWordOffset & 0xffff;
|
||||||
|
|
||||||
|
// Register address
|
||||||
|
if ( (addr & 0xfC00) == 0x0) {
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EPage address
|
||||||
|
if ((addr & 0xfc00) ==0x800) {
|
||||||
|
return 0x100000 | ((page << 10) | (addr & 0x3ff));
|
||||||
|
}
|
||||||
|
|
||||||
|
// EPage FF fixed address
|
||||||
|
if ((addr & 0xfc00) ==0xC00) {
|
||||||
|
return (0x4FF << 10) | (addr & 0x3ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPage address
|
||||||
|
if ((addr & 0xf000) ==0x1000) {
|
||||||
|
return (page << 12) | (addr & 0xfff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPage FE fixed address
|
||||||
|
if ((addr & 0xf000) ==0x2000) {
|
||||||
|
return (0xFE << 12) | (addr & 0xfff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPage FF fixed address
|
||||||
|
if ((addr & 0xf000) ==0x3000) {
|
||||||
|
return (0xFF << 12) | (addr & 0xfff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PPage FD fixed address
|
||||||
|
if ((addr & 0xc000) ==0x4000) {
|
||||||
|
return 0x400000 | (0xFD << 14) | (addr & 0x3fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PPage address
|
||||||
|
if ((addr & 0xc000) ==0x8000) {
|
||||||
|
return 0x400000 | (page << 14) | (addr & 0x3fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PPage FF fixed address
|
||||||
|
if ((addr & 0xc000) ==0xC000) {
|
||||||
|
return 0x400000 | (0xFF << 14) | (addr & 0x3fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Address evaluateElfSymbol(ElfLoadHelper elfLoadHelper, ElfSymbol elfSymbol,
|
||||||
|
Address address, boolean isExternal) {
|
||||||
|
|
||||||
|
if (isExternal) {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
String symName = elfSymbol.getNameAsString();
|
||||||
|
|
||||||
|
long laddr = address.getOffset();
|
||||||
|
|
||||||
|
laddr = hcs12TranslatePagedAddress(laddr);
|
||||||
|
|
||||||
|
Address mappedAddr = address.getNewAddress(laddr);
|
||||||
|
|
||||||
|
return mappedAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue