2019-08-17 13:51:31 -04:00
|
|
|
#include <cstring>
|
2008-01-15 20:27:44 +00:00
|
|
|
#include "Iop_Stdio.h"
|
2014-08-02 21:23:25 -04:00
|
|
|
#include "Iop_Ioman.h"
|
2008-01-15 20:27:44 +00:00
|
|
|
#include "lexical_cast_ex.h"
|
2015-10-27 00:23:27 -04:00
|
|
|
#include "string_format.h"
|
2025-03-11 12:48:26 -04:00
|
|
|
#include "Log.h"
|
2008-12-02 03:10:37 +00:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
#define LOG_NAME "iop_stdio"
|
2008-12-02 03:10:37 +00:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
#define FUNCTION_PRINTF "printf"
|
2018-05-27 15:11:48 -04:00
|
|
|
#define FUNCTION_PUTS "puts"
|
2008-01-15 20:27:44 +00:00
|
|
|
|
|
|
|
using namespace Iop;
|
|
|
|
|
2014-08-02 21:23:25 -04:00
|
|
|
CStdio::CStdio(uint8* ram, CIoman& ioman)
|
2018-04-30 21:01:23 +01:00
|
|
|
: m_ram(ram)
|
|
|
|
, m_ioman(ioman)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-03-31 23:24:25 +00:00
|
|
|
std::string CStdio::GetId() const
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2012-03-31 23:24:25 +00:00
|
|
|
return "stdio";
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2012-03-31 23:24:25 +00:00
|
|
|
std::string CStdio::GetFunctionName(unsigned int functionId) const
|
2008-11-28 23:46:52 +00:00
|
|
|
{
|
2012-03-31 23:24:25 +00:00
|
|
|
switch(functionId)
|
|
|
|
{
|
|
|
|
case 4:
|
|
|
|
return FUNCTION_PRINTF;
|
|
|
|
break;
|
2018-05-27 15:11:48 -04:00
|
|
|
case 7:
|
|
|
|
return FUNCTION_PUTS;
|
|
|
|
break;
|
2012-03-31 23:24:25 +00:00
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
break;
|
|
|
|
}
|
2008-11-28 23:46:52 +00:00
|
|
|
}
|
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
void CStdio::Invoke(CMIPS& context, unsigned int functionId)
|
|
|
|
{
|
2012-03-31 23:24:25 +00:00
|
|
|
switch(functionId)
|
|
|
|
{
|
|
|
|
case 4:
|
|
|
|
__printf(context);
|
|
|
|
break;
|
2018-05-27 15:11:48 -04:00
|
|
|
case 7:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = __puts(
|
2018-05-28 12:39:50 -04:00
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0);
|
2019-11-27 16:10:35 +00:00
|
|
|
break;
|
2012-03-31 23:24:25 +00:00
|
|
|
default:
|
2018-05-24 12:59:15 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "Unknown function (%d) called. PC = (%08X).\r\n",
|
|
|
|
functionId, context.m_State.nPC);
|
2012-03-31 23:24:25 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2016-05-27 16:46:31 +01:00
|
|
|
std::string CStdio::PrintFormatted(const char* format, CArgumentIterator& args)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2016-05-29 16:41:31 -04:00
|
|
|
std::string output;
|
2012-03-31 23:24:25 +00:00
|
|
|
while(*format != 0)
|
|
|
|
{
|
|
|
|
char character = *(format++);
|
|
|
|
if(character == '%')
|
|
|
|
{
|
|
|
|
bool paramDone = false;
|
|
|
|
bool inPrecision = false;
|
2016-10-15 21:26:01 -04:00
|
|
|
bool showSign = false;
|
2011-02-26 22:42:59 +00:00
|
|
|
char fillChar = ' ';
|
2012-03-31 23:24:25 +00:00
|
|
|
std::string precision;
|
2018-04-30 21:01:23 +01:00
|
|
|
while(!paramDone && *format != 0)
|
2012-03-31 23:24:25 +00:00
|
|
|
{
|
|
|
|
char type = *(format++);
|
2014-05-31 04:46:45 -04:00
|
|
|
if(type == '%')
|
|
|
|
{
|
2014-05-30 12:49:40 +01:00
|
|
|
output += type;
|
|
|
|
paramDone = true;
|
|
|
|
}
|
2016-10-15 21:26:01 -04:00
|
|
|
else if(type == '+')
|
|
|
|
{
|
|
|
|
showSign = true;
|
|
|
|
}
|
2014-05-30 12:49:40 +01:00
|
|
|
else if(type == 's')
|
2012-03-31 23:24:25 +00:00
|
|
|
{
|
|
|
|
const char* text = reinterpret_cast<const char*>(&m_ram[args.GetNext()]);
|
|
|
|
output += text;
|
|
|
|
paramDone = true;
|
|
|
|
}
|
2011-05-05 04:22:47 +00:00
|
|
|
else if(type == 'c')
|
|
|
|
{
|
|
|
|
char character = static_cast<char>(args.GetNext());
|
|
|
|
output += character;
|
|
|
|
paramDone = true;
|
|
|
|
}
|
2012-03-31 23:37:42 +00:00
|
|
|
else if(type == 'd' || type == 'i')
|
2012-03-31 23:24:25 +00:00
|
|
|
{
|
|
|
|
int number = args.GetNext();
|
2019-06-04 18:18:25 +01:00
|
|
|
unsigned int precisionValue = precision.length() ? std::stoul(precision) : 1;
|
2016-10-15 21:26:01 -04:00
|
|
|
if(showSign && (number >= 0))
|
|
|
|
{
|
|
|
|
output += "+";
|
|
|
|
}
|
2012-03-31 23:24:25 +00:00
|
|
|
output += lexical_cast_int<std::string>(number, precisionValue, fillChar);
|
|
|
|
paramDone = true;
|
|
|
|
}
|
|
|
|
else if(type == 'u')
|
|
|
|
{
|
|
|
|
unsigned int number = args.GetNext();
|
2019-06-04 18:18:25 +01:00
|
|
|
unsigned int precisionValue = precision.length() ? std::stoul(precision) : 1;
|
2012-03-31 23:24:25 +00:00
|
|
|
output += lexical_cast_uint<std::string>(number, precisionValue);
|
|
|
|
paramDone = true;
|
|
|
|
}
|
2012-07-29 19:37:36 +00:00
|
|
|
else if(type == 'x' || type == 'X' || type == 'p')
|
2012-03-31 23:24:25 +00:00
|
|
|
{
|
|
|
|
uint32 number = args.GetNext();
|
2015-10-27 00:23:27 -04:00
|
|
|
std::string format;
|
|
|
|
if(precision.empty())
|
|
|
|
{
|
|
|
|
format = string_format("%%%c", type);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned int precisionValue = atoi(precision.c_str());
|
|
|
|
format = string_format("%%0%d%c", precisionValue, type);
|
|
|
|
}
|
|
|
|
output += string_format(format.c_str(), number);
|
2012-03-31 23:24:25 +00:00
|
|
|
paramDone = true;
|
|
|
|
}
|
|
|
|
else if(type == 'l')
|
|
|
|
{
|
|
|
|
//Length specifier, don't bother about it.
|
|
|
|
}
|
|
|
|
else if(type == '.')
|
|
|
|
{
|
|
|
|
inPrecision = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(isdigit(type));
|
|
|
|
if(inPrecision)
|
|
|
|
{
|
|
|
|
precision += type;
|
|
|
|
}
|
2011-02-26 22:42:59 +00:00
|
|
|
else
|
|
|
|
{
|
2019-10-31 18:57:44 -04:00
|
|
|
fillChar = '0';
|
2011-02-26 22:42:59 +00:00
|
|
|
inPrecision = true;
|
|
|
|
}
|
2012-03-31 23:24:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
output += character;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return output;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CStdio::__printf(CMIPS& context)
|
|
|
|
{
|
2016-05-29 16:41:31 -04:00
|
|
|
CCallArgumentIterator args(context);
|
|
|
|
auto format = reinterpret_cast<const char*>(m_ram + args.GetNext());
|
2016-05-27 16:46:31 +01:00
|
|
|
auto output = PrintFormatted(format, args);
|
2014-08-02 21:23:25 -04:00
|
|
|
m_ioman.Write(CIoman::FID_STDOUT, output.length(), output.c_str());
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
2018-05-27 15:11:48 -04:00
|
|
|
|
|
|
|
int32 CStdio::__puts(uint32 stringPtr)
|
|
|
|
{
|
|
|
|
auto string = reinterpret_cast<const char*>(m_ram + stringPtr);
|
|
|
|
m_ioman.Write(CIoman::FID_STDOUT, strlen(string), string);
|
|
|
|
return 0;
|
|
|
|
}
|