DSPAssembler: Rework errors and warnings
Among other things, this trims trailing newline characters. Before (on windows) the \r would corrupt the output and make them very hard to understand (as the error message would be drawn over the code line, but part of the code line would peek out from behind it).
This commit is contained in:
parent
db3d457e5f
commit
bd3173e344
|
@ -26,6 +26,42 @@
|
||||||
#include "Core/DSP/DSPDisassembler.h"
|
#include "Core/DSP/DSPDisassembler.h"
|
||||||
#include "Core/DSP/DSPTables.h"
|
#include "Core/DSP/DSPTables.h"
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct fmt::formatter<DSP::DSPAssembler::LocationContext>
|
||||||
|
{
|
||||||
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const DSP::DSPAssembler::LocationContext& loc, FormatContext& ctx) const
|
||||||
|
{
|
||||||
|
// Trim trailing newlines
|
||||||
|
// TODO: Ideally, we shouldn't be getting any newlines at all here, but
|
||||||
|
// DSPTool uses File::ReadFileToString, which opens the file in binary mode,
|
||||||
|
// so we get \r endings on Windows. This leads to bad results when printing the string.
|
||||||
|
std::string trimmed_line = loc.line_text;
|
||||||
|
// while (trimmed_line.ends_with('\r') || trimmed_line.ends_with('\n'))
|
||||||
|
while (!trimmed_line.empty() && (trimmed_line.back() == '\r' || trimmed_line.back() == '\n'))
|
||||||
|
trimmed_line.pop_back();
|
||||||
|
|
||||||
|
auto out = fmt::format_to(ctx.out(), "At line {}", loc.line_num);
|
||||||
|
|
||||||
|
if (loc.included_file_path.has_value())
|
||||||
|
out = fmt::format_to(out, " of included file {}", loc.included_file_path.value());
|
||||||
|
|
||||||
|
if (loc.opcode_type.has_value())
|
||||||
|
{
|
||||||
|
if (loc.opcode_type.value() == DSP::DSPAssembler::OpcodeType::Primary)
|
||||||
|
out = fmt::format_to(out, ", main opcode");
|
||||||
|
else if (loc.opcode_type.value() == DSP::DSPAssembler::OpcodeType::Extension)
|
||||||
|
out = fmt::format_to(out, ", extension opcode");
|
||||||
|
|
||||||
|
if (loc.opcode_param_number.has_value())
|
||||||
|
out = fmt::format_to(out, " parameter {}", loc.opcode_param_number.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt::format_to(out, ":\n{}", trimmed_line);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
namespace DSP
|
namespace DSP
|
||||||
{
|
{
|
||||||
static const char* err_string[] = {"",
|
static const char* err_string[] = {"",
|
||||||
|
@ -88,31 +124,39 @@ bool DSPAssembler::Assemble(const std::string& text, std::vector<u16>& code,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPAssembler::ShowError(AssemblerError err_code, const char* extra_info)
|
void DSPAssembler::ShowError(AssemblerError err_code)
|
||||||
{
|
{
|
||||||
if (!m_settings.force)
|
if (!m_settings.force)
|
||||||
m_failed = true;
|
m_failed = true;
|
||||||
|
|
||||||
std::string error = fmt::format("{} : {} ", m_code_line, m_cur_line);
|
m_last_error_str =
|
||||||
if (!extra_info)
|
fmt::format("{}\nERROR: {}\n\n", m_location, err_string[static_cast<size_t>(err_code)]);
|
||||||
extra_info = "-";
|
fmt::print(stderr, "{}", m_last_error_str);
|
||||||
|
|
||||||
const char* const error_string = err_string[static_cast<size_t>(err_code)];
|
|
||||||
|
|
||||||
if (m_current_param == 0)
|
|
||||||
{
|
|
||||||
error += fmt::format("ERROR: {} Line: {} : {}\n", error_string, m_code_line, extra_info);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
error += fmt::format("ERROR: {} Line: {} Param: {} : {}\n", error_string, m_code_line,
|
|
||||||
m_current_param, extra_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_last_error_str = std::move(error);
|
|
||||||
m_last_error = err_code;
|
m_last_error = err_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void DSPAssembler::ShowError(AssemblerError err_code, fmt::format_string<Args...> format,
|
||||||
|
Args&&... args)
|
||||||
|
{
|
||||||
|
if (!m_settings.force)
|
||||||
|
m_failed = true;
|
||||||
|
|
||||||
|
const auto msg = fmt::format(format, std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
m_last_error_str = fmt::format("{}\nERROR: {}: {}\n\n", m_location,
|
||||||
|
err_string[static_cast<size_t>(err_code)], msg);
|
||||||
|
fmt::print(stderr, "{}", m_last_error_str);
|
||||||
|
m_last_error = err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void DSPAssembler::ShowWarning(fmt::format_string<Args...> format, Args&&... args)
|
||||||
|
{
|
||||||
|
const auto msg = fmt::format(format, std::forward<Args>(args)...);
|
||||||
|
fmt::print(stderr, "{}\nWARNING: {}\n\n", m_location, msg);
|
||||||
|
}
|
||||||
|
|
||||||
static char* skip_spaces(char* ptr)
|
static char* skip_spaces(char* ptr)
|
||||||
{
|
{
|
||||||
while (*ptr == ' ')
|
while (*ptr == ' ')
|
||||||
|
@ -147,7 +191,7 @@ s32 DSPAssembler::ParseValue(const char* str)
|
||||||
if (ptr[i] >= '0' && ptr[i] <= '9')
|
if (ptr[i] >= '0' && ptr[i] <= '9')
|
||||||
val += ptr[i] - '0';
|
val += ptr[i] - '0';
|
||||||
else
|
else
|
||||||
ShowError(AssemblerError::IncorrectDecimal, str);
|
ShowError(AssemblerError::IncorrectDecimal, "{}", str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -165,7 +209,7 @@ s32 DSPAssembler::ParseValue(const char* str)
|
||||||
else if (ptr[i] >= '0' && ptr[i] <= '9')
|
else if (ptr[i] >= '0' && ptr[i] <= '9')
|
||||||
val += (ptr[i] - '0');
|
val += (ptr[i] - '0');
|
||||||
else
|
else
|
||||||
ShowError(AssemblerError::IncorrectHex, str);
|
ShowError(AssemblerError::IncorrectHex, "{}", str);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '\'': // binary
|
case '\'': // binary
|
||||||
|
@ -175,7 +219,7 @@ s32 DSPAssembler::ParseValue(const char* str)
|
||||||
if (ptr[i] >= '0' && ptr[i] <= '1')
|
if (ptr[i] >= '0' && ptr[i] <= '1')
|
||||||
val += ptr[i] - '0';
|
val += ptr[i] - '0';
|
||||||
else
|
else
|
||||||
ShowError(AssemblerError::IncorrectBinary, str);
|
ShowError(AssemblerError::IncorrectBinary, "{}", str);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -196,7 +240,7 @@ s32 DSPAssembler::ParseValue(const char* str)
|
||||||
if (ptr[i] >= '0' && ptr[i] <= '9')
|
if (ptr[i] >= '0' && ptr[i] <= '9')
|
||||||
val += ptr[i] - '0';
|
val += ptr[i] - '0';
|
||||||
else
|
else
|
||||||
ShowError(AssemblerError::IncorrectDecimal, str);
|
ShowError(AssemblerError::IncorrectDecimal, "{}", str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // Everything else is a label.
|
else // Everything else is a label.
|
||||||
|
@ -206,7 +250,7 @@ s32 DSPAssembler::ParseValue(const char* str)
|
||||||
return *value;
|
return *value;
|
||||||
|
|
||||||
if (m_cur_pass == 2)
|
if (m_cur_pass == 2)
|
||||||
ShowError(AssemblerError::UnknownLabel, str);
|
ShowError(AssemblerError::UnknownLabel, "{}", str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (negative)
|
if (negative)
|
||||||
|
@ -332,10 +376,10 @@ u32 DSPAssembler::ParseExpression(const char* ptr)
|
||||||
val = ParseExpression(d_buffer) - ParseExpression(pbuf + 1);
|
val = ParseExpression(d_buffer) - ParseExpression(pbuf + 1);
|
||||||
if (val < 0)
|
if (val < 0)
|
||||||
{
|
{
|
||||||
|
ShowWarning("Number Underflow: {}", val);
|
||||||
val = 0x10000 +
|
val = 0x10000 +
|
||||||
(val &
|
(val &
|
||||||
0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf
|
0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf
|
||||||
fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", m_code_line);
|
|
||||||
}
|
}
|
||||||
sprintf(d_buffer, "%d", val);
|
sprintf(d_buffer, "%d", val);
|
||||||
}
|
}
|
||||||
|
@ -472,7 +516,7 @@ bool DSPAssembler::VerifyParams(const DSPOPCTemplate* opc, param_t* par, size_t
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < count; i++)
|
for (size_t i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
const size_t current_param = i + 1; // just for display.
|
m_location.opcode_param_number = i + 1;
|
||||||
if (opc->params[i].type != par[i].type || (par[i].type & P_REG))
|
if (opc->params[i].type != par[i].type || (par[i].type & P_REG))
|
||||||
{
|
{
|
||||||
if (par[i].type == P_VAL &&
|
if (par[i].type == P_VAL &&
|
||||||
|
@ -496,10 +540,6 @@ bool DSPAssembler::VerifyParams(const DSPOPCTemplate* opc, param_t* par, size_t
|
||||||
if ((int)par[i].val < value ||
|
if ((int)par[i].val < value ||
|
||||||
(int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask))
|
(int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask))
|
||||||
{
|
{
|
||||||
if (type == OpcodeType::Extension)
|
|
||||||
fprintf(stderr, "(ext) ");
|
|
||||||
|
|
||||||
fprintf(stderr, "%s (param %zu)", m_cur_line.c_str(), current_param);
|
|
||||||
ShowError(AssemblerError::InvalidRegister);
|
ShowError(AssemblerError::InvalidRegister);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -507,34 +547,19 @@ bool DSPAssembler::VerifyParams(const DSPOPCTemplate* opc, param_t* par, size_t
|
||||||
case P_PRG:
|
case P_PRG:
|
||||||
if ((int)par[i].val < DSP_REG_AR0 || (int)par[i].val > DSP_REG_AR3)
|
if ((int)par[i].val < DSP_REG_AR0 || (int)par[i].val > DSP_REG_AR3)
|
||||||
{
|
{
|
||||||
if (type == OpcodeType::Extension)
|
|
||||||
fprintf(stderr, "(ext) ");
|
|
||||||
|
|
||||||
fprintf(stderr, "%s (param %zu)", m_cur_line.c_str(), current_param);
|
|
||||||
ShowError(AssemblerError::InvalidRegister);
|
ShowError(AssemblerError::InvalidRegister);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case P_ACC:
|
case P_ACC:
|
||||||
if ((int)par[i].val < DSP_REG_ACC0_FULL || (int)par[i].val > DSP_REG_ACC1_FULL)
|
if ((int)par[i].val < DSP_REG_ACC0_FULL || (int)par[i].val > DSP_REG_ACC1_FULL)
|
||||||
{
|
{
|
||||||
if (type == OpcodeType::Extension)
|
|
||||||
fprintf(stderr, "(ext) ");
|
|
||||||
|
|
||||||
if (par[i].val >= DSP_REG_ACM0 && par[i].val <= DSP_REG_ACM1)
|
if (par[i].val >= DSP_REG_ACM0 && par[i].val <= DSP_REG_ACM1)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%i : %s ", m_code_line, m_cur_line.c_str());
|
ShowWarning("$ACM{0} register used instead of $ACC{0} register", (par[i].val & 1));
|
||||||
fprintf(stderr,
|
|
||||||
"WARNING: $ACM%d register used instead of $ACC%d register Line: %d "
|
|
||||||
"Param: %zu Ext: %d\n",
|
|
||||||
(par[i].val & 1), (par[i].val & 1), m_code_line, current_param,
|
|
||||||
static_cast<int>(type));
|
|
||||||
}
|
}
|
||||||
else if (par[i].val >= DSP_REG_ACL0 && par[i].val <= DSP_REG_ACL1)
|
else if (par[i].val >= DSP_REG_ACL0 && par[i].val <= DSP_REG_ACL1)
|
||||||
{
|
{
|
||||||
fprintf(
|
ShowWarning("$ACL{0} register used instead of $ACC{0} register", (par[i].val & 1));
|
||||||
stderr,
|
|
||||||
"WARNING: $ACL%d register used instead of $ACC%d register Line: %d Param: %zu\n",
|
|
||||||
(par[i].val & 1), (par[i].val & 1), m_code_line, current_param);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -545,22 +570,13 @@ bool DSPAssembler::VerifyParams(const DSPOPCTemplate* opc, param_t* par, size_t
|
||||||
case P_ACCM:
|
case P_ACCM:
|
||||||
if ((int)par[i].val < DSP_REG_ACM0 || (int)par[i].val > DSP_REG_ACM1)
|
if ((int)par[i].val < DSP_REG_ACM0 || (int)par[i].val > DSP_REG_ACM1)
|
||||||
{
|
{
|
||||||
if (type == OpcodeType::Extension)
|
|
||||||
fprintf(stderr, "(ext) ");
|
|
||||||
|
|
||||||
if (par[i].val >= DSP_REG_ACL0 && par[i].val <= DSP_REG_ACL1)
|
if (par[i].val >= DSP_REG_ACL0 && par[i].val <= DSP_REG_ACL1)
|
||||||
{
|
{
|
||||||
fprintf(
|
ShowWarning("$ACL{0} register used instead of $ACCM{0} register", (par[i].val & 1));
|
||||||
stderr,
|
|
||||||
"WARNING: $ACL%d register used instead of $ACM%d register Line: %d Param: %zu\n",
|
|
||||||
(par[i].val & 1), (par[i].val & 1), m_code_line, current_param);
|
|
||||||
}
|
}
|
||||||
else if (par[i].val >= DSP_REG_ACC0_FULL && par[i].val <= DSP_REG_ACC1_FULL)
|
else if (par[i].val >= DSP_REG_ACC0_FULL && par[i].val <= DSP_REG_ACC1_FULL)
|
||||||
{
|
{
|
||||||
fprintf(
|
ShowWarning("$ACC{0} register used instead of $ACM{0} register", (par[i].val & 1));
|
||||||
stderr,
|
|
||||||
"WARNING: $ACC%d register used instead of $ACM%d register Line: %d Param: %zu\n",
|
|
||||||
(par[i].val & 1), (par[i].val & 1), m_code_line, current_param);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -572,24 +588,13 @@ bool DSPAssembler::VerifyParams(const DSPOPCTemplate* opc, param_t* par, size_t
|
||||||
case P_ACCL:
|
case P_ACCL:
|
||||||
if ((int)par[i].val < DSP_REG_ACL0 || (int)par[i].val > DSP_REG_ACL1)
|
if ((int)par[i].val < DSP_REG_ACL0 || (int)par[i].val > DSP_REG_ACL1)
|
||||||
{
|
{
|
||||||
if (type == OpcodeType::Extension)
|
|
||||||
fprintf(stderr, "(ext) ");
|
|
||||||
|
|
||||||
if (par[i].val >= DSP_REG_ACM0 && par[i].val <= DSP_REG_ACM1)
|
if (par[i].val >= DSP_REG_ACM0 && par[i].val <= DSP_REG_ACM1)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s ", m_cur_line.c_str());
|
ShowWarning("$ACM{0} register used instead of $ACL{0} register", (par[i].val & 1));
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %zu\n",
|
|
||||||
(par[i].val & 1), (par[i].val & 1), m_code_line, current_param);
|
|
||||||
}
|
}
|
||||||
else if (par[i].val >= DSP_REG_ACC0_FULL && par[i].val <= DSP_REG_ACC1_FULL)
|
else if (par[i].val >= DSP_REG_ACC0_FULL && par[i].val <= DSP_REG_ACC1_FULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s ", m_cur_line.c_str());
|
ShowWarning("$ACC{0} register used instead of $ACL{0} register", (par[i].val & 1));
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"WARNING: $ACC%d register used instead of $ACL%d register Line: %d Param: %zu\n",
|
|
||||||
(par[i].val & 1), (par[i].val & 1), m_code_line, current_param);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -604,23 +609,15 @@ bool DSPAssembler::VerifyParams(const DSPOPCTemplate* opc, param_t* par, size_t
|
||||||
switch (par[i].type & (P_REG | 7))
|
switch (par[i].type & (P_REG | 7))
|
||||||
{
|
{
|
||||||
case P_REG:
|
case P_REG:
|
||||||
if (type == OpcodeType::Extension)
|
|
||||||
fprintf(stderr, "(ext) ");
|
|
||||||
ShowError(AssemblerError::ExpectedParamReg);
|
ShowError(AssemblerError::ExpectedParamReg);
|
||||||
break;
|
break;
|
||||||
case P_MEM:
|
case P_MEM:
|
||||||
if (type == OpcodeType::Extension)
|
|
||||||
fprintf(stderr, "(ext) ");
|
|
||||||
ShowError(AssemblerError::ExpectedParamMem);
|
ShowError(AssemblerError::ExpectedParamMem);
|
||||||
break;
|
break;
|
||||||
case P_VAL:
|
case P_VAL:
|
||||||
if (type == OpcodeType::Extension)
|
|
||||||
fprintf(stderr, "(ext) ");
|
|
||||||
ShowError(AssemblerError::ExpectedParamVal);
|
ShowError(AssemblerError::ExpectedParamVal);
|
||||||
break;
|
break;
|
||||||
case P_IMM:
|
case P_IMM:
|
||||||
if (type == OpcodeType::Extension)
|
|
||||||
fprintf(stderr, "(ext) ");
|
|
||||||
ShowError(AssemblerError::ExpectedParamImm);
|
ShowError(AssemblerError::ExpectedParamImm);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -634,40 +631,49 @@ bool DSPAssembler::VerifyParams(const DSPOPCTemplate* opc, param_t* par, size_t
|
||||||
unsigned int valueu = 0xffff & ~(value >> 1);
|
unsigned int valueu = 0xffff & ~(value >> 1);
|
||||||
if ((int)par[i].val < 0)
|
if ((int)par[i].val < 0)
|
||||||
{
|
{
|
||||||
if (value == 7) // value 7 por sbclr/sbset
|
if (value == 7) // value 7 for sbclr/sbset
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Value must be from 0x0 to 0x%x\n", value);
|
ShowError(AssemblerError::NumberOutOfRange, "Value must be from 0x0 to {:#x}, was {:#x}",
|
||||||
ShowError(AssemblerError::NumberOutOfRange);
|
value, (int)par[i].val);
|
||||||
}
|
}
|
||||||
else if (opc->params[i].type == P_MEM)
|
else if (opc->params[i].type == P_MEM)
|
||||||
{
|
{
|
||||||
if (value < 256)
|
if (value < 256)
|
||||||
fprintf(stderr, "Address value must be from 0x%x to 0x%x\n", valueu, (value >> 1));
|
{
|
||||||
|
ShowError(AssemblerError::NumberOutOfRange,
|
||||||
|
"Address value must be from {:#x} to {:#x}, was {:#x}", valueu, (value >> 1),
|
||||||
|
(int)par[i].val);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value);
|
{
|
||||||
|
ShowError(AssemblerError::NumberOutOfRange,
|
||||||
ShowError(AssemblerError::NumberOutOfRange);
|
"Address value must be from 0x0 to {:#x}, was {:#x}", value, (int)par[i].val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ((int)par[i].val < -((value >> 1) + 1))
|
else if ((int)par[i].val < -((value >> 1) + 1))
|
||||||
{
|
{
|
||||||
if (value < 128)
|
if (value < 128)
|
||||||
fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n", (value >> 1) + 1,
|
{
|
||||||
value >> 1, par[i].val);
|
ShowError(AssemblerError::NumberOutOfRange,
|
||||||
|
"Value must be from {:#x} to {:#x}, was {:#x}", -((value >> 1) + 1),
|
||||||
|
value >> 1, (int)par[i].val);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
fprintf(stderr, "Value must be from -0x%x to 0x%x or 0x0 to 0x%x, is %i\n",
|
{
|
||||||
(value >> 1) + 1, value >> 1, value, par[i].val);
|
ShowError(AssemblerError::NumberOutOfRange,
|
||||||
|
"Value must be from {:#x} to {:#x} or 0x0 to {:#x}, was {:#x}",
|
||||||
ShowError(AssemblerError::NumberOutOfRange);
|
-((value >> 1) + 1), value >> 1, value, (int)par[i].val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (value == 7) // value 7 por sbclr/sbset
|
if (value == 7) // value 7 for sbclr/sbset
|
||||||
{
|
{
|
||||||
if (par[i].val > (unsigned)value)
|
if (par[i].val > (unsigned)value)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Value must be from 0x%x to 0x%x, is %i\n", valueu, value, par[i].val);
|
ShowError(AssemblerError::NumberOutOfRange,
|
||||||
ShowError(AssemblerError::NumberOutOfRange);
|
"Value must be from {:#x} to {:#x}, was {:#x}\n", valueu, value, par[i].val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (opc->params[i].type == P_MEM)
|
else if (opc->params[i].type == P_MEM)
|
||||||
|
@ -678,11 +684,17 @@ bool DSPAssembler::VerifyParams(const DSPOPCTemplate* opc, param_t* par, size_t
|
||||||
(par[i].val < valueu || par[i].val > (unsigned)0xffff))
|
(par[i].val < valueu || par[i].val > (unsigned)0xffff))
|
||||||
{
|
{
|
||||||
if (value < 256)
|
if (value < 256)
|
||||||
fprintf(stderr, "Address value must be from 0x%x to 0x%x, is %04x\n", valueu, value,
|
{
|
||||||
par[i].val);
|
ShowError(AssemblerError::NumberOutOfRange,
|
||||||
|
"Address value must be from {:#x} to {:#x}, was {:04x}\n", valueu, value,
|
||||||
|
par[i].val);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
fprintf(stderr, "Address value must be minor of 0x%x\n", value + 1);
|
{
|
||||||
ShowError(AssemblerError::NumberOutOfRange);
|
ShowError(AssemblerError::NumberOutOfRange,
|
||||||
|
"Address value must be less than {:#x}, was {:04x}\n", value + 1,
|
||||||
|
par[i].val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -692,18 +704,23 @@ bool DSPAssembler::VerifyParams(const DSPOPCTemplate* opc, param_t* par, size_t
|
||||||
if (par[i].val > (unsigned)value)
|
if (par[i].val > (unsigned)value)
|
||||||
{
|
{
|
||||||
if (value < 64)
|
if (value < 64)
|
||||||
fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n", (value + 1), value,
|
{
|
||||||
par[i].val);
|
ShowError(AssemblerError::NumberOutOfRange,
|
||||||
|
"Value must be from {:#x} to {:#x}, was {:#x}\n", -(value + 1), value,
|
||||||
|
par[i].val);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
fprintf(stderr, "Value must be minor of 0x%x, is %i\n", value + 1, par[i].val);
|
{
|
||||||
ShowError(AssemblerError::NumberOutOfRange);
|
ShowError(AssemblerError::NumberOutOfRange,
|
||||||
|
"Value must be less than {:#x}, was {:#x}\n", value + 1, par[i].val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_current_param = 0;
|
m_location.opcode_param_number = std::nullopt;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -755,7 +772,7 @@ bool DSPAssembler::AssemblePass(const std::string& text, int pass)
|
||||||
|
|
||||||
std::istringstream fsrc(text);
|
std::istringstream fsrc(text);
|
||||||
|
|
||||||
m_code_line = 0;
|
m_location.line_num = 0;
|
||||||
m_cur_pass = pass;
|
m_cur_pass = pass;
|
||||||
|
|
||||||
#define LINEBUF_SIZE 1024
|
#define LINEBUF_SIZE 1024
|
||||||
|
@ -767,8 +784,8 @@ bool DSPAssembler::AssemblePass(const std::string& text, int pass)
|
||||||
if (fsrc.fail())
|
if (fsrc.fail())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
m_cur_line = line;
|
m_location.line_text = line;
|
||||||
m_code_line++;
|
m_location.line_num++;
|
||||||
|
|
||||||
param_t params[10] = {{0, P_NONE, nullptr}};
|
param_t params[10] = {{0, P_NONE, nullptr}};
|
||||||
param_t params_ext[10] = {{0, P_NONE, nullptr}};
|
param_t params_ext[10] = {{0, P_NONE, nullptr}};
|
||||||
|
@ -905,23 +922,22 @@ bool DSPAssembler::AssemblePass(const std::string& text, int pass)
|
||||||
{
|
{
|
||||||
if (params[0].type == P_STR)
|
if (params[0].type == P_STR)
|
||||||
{
|
{
|
||||||
std::string include_file_path;
|
const auto old_location = m_location;
|
||||||
const u32 this_code_line = m_code_line;
|
|
||||||
|
|
||||||
if (m_include_dir.empty())
|
if (m_include_dir.empty())
|
||||||
{
|
{
|
||||||
include_file_path = params[0].str;
|
m_location.included_file_path = params[0].str;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
include_file_path = m_include_dir + '/' + params[0].str;
|
m_location.included_file_path = m_include_dir + '/' + params[0].str;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string included_text;
|
std::string included_text;
|
||||||
File::ReadFileToString(include_file_path, included_text);
|
File::ReadFileToString(m_location.included_file_path.value(), included_text);
|
||||||
AssemblePass(included_text, pass);
|
AssemblePass(included_text, pass);
|
||||||
|
|
||||||
m_code_line = this_code_line;
|
m_location = old_location;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -959,9 +975,8 @@ bool DSPAssembler::AssemblePass(const std::string& text, int pass)
|
||||||
{
|
{
|
||||||
if (m_cur_addr > params[0].val)
|
if (m_cur_addr > params[0].val)
|
||||||
{
|
{
|
||||||
const std::string msg = fmt::format("WARNPC at 0x{:04x}, expected 0x{:04x} or less",
|
ShowError(AssemblerError::PCOutOfRange, "WARNPC at 0x{:04x}, expected 0x{:04x} or less",
|
||||||
m_cur_addr, params[0].val);
|
m_cur_addr, params[0].val);
|
||||||
ShowError(AssemblerError::PCOutOfRange, msg.c_str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -987,6 +1002,7 @@ bool DSPAssembler::AssemblePass(const std::string& text, int pass)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_location.opcode_type = OpcodeType::Primary;
|
||||||
const DSPOPCTemplate* opc = FindOpcode(opcode, params_count, OpcodeType::Primary);
|
const DSPOPCTemplate* opc = FindOpcode(opcode, params_count, OpcodeType::Primary);
|
||||||
if (!opc)
|
if (!opc)
|
||||||
opc = &cw;
|
opc = &cw;
|
||||||
|
@ -997,6 +1013,7 @@ bool DSPAssembler::AssemblePass(const std::string& text, int pass)
|
||||||
|
|
||||||
const DSPOPCTemplate* opc_ext = nullptr;
|
const DSPOPCTemplate* opc_ext = nullptr;
|
||||||
// Check for opcode extensions.
|
// Check for opcode extensions.
|
||||||
|
m_location.opcode_type = OpcodeType::Extension;
|
||||||
if (opc->extended)
|
if (opc->extended)
|
||||||
{
|
{
|
||||||
if (opcode_ext)
|
if (opcode_ext)
|
||||||
|
@ -1016,6 +1033,7 @@ bool DSPAssembler::AssemblePass(const std::string& text, int pass)
|
||||||
if (params_count_ext)
|
if (params_count_ext)
|
||||||
ShowError(AssemblerError::ExtensionParamsOnNonExtendableOpcode);
|
ShowError(AssemblerError::ExtensionParamsOnNonExtendableOpcode);
|
||||||
}
|
}
|
||||||
|
m_location.opcode_type = std::nullopt;
|
||||||
|
|
||||||
if (pass == 2)
|
if (pass == 2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,9 +6,13 @@
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
#include "Core/DSP/DSPDisassembler.h"
|
#include "Core/DSP/DSPDisassembler.h"
|
||||||
|
@ -85,6 +89,17 @@ private:
|
||||||
Extension
|
Extension
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LocationContext
|
||||||
|
{
|
||||||
|
u32 line_num = 0;
|
||||||
|
std::string line_text;
|
||||||
|
std::optional<OpcodeType> opcode_type;
|
||||||
|
std::optional<size_t> opcode_param_number;
|
||||||
|
std::optional<std::string> included_file_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
friend struct ::fmt::formatter<DSP::DSPAssembler::LocationContext>;
|
||||||
|
|
||||||
// Utility functions
|
// Utility functions
|
||||||
s32 ParseValue(const char* str);
|
s32 ParseValue(const char* str);
|
||||||
u32 ParseExpression(const char* ptr);
|
u32 ParseExpression(const char* ptr);
|
||||||
|
@ -94,7 +109,11 @@ private:
|
||||||
void InitPass(int pass);
|
void InitPass(int pass);
|
||||||
bool AssemblePass(const std::string& text, int pass);
|
bool AssemblePass(const std::string& text, int pass);
|
||||||
|
|
||||||
void ShowError(AssemblerError err_code, const char* extra_info = nullptr);
|
void ShowError(AssemblerError err_code);
|
||||||
|
template <typename... Args>
|
||||||
|
void ShowError(AssemblerError err_code, fmt::format_string<Args...> format, Args&&... args);
|
||||||
|
template <typename... Args>
|
||||||
|
void ShowWarning(fmt::format_string<Args...> format, Args&&... args);
|
||||||
|
|
||||||
char* FindBrackets(char* src, char* dst);
|
char* FindBrackets(char* src, char* dst);
|
||||||
const DSPOPCTemplate* FindOpcode(std::string name, size_t par_count, OpcodeType type);
|
const DSPOPCTemplate* FindOpcode(std::string name, size_t par_count, OpcodeType type);
|
||||||
|
@ -104,7 +123,6 @@ private:
|
||||||
std::vector<u16> m_output_buffer;
|
std::vector<u16> m_output_buffer;
|
||||||
|
|
||||||
std::string m_include_dir;
|
std::string m_include_dir;
|
||||||
std::string m_cur_line;
|
|
||||||
|
|
||||||
u32 m_cur_addr = 0;
|
u32 m_cur_addr = 0;
|
||||||
int m_total_size = 0;
|
int m_total_size = 0;
|
||||||
|
@ -112,7 +130,6 @@ private:
|
||||||
|
|
||||||
LabelMap m_labels;
|
LabelMap m_labels;
|
||||||
|
|
||||||
u32 m_code_line = 0;
|
|
||||||
bool m_failed = false;
|
bool m_failed = false;
|
||||||
std::string m_last_error_str;
|
std::string m_last_error_str;
|
||||||
AssemblerError m_last_error = AssemblerError::OK;
|
AssemblerError m_last_error = AssemblerError::OK;
|
||||||
|
@ -122,7 +139,8 @@ private:
|
||||||
|
|
||||||
segment_t m_cur_segment = SEGMENT_CODE;
|
segment_t m_cur_segment = SEGMENT_CODE;
|
||||||
u32 m_segment_addr[SEGMENT_MAX] = {};
|
u32 m_segment_addr[SEGMENT_MAX] = {};
|
||||||
int m_current_param = 0;
|
|
||||||
const AssemblerSettings m_settings;
|
const AssemblerSettings m_settings;
|
||||||
|
|
||||||
|
LocationContext m_location;
|
||||||
};
|
};
|
||||||
} // namespace DSP
|
} // namespace DSP
|
||||||
|
|
|
@ -35,13 +35,7 @@ bool Assemble(const std::string& text, std::vector<u16>& code, bool force)
|
||||||
|
|
||||||
// TODO: fix the terrible api of the assembler.
|
// TODO: fix the terrible api of the assembler.
|
||||||
DSPAssembler assembler(settings);
|
DSPAssembler assembler(settings);
|
||||||
if (!assembler.Assemble(text, code))
|
return assembler.Assemble(text, code);
|
||||||
{
|
|
||||||
std::cerr << assembler.GetErrorString() << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Disassemble(const std::vector<u16>& code, bool line_numbers, std::string& text)
|
bool Disassemble(const std::vector<u16>& code, bool line_numbers, std::string& text)
|
||||||
|
|
Loading…
Reference in New Issue