Merge remote-tracking branch 'origin/GT-3049_ghidorahrex_HCS12'

This commit is contained in:
ghidra1 2019-09-06 18:47:49 -04:00
commit 4a6e6697f4
21 changed files with 8220 additions and 21 deletions

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

View 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'

View 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|

View 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>

View 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>

View 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>

View 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>

View 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"

File diff suppressed because it is too large Load Diff

View 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);
}
}

View 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

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}