/*
TargetContext.java
(c) 2010-2015 Edward Swartz
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
*/
package v9t9.tools.forthcomp;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import v9t9.common.asm.IRawInstructionFactory;
import v9t9.common.asm.RawInstruction;
import v9t9.common.machine.IBaseMachine;
import v9t9.common.memory.IMemoryDomain;
import v9t9.engine.memory.MemoryDomain;
import v9t9.engine.memory.MemoryEntry;
import v9t9.machine.ti99.memory.EnhancedRamByteArea;
import v9t9.tools.forthcomp.RelocEntry.RelocType;
import v9t9.tools.forthcomp.words.HostDoubleLiteral;
import v9t9.tools.forthcomp.words.HostLiteral;
import v9t9.tools.forthcomp.words.HostVariable;
import v9t9.tools.forthcomp.words.INativeCodeWord;
import v9t9.tools.forthcomp.words.StubWord;
import v9t9.tools.forthcomp.words.TargetCodeWord;
import v9t9.tools.forthcomp.words.TargetColonWord;
import v9t9.tools.forthcomp.words.TargetConstant;
import v9t9.tools.forthcomp.words.TargetDefer;
import v9t9.tools.forthcomp.words.TargetUserVariable;
import v9t9.tools.forthcomp.words.TargetValue;
import v9t9.tools.forthcomp.words.TargetVariable;
import v9t9.tools.forthcomp.words.TargetWord;
import ejs.base.utils.HexUtils;
import ejs.base.utils.Pair;
/**
* @author ejs
*
*/
public abstract class TargetContext extends Context implements ITargetContext {
private final boolean littleEndian;
private final int charBits;
private final int cellBits;
protected byte[] memory;
protected IRawInstructionFactory rawInstructionFactory;
protected Map<Integer, RelocEntry> relocEntries = new TreeMap<Integer, RelocEntry>();
protected List<RelocEntry> relocs = new ArrayList<RelocEntry>();
private Map<Integer, String> symbols = new TreeMap<Integer, String>();
protected int dp;
private Map<String, DictEntry> dictEntryMap = new LinkedHashMap<String, DictEntry>();
private DictEntry lastEntry;
private DictEntry lastExportedEntry;
/** in bytes */
protected int cellSize;
private boolean export;
private int baseDP;
protected PrintStream logfile = System.out;
private Map<String, ForwardRef> forwards;
private List<StubWord> stubWords = new ArrayList<StubWord>();
public DictEntry stubData;
private boolean exportFlagNext;
private boolean exportFlag;
//private boolean inlineFlagNext;
protected HostContext hostCtx;
private List<Integer> leaves;
private boolean testMode;
protected IWord romDeferTableWord;
private TargetConstant numRomDefersWord;
private Map<TargetDefer, Integer> targetDefers = new HashMap<TargetDefer, Integer>();
private MemoryDomain console;
public TargetContext(boolean littleEndian, int charBits, int cellBits, int memorySize) {
this.littleEndian = littleEndian;
this.charBits = charBits;
this.cellBits = cellBits;
this.cellSize = cellBits / 8;
this.memory = new byte[memorySize];
this.forwards = new LinkedHashMap<String,ForwardRef>();
this.export = true;
leaves = new LinkedList<Integer>();
stubData = defineStub("<<data space>>");
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#setHostContext(v9t9.tools.forthcomp.HostContext)
*/
@Override
public void setHostContext(HostContext hostCtx) {
this.hostCtx = hostCtx;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.Context#define(java.lang.String, v9t9.tools.forthcomp.IWord)
*/
@Override
public IWord define(String string, IWord word) {
if (word instanceof TargetWord) {
logfile.println("T>"+ HexUtils.toHex4(((TargetWord) word).getEntry().getAddr()) +" "
//+ ((TargetWord) word).getClass().getSimpleName() + " " + string
+ word
);
resolveForward(((ITargetWord) word).getEntry());
}
return super.define(string, word);
}
protected DictEntry defineStub(String name) {
StubWord stubWord = new StubWord(name);
//getDictionary().put(name, stubWord.getEntry());
stubWords.add(stubWord);
return stubWord.getEntry();
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.ITargetContext#defineColonPrims()
*/
@Override
public void defineColonPrims() throws AbortException {
defineConstant("#CHAR", 1, 1);
defineConstant("#CELL", getCellSize(), 1);
setExportNext(false);
defineConstant("TESTING?", isTestMode() ? -1 : 0, 1);
defineConstant("LOCALS", isLocalSupportAvailable(hostCtx) ? -1 : 0, 1);
defineConstant("GROM-DICT", this instanceof IGromTargetContext
&& ((BaseGromTargetContext) this).useGromDictionary() ? -1 : 0, 1);
romDeferTableWord = find("(rdefertbl)");
if (romDeferTableWord == null) {
romDeferTableWord = defineForward("(rdefertbl)", "<builtin>");
}
setExportNext(false);
numRomDefersWord = defineConstant("(#rdefers)", 0, 1);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#defineBuiltins()
*/
public void definePrims() throws AbortException {
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.ITargetContext#defineCompilerWords(v9t9.tools.forthcomp.HostContext)
*/
@Override
public void defineCompilerWords(HostContext hostContext) {
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#readCell(int)
*/
@Override
public int readCell(int addr) {
if (addr < 0) {
addr = resolveAddr(addr);
}
return readCell(memory, addr);
}
protected int readCell(byte[] memory, int addr) {
if (!littleEndian && cellBits == 16) {
addr &= 0xffff;
return (short) ((memory[addr] & 0xff) << 8) | (memory[addr + 1] & 0xff);
} else {
throw new UnsupportedOperationException();
}
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#readAddr(int)
*/
@Override
public int readAddr(int addr) {
if (addr < 0) {
addr = resolveAddr(addr);
}
else {
// see if this is a relocated entry
RelocEntry reloc = relocEntries.get(addr);
if (reloc != null)
return -relocs.indexOf(reloc) - 1;
}
if (!littleEndian && cellBits == 16) {
return ((memory[addr] & 0xff) << 8) | (memory[addr + 1] & 0xff);
} else {
throw new UnsupportedOperationException();
}
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#addRelocation(int, v9t9.tools.forthcomp.RelocEntry.RelocType, int)
*/
@Override
public int addRelocation(int addr, RelocType type, int target) {
RelocEntry reloc = new RelocEntry(addr, type, target);
assert !relocEntries.containsKey(addr);
relocEntries.put(addr, reloc);
relocs.add(reloc);
return -relocs.size();
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#getDP()
*/
@Override
public int getDP() {
return dp;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#setDP(int)
*/
@Override
public void setDP(int dp) {
this.dp = dp;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#alloc(int)
*/
@Override
public int alloc(int size) {
int old = dp;
// clear out alloc'd space in case another word wrote temp stuff here
while (size-- > 0) {
writeChar(dp++, 0);
}
return old;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#allocCell()
*/
@Override
public int allocCell() {
stubData.use(cellSize);
return alloc(cellSize);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#resolveAddr(int)
*/
@Override
public int resolveAddr(int relocIndex) {
// read actual contents
RelocEntry reloc = relocs.get(-relocIndex - 1);
if (reloc == null)
throw new IllegalArgumentException();
relocIndex = reloc.addr;
return relocIndex;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#findReloc(int)
*/
@Override
public int findReloc(int addr) {
RelocEntry reloc = relocEntries.get(addr);
if (reloc == null)
return 0;
return reloc.target;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#removeReloc(int)
*/
@Override
public void removeReloc(int addr) {
relocEntries.remove(addr);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#getRelocEntry(int)
*/
@Override
public RelocEntry getRelocEntry(int id) {
return relocs.get(-id - 1);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#defineEntry(java.lang.String)
*/
@Override
public DictEntry defineEntry(String name) {
boolean doExport = currentExport();
alignDP();
int entryAddr = getDP();
int size = 0;
//boolean doInline = inlineFlagNext;
exportFlagNext = false;
//inlineFlagNext = false;
DictEntry entry = createDictEntry(size, entryAddr, name, doExport);
entry.setExport(doExport);
if (doExport && hostCtx != null) {
ITargetWord word = (ITargetWord) find(">latest");
if (word != null) {
try {
word.getExecutionSemantics().execute(hostCtx, this);
//System.out.println("Latest: " + HexUtils.toHex4(entryAddr));
writeCell(hostCtx.popData(), entry.getAddr());
} catch (AbortException e) {
e.printStackTrace();
}
}
}
DictEntry existing = dictEntryMap.get(name.toUpperCase());
if (existing != null) {
logfile.println("*** Redefining " + name);
System.err.println("*** Redefining " + name);
}
dictEntryMap.put(name.toUpperCase(), entry);
if (lastEntry != null)
lastEntry.setEndAddr(entry.getAddr());
lastEntry = entry;
if (hostCtx != null)
hostCtx.setLatest(hostCtx.getDictionary().get(name.toUpperCase()));
setLatest(getDictionary().get(name.toUpperCase()));
if (doExport) {
if (lastExportedEntry != null) {
entry.setLink(lastExportedEntry.getAddr());
}
entry.writeEntry(this);
lastExportedEntry = entry;
}
symbols.put(entry.getContentAddr(), name);
return entry;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.ITargetContext#resolveForward(v9t9.tools.forthcomp.DictEntry)
*/
@Override
public void resolveForward(DictEntry entry) {
String name = entry.getName().toUpperCase();
ForwardRef ref = forwards.get(name);
if (ref != null) {
resolveForward(ref, entry);
forwards.remove(name);
}
}
public ITargetWord require(String token) {
ITargetWord word = (ITargetWord) find(token);
if (word == null) {
word = defineForward(token, hostCtx.getStream().getLocation());
}
return word;
//return (ITargetWord) super.require(token);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#getLastEntry()
*/
@Override
public DictEntry getLastEntry() {
return lastEntry;
}
/**
* @param size
* @param entryAddr
* @param name
* @param doExport TODO
* @return
*/
protected DictEntry createDictEntry(int size, int entryAddr, String name, boolean doExport) {
if (doExport) {
// link, name
size = cellSize + align(1 + name.length());
alignDP();
stubData.use(size);
entryAddr = alloc(size);
}
return new DictEntry(size, entryAddr, name);
}
private boolean currentExport() {
boolean doExport = export;
if (exportFlagNext)
doExport = exportFlag;
return doExport;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#defineForward(java.lang.String, java.lang.String)
*/
@Override
public ITargetWord defineForward(String token, String location) {
token = token.toUpperCase();
ForwardRef ref = forwards.get(token);
if (ref == null) {
ref = new ForwardRef(token, location, -relocs.size() - 1);
relocs.add(new RelocEntry(0, RelocType.RELOC_FORWARD, ref.getId()));
}
forwards.put(token, ref);
return ref;
}
/**
* @param ref
*/
private void resolveForward(ForwardRef ref, DictEntry entry) {
for (RelocEntry rel : relocs) {
if (rel.target == ref.getId()) {
rel.target = entry.getContentAddr();
if (rel.type != RelocType.RELOC_FORWARD)
writeCell(rel.addr, entry.getContentAddr());
}
}
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#alignDP()
*/
@Override
public void alignDP() {
dp = getAlignedDP();
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#getAlignedDP()
*/
@Override
public int getAlignedDP() {
return (dp + cellSize - 1) & ~(cellSize - 1);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#align(int)
*/
@Override
public int align(int bytes) {
return (bytes + cellSize - 1) & ~(cellSize - 1);
}
/* (non-Javadoc)
* @see v9t9.forthcomp.words.TargetContext#convertCell(int)
*/
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#writeCell(byte[], int, int)
*/
@Override
public int writeCell(byte[] memory, int offs, int cell) {
if (!littleEndian && cellBits == 16) {
memory[offs++] = (byte) (cell >> 8);
memory[offs++] = (byte) (cell & 0xff);
} else {
throw new UnsupportedOperationException();
}
return offs;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#writeCell(int, int)
*/
@Override
public void writeCell(int addr, int cell) {
if (addr < 0)
addr = relocs.get(-addr - 1).target;
RelocEntry entry = relocEntries.get(addr);
if (entry != null)
cell = -relocs.indexOf(entry) - 1; // flag
writeCell(memory, addr, cell);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#writeChar(int, int)
*/
@Override
public void writeChar(int addr, int ch) {
if (charBits != 8) throw new UnsupportedOperationException();
memory[addr] = (byte) ch;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#getCellSize()
*/
@Override
public int getCellSize() {
return cellSize;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#readChar(int)
*/
@Override
public int readChar(int addr) {
if (charBits != 8) throw new UnsupportedOperationException();
return memory[addr];
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#create(java.lang.String, int)
*/
@Override
public TargetVariable create(String name, int bytes) {
DictEntry entry = defineEntry(name);
int dp = entry.getContentAddr();
initWordEntry();
compileDoVar();
stubData.use(bytes);
int loc = alloc(bytes);
entry.setCodeSize(loc - dp);
final TargetVariable var = (TargetVariable) define(name, new TargetVariable(entry));
return var;
}
/** Compile code that will push the parameter area's address */
abstract protected void compileDoVar();
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#defineColonWord(java.lang.String)
*/
@Override
public TargetColonWord defineColonWord(String name) {
DictEntry entry = createColonEntry(name);
final TargetColonWord colon = (TargetColonWord) define(name, new TargetColonWord(entry));
return colon;
}
/**
* @param name
* @return
*/
protected DictEntry createColonEntry(String name) {
DictEntry entry = defineEntry(name);
initWordEntry();
leaves.clear();
return entry;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#defineConstant(java.lang.String, int, int)
*/
@Override
public TargetConstant defineConstant(String name, int value, int cells) throws AbortException {
// logfile.println("T> CONSTANT " + name);
boolean mustDefine = currentExport();
if (!mustDefine) {
mustDefine = isForcedExport(name);
}
DictEntry entry;
if (mustDefine) {
entry = defineEntry(name);
initWordEntry();
if (isNativeDefinition())
compileDoConstant(value, cells);
} else {
entry = new DictEntry(0, getDP(), name);
exportFlagNext = false;
// assume address
//if (isLikelyAddress(value))
symbols.put(value, name);
}
if (!isNativeDefinition() && mustDefine)
compileDoConstant(value, cells);
entry.setCodeSize(getDP() - entry.getAddr() - cells * cellSize);
final TargetConstant constant = (TargetConstant) define(name, new TargetConstant(entry, value, 1));
return constant;
}
/**
* @param value
* @return
*/
abstract protected boolean isLikelyAddress(int value);
/**
* @param name
* @param forwardRef
*/
protected void warnForcedWord(String name, ForwardRef forwardRef) {
System.err.println("*** WARNING: forward reference to : " +name + " forces dictionary definition from "
+ forwardRef.getLocation());
}
protected void defineSymbol(int addr, String name) {
symbols.put(addr, name);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#defineValue(java.lang.String, int, int)
*/
@Override
public TargetValue defineValue(String name, int value, int cells) throws AbortException {
DictEntry entry = defineEntry(name);
// logfile.println("T> VALUE " + name);
int origDp = entry.getContentAddr();
int loc = compilePushValue(cells, value);
entry.setCodeSize(loc - origDp);
final TargetValue tvalue = (TargetValue) define(name, new TargetValue(entry, cells));
return tvalue;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#defineUser(java.lang.String, int)
*/
@Override
public TargetUserVariable defineUser(String name, int bytes) throws AbortException {
// logfile.println("T> USER " + name);
// the "variable" will be frozen in ROM, a count of bytes
TargetVariable up = findOrCreateVariable("UP0");
int paramAddr = up.getEntry().getParamAddr();
int offset = readCell(paramAddr);
writeCell(paramAddr, offset + bytes);
boolean mustDefine = currentExport();
if (!mustDefine) {
mustDefine = isForcedExport(name);
}
DictEntry entry;
if (mustDefine) {
entry = defineEntry(name);
initWordEntry();
if (isNativeDefinition())
compileDoUser(offset);
} else {
entry = new DictEntry(0, getDP(), name);
exportFlagNext = false;
symbols.put(entry.getAddr(), name);
}
if (!isNativeDefinition())
compileDoUser(offset);
return (TargetUserVariable) define(name, new TargetUserVariable(entry, offset));
}
/**
* @param name
* @return
*/
protected boolean isForcedExport(String name) {
ForwardRef forwardRef = forwards.get(name.toUpperCase());
if (forwardRef != null) {
warnForcedWord(name, forwardRef);
return true;
}
return false;
}
@Override
public TargetDefer defineRomDefer(String name) throws AbortException {
// the defer location is an offset into a table initialized later
DictEntry entry;
entry = defineEntry(name);
initWordEntry();
// the "variable" will be frozen in ROM, a count of bytes
int paramAddr = numRomDefersWord.getEntry().getParamAddr();
int offset = readCell(paramAddr);
int newOffset = offset + getCellSize();
writeCell(paramAddr, newOffset);
numRomDefersWord.setValue(newOffset);
compileDoRomDefer(offset);
TargetDefer defer = new TargetDefer(entry, offset);
targetDefers.put(defer, null);
return (TargetDefer) define(name, defer);
}
protected TargetVariable findOrCreateVariable(String name) {
TargetVariable var = (TargetVariable) find(name);
if (var == null) {
setExportNext(false);
var = create(name, getCellSize());
}
return var;
}
@Override
public void exportMemory(IMemoryDomain console) throws AbortException {
for (int i = baseDP; i < dp; i += cellSize) {
console.writeWord(i, (short) readCell(i));
}
for (RelocEntry reloc : relocEntries.values()) {
int val = doResolveRelocation(reloc);
console.writeWord(reloc.addr, (short) val);
}
for (int i = baseDP; i < dp; i += MemoryDomain.AREASIZE)
console.getEntryAt(i).clearSymbols();
for (Map.Entry<Integer, String> symEntry : symbols.entrySet()) {
console.getEntryAt(symEntry.getKey()).defineSymbol(symEntry.getKey(), symEntry.getValue());
}
}
protected int doResolveRelocation(RelocEntry reloc) throws AbortException {
if (reloc.type == RelocType.RELOC_ABS_ADDR_16)
return reloc.target;
throw abort("unhandled relocation: " + reloc);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#importMemory(v9t9.common.memory.IMemoryDomain)
*/
@Override
public void importMemory(IMemoryDomain console) {
for (int i = 0; i < memory.length; i += cellSize) {
RelocEntry reloc = relocEntries.get(i);
if (reloc == null) {
short val = console.readWord(i);
writeCell(i, val);
}
}
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#clearDict()
*/
@Override
public void clearDict() {
super.clearDict();
dp = 0;
relocs.clear();
relocEntries.clear();
lastEntry = null;
lastExportedEntry = null;
Arrays.fill(memory, (byte) 0);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#setExport(boolean)
*/
@Override
public void setExport(boolean export) {
this.export = export;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#isExport()
*/
@Override
public boolean isExport() {
return export;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#setExportNext(boolean)
*/
@Override
public void setExportNext(boolean export) {
this.exportFlag = export;
this.exportFlagNext = true;
}
public interface IMemoryReader {
int readWord(int addr);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#dumpDict(java.io.PrintStream, int, int)
*/
@Override
public void dumpDict(PrintStream out, int from, int to) {
dumpMemory(out, from, to, new IMemoryReader() {
public int readWord(int addr) {
return readCell(addr);
}
});
}
public static void dumpMemory(PrintStream out, int from, int to, IMemoryReader reader) {
int perLine = 8;
int lines = ((to - from) / 2 + perLine - 1) / perLine;
int addr = from;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < lines; i++) {
boolean allZero = true;
for (int j = 0; j < perLine && addr < to; j++) {
if (reader.readWord(addr + j) != 0) {
allZero = false;
break;
}
}
if (allZero) {
addr += perLine * 2;
continue;
}
out.print(HexUtils.toHex4(addr) + ": ");
sb.setLength(0);
int j;
for (j = 0; j < perLine && addr < to; j++) {
int word = reader.readWord(addr);
out.print(HexUtils.toHex4(word) + " ");
addr += 2;
int ch = ((word >> 8) & 0xff);
if (ch >= 0x20 && ch < 0x7f)
sb.append((char) ch);
else
sb.append('.');
ch = (word & 0xff);
if (ch >= 0x20 && ch < 0x7f)
sb.append((char) ch);
else
sb.append('.');
}
for (; j < perLine ; j++) {
out.print(" ");
}
out.print(' ');
out.print(sb);
out.println();
}
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#getBaseDP()
*/
@Override
public int getBaseDP() {
return baseDP;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#setBaseDP(int)
*/
@Override
public void setBaseDP(int baseDP) {
this.baseDP = baseDP;
if (dp == 0)
dp = baseDP;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#setLog(java.io.PrintStream)
*/
@Override
public void setLog(PrintStream logfile) {
this.logfile = logfile != null ? logfile : System.out;
}
/**
* @return the logfile
*/
public PrintStream getLog() {
return logfile;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#getForwardRefs()
*/
@Override
public Collection<ForwardRef> getForwardRefs() {
return forwards.values();
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#getTargetDictionary()
*/
@Override
public Map<String, DictEntry> getTargetDictionary() {
return dictEntryMap;
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#find(java.lang.String)
*/
@Override
public IWord find(String token) {
if (getLatest() != null) {
DictEntry entry = ((ITargetWord) getLatest()).getEntry();
if (entry.hasLocals()) {
IWord word = entry.findLocalWord(token);
if (word != null) {
return word;
}
}
}
return super.find(token);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#compileExit(v9t9.tools.forthcomp.HostContext)
*/
@Override
public void compileExit(HostContext hostContext) throws AbortException {
if (getLatest() != null && ((ITargetWord) getLatest()).getEntry().hasLocals())
compileCleanupLocals(hostContext);
//buildCall(require(";S"));
//require(";S").getCompilationSemantics().execute(hostContext, this);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#compileToValue(v9t9.tools.forthcomp.HostContext, v9t9.tools.forthcomp.words.TargetValue)
*/
@Override
public void compileToValue(HostContext hostContext, TargetValue word) throws AbortException {
compileWordParamAddr(word);
require("!").getCompilationSemantics().execute(hostContext, this);
}
public void compileToRomDefer(HostContext hostContext, TargetDefer word) throws AbortException {
compileWordParamAddr(word);
require("!").getCompilationSemantics().execute(hostContext, this);
}
protected abstract void doExportState(HostContext hostCtx, IBaseMachine machine,
int baseSp, int baseRp, int baseUp) throws AbortException;
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#exportState(v9t9.tools.forthcomp.HostContext, v9t9.common.machine.IBaseMachine, int, int, int)
*/
@Override
public void exportState(HostContext hostCtx, IBaseMachine machine,
int baseSp, int baseRp, int baseUp) throws AbortException {
IWord dp = find("DP");
if (dp instanceof ITargetWord) {
writeCell(((ITargetWord) dp).getEntry().getParamAddr(), getDP());
}
doExportState(hostCtx, machine, baseSp, baseRp, baseUp);
}
protected abstract void doImportState(HostContext hostCtx, IBaseMachine machine,
int baseSp, int baseRp);
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#importState(v9t9.tools.forthcomp.HostContext, v9t9.common.machine.IBaseMachine, int, int)
*/
@Override
public void importState(HostContext hostCtx, IBaseMachine machine,
int baseSp, int baseRp) {
doImportState(hostCtx, machine, baseSp, baseRp);
IWord dp = find("DP");
if (dp instanceof ITargetWord) {
setDP(readCell(((ITargetWord) dp).getEntry().getParamAddr()));
}
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#writeLengthPrefixedString(java.lang.String)
*/
@Override
public Pair<Integer, Integer> writeLengthPrefixedString(String string) throws AbortException {
int length = string.length();
if (length > 255)
throw new AbortException("String constant is too long");
int dp = getDP();
writeChar(dp, length);
stubData.use();
for (int i = 0; i < length; i++) {
writeChar(dp + 1 + i, string.charAt(i));
stubData.use();
}
return new Pair<Integer, Integer>(dp, length + 1);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#markHostExecutionUnsupported()
*/
@Override
public void markHostExecutionUnsupported() {
((TargetWord) getLatest()).setHostDp(-1);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#compileString(v9t9.tools.forthcomp.HostContext, java.lang.String)
*/
@Override
public Pair<Integer, Integer> buildPushString(HostContext hostContext, String string) throws AbortException {
ITargetWord parenString = (ITargetWord)require("(s\")");
buildCall((ITargetWord) parenString);
Pair<Integer, Integer> info = writeLengthPrefixedString(string);
setDP(getDP() + info.second);
return info;
}
public void buildXt(int addr) {
if (isNativeDefinition()) {
assert false;
} else {
int ptr = alloc(cellSize);
int reloc = addRelocation(ptr,
RelocType.RELOC_ABS_ADDR_16,
addr);
writeCell(ptr, reloc);
}
}
public void buildXt(ITargetWord word) {
if (isNativeDefinition()) {
compileTick(word);
} else {
logfile.println("T>" + HexUtils.toHex4(getDP()) + " = " + word.getName());
buildXt(word.getEntry().getContentAddr());
}
}
public void buildCall(ITargetWord word) throws AbortException {
if (isNativeDefinition()) {
compile(word);
} else {
buildXt(word);
}
}
public void buildLiteral(int val, boolean isUnsigned, boolean optimize) throws AbortException {
if (isNativeDefinition()) {
compileLiteral(val, isUnsigned, optimize);
} else {
IWord word = find(Integer.toString(val));
if (word instanceof ITargetWord) {
buildCall((ITargetWord) word);
} else {
buildCall(require("DOLIT"));
buildCell(val);
}
}
}
public void buildDoubleLiteral(int valLo, int valHi, boolean isUnsigned, boolean optimize) throws AbortException {
if (isNativeDefinition()) {
compileDoubleLiteral(valLo, valHi, isUnsigned, optimize);
} else {
buildCall(require("DODLIT"));
buildCell(valLo);
buildCell(valHi);
}
}
public void buildTick(ITargetWord word) throws AbortException {
if (isNativeDefinition()) {
compileTick(word);
} else {
buildCall(require("DOLIT"));
buildXt(word);
}
}
public void buildUser(TargetUserVariable user) throws AbortException {
if (isNativeDefinition()) {
compileDoUser(user.getOffset());
} else {
buildCall(require("DOUSER"));
buildCell(user.getOffset());
}
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#getUP()
*/
@Override
public int getUP() {
TargetVariable up = findOrCreateVariable("UP0");
return readCell(up.getEntry().getParamAddr());
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#dumpStubs(java.io.PrintStream)
*/
@Override
public void dumpStubs(PrintStream logfile) {
logfile.println("Stub uses:");
for (StubWord word : stubWords) {
logfile.println("\t"+word.getName() + " = " + word.getEntry().getUses());
}
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.words.ITargetContext#parseLiteral(java.lang.String)
*/
@Override
public IWord parseLiteral(String token) {
int radix = ((HostVariable) hostCtx.find("base")).getValue();
boolean isNeg = token.startsWith("-");
if (isNeg) {
token = token.substring(1);
}
if (token.startsWith("$")) {
radix = 16;
token = token.substring(1);
}
else if (token.startsWith("&")) {
radix = 10;
token = token.substring(1);
}
boolean isDouble = false;
if (token.contains(".")) {
isDouble = true;
}
token = token.replaceAll("\\.", "");
boolean isUnsigned = false;
if (token.toUpperCase().endsWith("U")) {
isUnsigned = true;
token = token.substring(0, token.length() - 1);
}
try {
long val = Long.parseLong(token, radix);
if (isNeg)
val = -val;
if (isDouble) {
if (getCellSize() == 2)
return new HostDoubleLiteral((int)(val & 0xffff), (int)(val >> 16), isUnsigned);
else
throw new UnsupportedOperationException();
}
else
return new HostLiteral((int) val, isUnsigned);
} catch (NumberFormatException e) {
return null;
}
}
/* (non-Javadoc)
* @see v9t9.forthcomp.TargetContext#pushLeave(v9t9.forthcomp.HostContext)
*/
@Override
public void pushLeave(HostContext hostContext) {
// add fixup to a list
pushFixup(hostContext);
leaves.add(hostContext.popData());
}
abstract protected int writeJump(int opAddr, int target)
throws AbortException;
abstract protected void writeJumpAlloc(int target, boolean conditional)
throws AbortException;
/* (non-Javadoc)
* @see v9t9.forthcomp.TargetContext#pushFixup()
*/
@Override
public void pushFixup(HostContext hostContext) {
// a fixup needs the memory loc of the offset to update
// as well as the original PC of the referring instruction
int nextDp = getDP();
hostContext.pushData(nextDp);
hostContext.markFixup(nextDp);
}
/* (non-Javadoc)
* @see v9t9.forthcomp.TargetContext#pushHere(v9t9.forthcomp.HostContext)
*/
@Override
public int pushHere(HostContext hostContext) {
int nextDp = getDP();
hostContext.pushData(nextDp);
hostContext.markFixup(nextDp);
return nextDp;
}
/* (non-Javadoc)
* @see v9t9.forthcomp.TargetContext#swapFixup()
*/
@Override
public void swapFixup(HostContext hostContext) {
int d0 = hostContext.popData();
int e0 = hostContext.popData();
hostContext.pushData(d0);
hostContext.pushData(e0);
}
/* (non-Javadoc)
* @see v9t9.forthcomp.TargetContext#resolveFixup()
*/
@Override
public void resolveFixup(HostContext hostContext) throws AbortException {
int nextDp = getDP();
int opAddr = hostContext.popData();
//int diff = nextDp - opAddr;
writeJump(opAddr, nextDp);
hostContext.resolveFixup(opAddr, nextDp);
}
/* (non-Javadoc)
* @see v9t9.forthcomp.TargetContext#resolveFixup()
*/
@Override
public void compileBack(HostContext hostContext, boolean conditional) throws AbortException {
//int nextDp = getDP();
int opAddr = hostContext.popData();
writeJumpAlloc(opAddr, conditional);
//hostContext.build(new Host0Branch(hostContext.require("0branch"));
}
/* (non-Javadoc)
* @see v9t9.forthcomp.TargetContext#createMemory()
*/
@Override
public MemoryDomain createMemory() {
console = new MemoryDomain(IMemoryDomain.NAME_CPU, false);
EnhancedRamByteArea bigRamArea = new EnhancedRamByteArea(0, 0x10000);
MemoryEntry bigRamEntry = new MemoryEntry("RAM", console, 0, MemoryDomain.PHYSMEMORYSIZE,
bigRamArea);
console.mapEntry(bigRamEntry);
return console;
}
/**
* @return
*/
public IMemoryDomain getMemory() {
return console;
}
/* (non-Javadoc)
* @see v9t9.forthcomp.TargetContext#compileAddr(int)
*/
@Override
public void buildCell(int loc) {
int ptr = alloc(cellSize);
writeCell(ptr, loc);
}
/* (non-Javadoc)
* @see v9t9.forthcomp.TargetContext#compileChar(int)
*/
@Override
public void buildChar(int val) {
int ptr = alloc(1);
writeChar(ptr, val);
}
/* (non-Javadoc)
* @see v9t9.tools.forthcomp.ITargetContext#isNativeDefinition()
*/
@Override
public boolean isNativeDefinition() {
return getLatest() instanceof INativeCodeWord;
}
/* (non-Javadoc)
* @see v9t9.forthcomp.TargetContext#loopCompile(v9t9.forthcomp.HostContext, v9t9.forthcomp.ITargetWord)
*/
@Override
public void loopCompile(HostContext hostCtx, ITargetWord loopCaller)
throws AbortException {
hostCtx.compileWord(this, null, loopCaller);
boolean isQDo = hostCtx.popData() != 0;
int opAddr = hostCtx.popData();
writeLoopJump(opAddr);
if (isQDo) {
// then comes here
resolveFixup(hostCtx);
}
for (int i = 0; i < leaves.size(); i++) {
hostCtx.pushData(leaves.get(i));
resolveFixup(hostCtx);
}
leaves.clear();
ITargetWord unloop = require("unloop");
hostCtx.compileWord(this, null, unloop);
//unloop.getCompilationSemantics().execute(hostCtx, this);
}
abstract protected void writeLoopJump(int opAddr) throws AbortException;
/**
* @param token
* @param tokenStream
* @throws AbortException
*/
public void parse(String token) throws AbortException {
IWord word = null;
int state = hostCtx.readVar("state");
if (state == 0) {
word = hostCtx.find(token);
if (word == null) {
word = find(token);
}
if (word instanceof ITargetWord && ((ITargetWord) word).getEntry().isTargetOnly()) {
word = null;
}
if (word == null) {
word = parseLiteral(token);
}
if (word == null) {
throw abort("unknown word or literal: " + token);
}
if (word.getInterpretationSemantics() == null)
throw abort(word.getName() + " has no interpretation semantics");
// if (HostContext.DEBUG) System.out.println(
// //stack() + "\n" +
// "H> exec " + word);
word.getInterpretationSemantics().execute(hostCtx, this);
} else {
word = find(token);
if (word == null) {
word = hostCtx.find(token);
}
if (word == null) {
word = parseLiteral(token);
}
if (word == null) {
word = defineForward(token, hostCtx.getStream().getLocation());
}
ITargetWord targetWord = null;
IWord hostWord = null;
if (word instanceof ITargetWord) {
targetWord = (ITargetWord) word;
hostWord = hostCtx.find(token);
if (hostWord == null)
hostWord = targetWord;
} else {
if (word.getCompilationSemantics() == null) {
throw hostCtx.abort("host word " + token + " used instead of target word");
}
hostWord = word;
targetWord = null;
if (!word.isCompilerWord()) {
targetWord = (ITargetWord) defineForward(token,
hostCtx.getStream().getLocation());
//throw hostContext.abort("host word " + token + " used instead of target word");
}
}
hostCtx.compileWord(this, hostWord, targetWord);
}
}
private AbortException abort(String string) {
return hostCtx.getStream().abort(string);
}
/**
* @param doTest
*/
public void setTestMode(boolean doTest) {
this.testMode = doTest;
}
/**
* @return the testMode
*/
public boolean isTestMode() {
return testMode;
}
public void setDeferTarget(TargetDefer defer, int addr) {
for (DictEntry entry : dictEntryMap.values()) {
if (entry.getContentAddr() == addr) {
defer.setHostPc(entry.getTargetWord().getHostDp());
break;
}
}
targetDefers.put(defer, addr);
}
/**
*
*/
public void resolveRomDefers() throws AbortException {
ITargetWord to = null;
ITargetWord hang = null;
for (Map.Entry<TargetDefer, Integer> defEnt : targetDefers.entrySet()) {
Integer target = defEnt.getValue();
if (target == null) {
System.err.println("DEFER'ed word " + defEnt.getKey() + " not assigned with TO");
if (hang == null) {
hang = require("HANG");
}
target = hang.getEntry().getContentAddr();
}
if (to == null) {
to = require("(TO)");
}
buildLiteral(target, true, false);
buildTick(defEnt.getKey());
buildCall(to);
}
}
/**
* @param index
* @throws AbortException
*/
public void buildFromLocal(int index) throws AbortException {
if (isNativeDefinition())
compileFromLocal(index);
else {
buildCall(require("(LOCAL@)"));
buildCell(index);
}
}
public void buildToLocal(int index) throws AbortException {
if (isNativeDefinition())
compileToLocal(index);
else {
buildCall(require("(LOCAL!)"));
buildCell(index);
}
}
/**
* @param hostContext
* @param word
* @throws AbortException
*/
public void buildToValue(HostContext hostContext, TargetValue word) throws AbortException {
if (isNativeDefinition())
compileToValue(hostContext, word);
else {
buildXt(word);
buildCall(require("(TO)"));
}
}
/**
* @param hostContext
* @param word
* @throws AbortException
*/
public void buildToRomDefer(HostContext hostContext, TargetDefer word) throws AbortException {
if (isNativeDefinition())
compileToRomDefer(hostContext, word);
else {
buildXt(word);
buildCall(require("(RDEFER!)"));
}
}
public TargetCodeWord defineCodeWord(String name) {
TargetCodeWord word = (TargetCodeWord) define(name, new TargetCodeWord(defineEntry(name)));
alignDP();
// word.setDP(getDP());
return word;
}
public void disassemble(TargetCodeWord word) {
int start = word.getEntry().getContentAddr();
int len = word.getEntry().getCodeSize();
int end = start + len;
for (int addr = start; addr < end; addr++) {
console.flatWriteByte(addr, (byte) readChar(addr));
}
for (int addr = start; addr < end; ) {
RawInstruction instr = rawInstructionFactory.decodeInstruction(addr, console);
logfile.println("T>" + HexUtils.toHex4(instr.pc) + " " + instr);
addr += instr.getSize();
}
}
/**
* @param hostContext
* @throws AbortException
*/
public void buildExit(HostContext hostContext) throws AbortException {
if (isNativeDefinition()) {
compileExit(hostContext);
} else {
buildCall(require(";S"));
}
}
}