mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 13:42:06 +00:00
Merge remote-tracking branch 'origin/GT-3049_ghidorahrex_HCS12'
This commit is contained in:
commit
4a6e6697f4
@ -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 armDisassembleAction;
|
||||
private DockingAction armThumbDisassembleAction;
|
||||
private DockingAction hcs12DisassembleAction;
|
||||
private DockingAction xgateDisassembleAction;
|
||||
private DockingAction mipsDisassembleAction;
|
||||
private DockingAction mips16DisassembleAction;
|
||||
private DockingAction ppcDisassembleAction;
|
||||
@ -172,6 +174,8 @@ public class DisassemblerPlugin extends Plugin {
|
||||
contextAction = new ContextAction(this, GROUP_NAME);
|
||||
armDisassembleAction = new ArmDisassembleAction(this, GROUP_NAME, false);
|
||||
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);
|
||||
mips16DisassembleAction = new MipsDisassembleAction(this, GROUP_NAME, true);
|
||||
ppcDisassembleAction = new PowerPCDisassembleAction(this, GROUP_NAME, false);
|
||||
@ -183,6 +187,8 @@ public class DisassemblerPlugin extends Plugin {
|
||||
tool.addAction(disassembleStaticAction);
|
||||
tool.addAction(armDisassembleAction);
|
||||
tool.addAction(armThumbDisassembleAction);
|
||||
tool.addAction(hcs12DisassembleAction);
|
||||
tool.addAction(xgateDisassembleAction);
|
||||
tool.addAction(mipsDisassembleAction);
|
||||
tool.addAction(mips16DisassembleAction);
|
||||
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) {
|
||||
ProgramSelection currentSelection = context.getSelection();
|
||||
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
|
||||
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.
|
||||
@ -174,6 +197,27 @@ public class ElfLoadAdapter {
|
||||
// segment is not marked execute, use the data space by default
|
||||
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
|
||||
@ -429,5 +473,4 @@ public class ElfLoadAdapter {
|
||||
public Class<? extends ElfRelocation> getRelocationClass(ElfHeader elfHeader) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2170,16 +2170,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
private Address getPreferredSegmentLoadAddress(ElfProgramHeader elfProgramHeader)
|
||||
throws AddressOutOfBoundsException {
|
||||
|
||||
AddressSpace space =
|
||||
elf.getLoadAdapter().getPreferredSegmentAddressSpace(this, elfProgramHeader);
|
||||
|
||||
long addrWordOffset = elfProgramHeader.getVirtualAddress();
|
||||
|
||||
if (space == getDefaultAddressSpace()) {
|
||||
addrWordOffset += getImageBaseWordAdjustmentOffset();
|
||||
}
|
||||
|
||||
return space.getTruncatedAddress(addrWordOffset, true);
|
||||
return elf.getLoadAdapter().getPreferredSegmentAddress(this, elfProgramHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2216,15 +2207,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
private Address getPreferredSectionLoadAddress(ElfSectionHeader elfSectionHeader)
|
||||
throws AddressOutOfBoundsException {
|
||||
|
||||
AddressSpace space = getPreferredSectionAddressSpace(elfSectionHeader);
|
||||
|
||||
long addrWordOffset = elfSectionHeader.getAddress();
|
||||
|
||||
if (space == getDefaultAddressSpace()) {
|
||||
addrWordOffset += getImageBaseWordAdjustmentOffset();
|
||||
}
|
||||
|
||||
return space.getTruncatedAddress(addrWordOffset, true);
|
||||
return elf.getLoadAdapter().getPreferredSectionAddress(this, elfSectionHeader);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,8 +83,9 @@ public class CommitParamsAction extends AbstractDecompilerAction {
|
||||
if (hfunc.getFunction().getSignatureSource() == SourceType.USER_DEFINED) {
|
||||
source = SourceType.USER_DEFINED;
|
||||
}
|
||||
HighFunctionDBUtil.commitParamsToDatabase(hfunc, true, source);
|
||||
|
||||
HighFunctionDBUtil.commitReturnToDatabase(hfunc, source);
|
||||
HighFunctionDBUtil.commitParamsToDatabase(hfunc, true, source);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
throw new AssertException("Unexpected exception", e);
|
||||
|
@ -415,6 +415,8 @@ public class VariableUtilities {
|
||||
" bytes: " + curStorage.toString());
|
||||
}
|
||||
}
|
||||
|
||||
vnAddr = newReg.getAddress();
|
||||
if (bigEndian) {
|
||||
vnAddr = vnAddr.add(newReg.getMinimumByteSize() - 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…
Reference in New Issue
Block a user