You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

932 lines
28 KiB

//////////////////////////////////////////////////////////////
// //
// Propeller Spin/PASM Compiler //
// (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. //
// Adapted from Chip Gracey's x86 asm code by Roy Eltham //
// See end of file for terms of use. //
// //
//////////////////////////////////////////////////////////////
//
// CompileDatBlocks.cpp
//
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "Utilities.h"
#include "PropellerCompilerInternal.h"
#include "SymbolEngine.h"
#include "Elementizer.h"
#include "ErrorStrings.h"
void CompileDatBlocks_EnterInfo(int datstart, int objstart)
{
g_pCompilerData->inf_start = datstart;
g_pCompilerData->inf_finish = g_pElementizer->GetSourcePtr();
g_pCompilerData->inf_data0 = objstart;
g_pCompilerData->inf_data1 = g_pCompilerData->obj_ptr;
g_pCompilerData->inf_data2 = 0;
g_pCompilerData->inf_data3 = 0;
g_pCompilerData->inf_data4 = 0;
g_pCompilerData->inf_type = info_dat;
EnterInfo();
}
void CompileDatBlocks_EnterSymbol(bool bResSymbol, int size)
{
int value_1 = g_pCompilerData->obj_ptr;
int value_2 = g_pCompilerData->cog_org;
g_pCompilerData->inf_data0 = value_1;
g_pCompilerData->inf_data1 = size;
g_pCompilerData->inf_data2 = value_2;
g_pCompilerData->inf_data3 = 0;
g_pCompilerData->inf_data4 = 0;
g_pCompilerData->inf_type = info_dat_symbol;
EnterInfo();
g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, bResSymbol ? type_dat_long_res : (size == 0 ? type_dat_byte : (size == 1 ? type_dat_word : type_dat_long)), value_1, value_2);
#ifdef RPE_DEBUG
printf("dat: %s %08X %08X (%d)\n", g_pCompilerData->symbolBackup, value_1, value_2, size);
#endif
}
bool CompileDatBlocks_EnterByte(unsigned char value)
{
if (EnterObj(value))
{
if (g_pCompilerData->orgx == 0)
{
g_pCompilerData->cog_org++;
}
return true;
}
return false;
}
bool CompileDatBlocks_Enter(int value, int count, int size)
{
int numBytesPer = 1 << size;
for (int i = 0; i < count; i++)
{
if(!CompileDatBlocks_EnterByte(value & 0x000000FF))
{
return false;
}
if (numBytesPer > 1)
{
if(!CompileDatBlocks_EnterByte((value >> 8) & 0x000000FF))
{
return false;
}
}
if (numBytesPer > 2)
{
if(!CompileDatBlocks_EnterByte((value >> 16) & 0x000000FF))
{
return false;
}
if(!CompileDatBlocks_EnterByte((value >> 24) & 0x000000FF))
{
return false;
}
}
}
return true;
}
bool CompileDatBlocks_Advance(bool bSymbol, bool bResSymbol, int size)
{
int testVal = (1 << size) - 1;
for (;;)
{
if ((g_pCompilerData->obj_ptr & testVal) == 0)
{
if (bSymbol)
{
CompileDatBlocks_EnterSymbol(bResSymbol, size);
}
break;
}
if (!CompileDatBlocks_EnterByte(0)) // obj_ptr gets incremented in here
{
return false;
}
}
return true;
}
bool CompileDatBlocks_Data(bool& bEof, int pass, bool bSymbol, bool& bResSymbol, int& size)
{
size = g_pElementizer->GetValue() & 0x000000FF;
int overrideSize = size;
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size))
{
return false;
}
if (!g_pElementizer->GetNext(bEof))
{
return false;
}
if (g_pElementizer->GetType() == type_end)
{
return true;
}
while (!bEof)
{
// do we have a size override?
if (g_pElementizer->GetType() == type_size)
{
// yes, get it
overrideSize = g_pElementizer->GetValue() & 0x000000FF;
if (overrideSize < size)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_sombl];
return false;
}
}
else
{
// no, backup
g_pElementizer->Backup();
}
// get the value
if (!GetTryValue(pass == 1 ? true : false, overrideSize == 2 ? false : true, true))
{
return false;
}
int value = GetResult();
// get the count
int count = 1;
if (g_pElementizer->CheckElement(type_leftb))
{
if (!GetTryValue(true, true, true))
{
return false;
}
count = GetResult();
if (!g_pElementizer->GetElement(type_rightb))
{
return false;
}
}
// enter the value count times into the obj
if (!CompileDatBlocks_Enter(value, count, overrideSize))
{
return false;
}
bool bComma = false;
if (!GetCommaOrEnd(bComma))
{
return false;
}
if (!bComma)
{
break;
}
if (!g_pElementizer->GetNext(bEof))
{
return false;
}
}
return true;
}
bool CompileDatBlocks_File(bool bSymbol, bool bResSymbol, int& size)
{
size = 0; // force size to byte
if (bSymbol)
{
CompileDatBlocks_EnterSymbol(bResSymbol, size);
}
int filenameStart = 0;
int filenameFinish = 0;
if (!GetFilename(filenameStart, filenameFinish))
{
return false;
}
// find the file in the dat_data array and copy it into obj
for (int i = 0; i < g_pCompilerData->dat_files; i++)
{
if (strcmp(&(g_pCompilerData->dat_filenames[256*i]), g_pCompilerData->filename) == 0)
{
// copy dat data into obj (RPE: this should be optimized)
for (int j = 0; j < g_pCompilerData->dat_lengths[i]; j++)
{
if (!CompileDatBlocks_EnterByte(g_pCompilerData->dat_data[g_pCompilerData->dat_offsets[i] + j]))
{
return false;
}
}
if (!g_pElementizer->GetElement(type_end))
{
return false;
}
return true;
}
}
// file data not found
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_idfnf];
return false;
}
bool CompileDatBlocks_AsmDirective(bool bSymbol, bool& bResSymbol, int& size)
{
size = 2; // force to long size
int directive = g_pElementizer->GetValue() & 0x000000FF;
switch (directive)
{
case dir_nop:
{
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size))
{
return false;
}
if (!g_pElementizer->GetElement(type_end))
{
return false;
}
if (!CompileDatBlocks_Enter(0, 1, 2)) // enter a 0 long
{
return false;
}
return true;
}
break;
case dir_fit:
{
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size))
{
return false;
}
int fit = 0x1F0;
if (!g_pElementizer->CheckElement(type_end))
{
if (!GetTryValue(true, true, true))
{
return false;
}
fit = GetResult();
if (!g_pElementizer->GetElement(type_end))
{
return false;
}
}
fit <<= 2;
if ((unsigned int)(g_pCompilerData->cog_org) > (unsigned int)fit)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_oefl];
return false;
}
return true;
}
break;
case dir_res:
{
if (g_pCompilerData->orgx != 0)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_rinaiom];
return false;
}
bResSymbol = true;
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size))
{
return false;
}
int resSize = 1;
if (!g_pElementizer->CheckElement(type_end))
{
if (!GetTryValue(true, true, true))
{
return false;
}
resSize = GetResult();
if (!g_pElementizer->GetElement(type_end))
{
return false;
}
}
resSize <<= 2;
g_pCompilerData->cog_org += resSize;
if (g_pCompilerData->cog_org > (0x1F0 * 4))
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_oexl];
return false;
}
return true;
}
break;
case dir_org:
{
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size))
{
return false;
}
int newOrg = 0;
if (!g_pElementizer->CheckElement(type_end))
{
if (!GetTryValue(true, true, true))
{
return false;
}
newOrg = GetResult();
if (!g_pElementizer->GetElement(type_end))
{
return false;
}
}
if (newOrg > 0x1F0)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_oexl];
return false;
}
g_pCompilerData->cog_org = newOrg << 2;
g_pCompilerData->orgx = 0;
return true;
}
break;
}
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size))
{
return false;
}
if (!g_pElementizer->GetElement(type_end))
{
return false;
}
g_pCompilerData->cog_org = 0;
g_pCompilerData->orgx = 1;
return true;
}
bool CompileDatBlocks_ValidateCallSymbol(bool bIsRet, char* pSymbol)
{
if (!g_pElementizer->FindSymbol(pSymbol))
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_eads];
return false;
}
if (g_pElementizer->GetType() == type_undefined)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[bIsRet ? error_urs : error_us];
return false;
}
if (g_pElementizer->GetType() < type_dat_byte || g_pElementizer->GetType() > type_dat_long_res)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_eads];
return false;
}
// the offset to the label symbol is in second symbol value
int value = g_pElementizer->GetValue2();
// make sure it's long aligned
if (value & 0x03)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[bIsRet ? error_rainl : error_ainl];
return false;
}
// make sure is in range
value >>= 2;
if (value >= 0x1F0)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[bIsRet ? error_raioor : error_aioor];
return false;
}
return true;
}
bool CompileDatBlocks_AsmInstruction(bool& bEof, int pass, bool bSymbol, bool bResSymbol, int& size, unsigned char condition)
{
size = 2; // force to long size
if (!CompileDatBlocks_Advance(bSymbol, bResSymbol, size))
{
return false;
}
int opcode = g_pElementizer->GetValue() & 0x000000FF;
// handle dual type entries and also AND and OR (which are the only type_binary that will get here)
if (g_pElementizer->IsDual() || g_pElementizer->GetType() == type_binary)
{
opcode = g_pElementizer->GetAsm() & 0x000000FF;
}
unsigned int instruction = opcode << 8;
if (opcode & 0x80) // sys instruction
{
instruction = 0x03 << 8;
}
instruction |= condition;
if (opcode & 0x40) // set WR?
{
instruction |= 0x20;
}
instruction <<= 18; // justify the instruction (s & d will go in lower 18 bits)
if (opcode & 0x80) // sys instruction
{
instruction |= 0x00400000; // set immediate
instruction |= (opcode & 0x07); // set s
// get d
if (!GetTryValue(pass == 1 ? true : false, true, true))
{
return false;
}
int d = GetResult();
if (d > 0x1FF)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_drcex];
return false;
}
instruction |= (d << 9); // set d
}
else if (opcode == 0x15) // call?
{
// make 'jmpret label_ret, #label'
instruction ^= 0x08C00000;
if (!g_pElementizer->GetElement(type_pound))
{
return false;
}
int length = 0;
if (!GetSymbol(&length))
{
return false;
}
if (length > 0)
{
if (length > symbol_limit - 4)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_csmnexc];
return false;
}
char* pSymbol = g_pElementizer->GetCurrentSymbol();
if (pass == 1)
{
if (!CompileDatBlocks_ValidateCallSymbol(false, pSymbol))
{
return false;
}
}
instruction |= ((g_pElementizer->GetValue2() & 0x7FF) >> 2); // set #label
pSymbol[length] = '_';
pSymbol[length+1] = 'R';
pSymbol[length+2] = 'E';
pSymbol[length+3] = 'T';
pSymbol[length+4] = 0;
if (pass == 1)
{
if (!CompileDatBlocks_ValidateCallSymbol(true, pSymbol))
{
return false;
}
}
instruction |= (((g_pElementizer->GetValue2() & 0x7FF) >> 2) << 9); // set label_ret
}
else
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_eads];
return false;
}
}
else if (opcode == 0x16) // ret?
{
instruction ^= 0x04400000; // make 'jmp #0'
}
else if (opcode == 0x17) // jmp?
{
// for jmp, we only get s, there is no d
// see if it's an immediate value for s
if (!g_pElementizer->GetNext(bEof))
{
return false;
}
if (g_pElementizer->GetType() == type_pound)
{
instruction |= 0x00400000;
}
else
{
g_pElementizer->Backup();
}
// get s
if (!GetTryValue(pass == 1 ? true : false, true, true))
{
return false;
}
int s = GetResult();
// make sure it's in range
if (s > 0x1FF)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_srccex];
return false;
}
// set s on instruction
instruction |= s;
}
else // regular instruction get both d and s
{
// get d
if (!GetTryValue(pass == 1 ? true : false, true, true))
{
return false;
}
int d = GetResult();
// make sure it's in range
if (d > 0x1FF)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_drcex];
return false;
}
// set d on instruction
instruction |= (d << 9);
if (!g_pElementizer->GetElement(type_comma))
{
return false;
}
// see if it's an immediate value for s
if (!g_pElementizer->GetNext(bEof))
{
return false;
}
if (g_pElementizer->GetType() == type_pound)
{
instruction |= 0x00400000;
}
else
{
g_pElementizer->Backup();
}
// get s
if (!GetTryValue(pass == 1 ? true : false, true, true))
{
return false;
}
int s = GetResult();
// make sure it's in range
if (s > 0x1FF)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_srccex];
return false;
}
// set s on instruction
instruction |= s;
}
// check for effects
bool bAfterComma = false;
while (!bEof)
{
if (!g_pElementizer->GetNext(bEof))
{
return false;
}
if (g_pElementizer->GetType() == type_asm_effect)
{
int effectValue = g_pElementizer->GetValue();
// don't allow wr/nr for r/w instructions
if ((effectValue & 0x09) && (instruction >> 26) <= 2)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_micuwn];
return false;
}
// apply effect to instruction
int temp = (effectValue & 0x38) << 20;
instruction |= temp;
instruction ^= temp;
instruction |= ((effectValue & 0x07) << 23);
bool bComma = false;
if (!GetCommaOrEnd(bComma))
{
return false;
}
if (!bComma)
{
// got end, done with effects
break;
}
// got a comma, expecting another effect
bAfterComma = true;
}
else if (bAfterComma)
{
// expected another effect after the comma
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_eaasme];
return false;
}
else if (g_pElementizer->GetType() != type_end)
{
// if it wasn't an effect the first time in then it should be an end
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_eaaeoeol];
return false;
}
else
{
// we get here if we got no effect and got the proper end
break;
}
}
// enter instruction as 1 long
if (!CompileDatBlocks_Enter(instruction, 1, 2))
{
return false;
}
return true;
}
bool CompileDatBlocks_CheckInstruction()
{
if (g_pElementizer->GetType() == type_asm_inst || g_pElementizer->IsDual())
{
return true;
}
if (g_pElementizer->GetType() == type_binary)
{
if (g_pElementizer->GetOpType() == op_log_and || g_pElementizer->GetOpType() == op_log_or)
{
return true;
}
}
return false;
}
bool CompileDatBlocks_AsmCondition(bool& bEof, int pass, bool bSymbol, bool bResSymbol, int& size)
{
unsigned char condition = (unsigned char)(g_pElementizer->GetValue() & 0x000000FF);
if (!g_pElementizer->GetNext(bEof))
{
return false;
}
if (CompileDatBlocks_CheckInstruction())
{
return CompileDatBlocks_AsmInstruction(bEof, pass, bSymbol, bResSymbol, size, condition);
}
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_eaasmi];
return false;
}
bool CompileDatBlocks()
{
int infoflag = 0;
int ptr = g_pCompilerData->obj_ptr;
int datstart = 0;
int objstart = 0;
for (int pass = 0; pass < 2; pass++)
{
g_pCompilerData->obj_ptr = ptr;
g_pCompilerData->asm_local = 0;
g_pCompilerData->cog_org = 0;
g_pCompilerData->orgx = 0;
int size = 0;
bool bEof = false;
g_pElementizer->Reset();
while(!bEof)
{
if(g_pElementizer->GetNextBlock(block_dat, bEof))
{
if (bEof)
{
break;
}
datstart = g_pCompilerData->source_start;
objstart = g_pCompilerData->obj_ptr;
while (!bEof)
{
if (!g_pElementizer->GetNext(bEof))
{
return false;
}
if (bEof)
{
break;
}
infoflag = 1;
if (g_pElementizer->GetType() == type_end)
{
continue;
}
g_pCompilerData->inf_start = g_pCompilerData->source_start;
// clear symbol flags
bool bLocal = false;
bool bSymbol = false;
bool bResSymbol = false;
if (!CheckLocal(bLocal)) // bLocal will be set if it is a local
{
return false;
}
g_pCompilerData->inf_finish = g_pCompilerData->source_finish;
if (g_pElementizer->GetType() == type_undefined) // undefined here means it's a symbol
{
if (!bLocal)
{
if (!IncrementAsmLocal())
{
return false;
}
}
bSymbol = true;
g_pElementizer->BackupSymbol();
if (!g_pElementizer->GetNext(bEof))
{
return false;
}
if (g_pElementizer->GetType() == type_end)
{
if (bSymbol)
{
CompileDatBlocks_EnterSymbol(bResSymbol, size);
}
continue;
}
}
else if (g_pElementizer->GetType() == type_dat_byte ||
g_pElementizer->GetType() == type_dat_word ||
g_pElementizer->GetType() == type_dat_long ||
g_pElementizer->GetType() == type_dat_long_res)
{
if (!bLocal)
{
if (!IncrementAsmLocal())
{
return false;
}
}
if (pass == 0)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_siad];
return false;
}
if (!g_pElementizer->GetNext(bEof))
{
return false;
}
if (g_pElementizer->GetType() == type_end)
{
continue;
}
}
if (g_pElementizer->GetType() == type_size)
{
if (!CompileDatBlocks_Data(bEof, pass, bSymbol, bResSymbol, size))
{
return false;
}
continue;
}
else if (g_pElementizer->GetType() == type_file)
{
if (!CompileDatBlocks_File(bSymbol, bResSymbol, size))
{
return false;
}
continue;
}
else if (g_pElementizer->GetType() == type_asm_dir)
{
if (!CompileDatBlocks_AsmDirective(bSymbol, bResSymbol, size))
{
return false;
}
continue;
}
else if (g_pElementizer->GetType() == type_asm_cond)
{
if (!CompileDatBlocks_AsmCondition(bEof, pass, bSymbol, bResSymbol, size))
{
return false;
}
continue;
}
else if (CompileDatBlocks_CheckInstruction())
{
if (!CompileDatBlocks_AsmInstruction(bEof, pass, bSymbol, bResSymbol, size, if_always))
{
return false;
}
continue;
}
if (g_pElementizer->GetType() == type_block)
{
g_pElementizer->Backup();
if (pass == 0)
{
CompileDatBlocks_EnterInfo(datstart, objstart);
}
break;
}
else
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_eaunbwlo];
return false;
}
}
}
else
{
return false;
}
}
if (infoflag != 0 && pass == 0)
{
CompileDatBlocks_EnterInfo(datstart, objstart);
}
}
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////
// TERMS OF USE: MIT License //
///////////////////////////////////////////////////////////////////////////////////////////
// Permission is hereby granted, free of charge, to any person obtaining a copy of this //
// software and associated documentation files (the "Software"), to deal in the Software //
// without restriction, including without limitation the rights to use, copy, modify, //
// merge, publish, distribute, sublicense, and/or sell copies of the Software, and to //
// permit persons to whom the Software is furnished to do so, subject to the following //
// conditions: //
// //
// The above copyright notice and this permission notice shall be included in all copies //
// or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, //
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A //
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT //
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION //
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE //
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //
///////////////////////////////////////////////////////////////////////////////////////////