blob: 810cad9c1b2c06d4035f306609a8ebc8fd31d307 [file] [log] [blame]
/*
* Copyright (c) 2017, Intel Corporation
*
* 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.
*/
#pragma once
#include "cm_printf_base.h"
#include <string>
#define CM_PRINTF(f_, ...) fprintf((f_), __VA_ARGS__)
#define PRINT_BUFFER_HEADER_SIZE 32
#define PRINT_PAYLOAD_ALIGN 16
#define PRINT_HEADER_SIZE 32
#define PRINT_FORMAT_STRING_SIZE 128
#define CM_PRINT_SIZE_WITH_PAYLOAD(msize) (PRINT_HEADER_SIZE + (msize-1) / PRINT_PAYLOAD_ALIGN * PRINT_PAYLOAD_ALIGN + PRINT_PAYLOAD_ALIGN)
/// Structure of header:
/// vector<int, 8> header
/// [0]: Object type: matrix,vector,scalar,string, or format string.
/// [1]: Data type: [u]*int[136]*[6248]_t, float, or double.
/// [2]: width
/// [3]: height
/// [4]: tid
/// [5]: reserved3
/// [6]: Scalar lower 32bits: [u]*int[13]*[628]_t, float. Lower 32bits of double and [u]*int64_t.
/// [7]: Scalar upper 32bits: Upper 32bits of double and [u]*int64_t.
typedef struct _CM_PRINT_HEADER{
unsigned int objectType;
unsigned int dataType;
unsigned int width;
unsigned int height;
unsigned int tid;
unsigned int reserved3;
unsigned long long scalar64;
}CM_PRINT_HEADER, *PCM_PRINT_HEADER;
enum PRINT_FMT_STATUS
{
PF_FAIL = 0,
PF_SUCCESS = 1
};
// A small class used to contain the state machine used when parsing the printf string
// The issue we have to deal with is that there is a format string with some directives in it - the
// format string is received as an object from the client as an object in memory
// Any arguments are then passed as separate objects in memory. How many objects are required is
// determined by the format string.
// The cleanest way to deal with this is to use a very simple recursive descent parser on the format
// string in order to process the arguments in the correct way
// Here's the grammar for printf format strings (using EBNF). Only one format directive is to be
// returned from the input at a time:
//
// format:
// { STRING } directive
//
//
// directive:
// PERCENT flags { width } { PERIOD precision } { length_modifier } conversion
//
// flags:
// { MINUS } { PLUS } { SPACE } { ZERO } { HASH }
//
// width:
// INTEGER
// | STAR
//
// precision:
// INTEGER
// | STAR
//
// length_modifier:
// hh_MOD | h_MOD | l_MOD | ll_MOD | j_MOD | t_MOD | z_MOD | L_MOD
//
// conversion:
// PERCENT
// | c_CONV
// | s_CONV
// | d_CONV
// | i_CONV
// | o_CONV
// | x_CONV
// | X_CONV
// | u_CONV
// | f_CONV
// | F_CONV
// | e_CONV
// | E_CONV
// | a_CONV
// | A_CONV
// | g_CONV
// | G_CONV
// | n_CONV
// | p_CONV
//
// STRING : [any ASCII character that isn't a %]+
// PERCENT : '%'
// MINUS : '-'
// PLUS : '+'
// SPACE : ' '
// ZERO : '0'
// INTEGER : [
// PERIOD : '.'
// HASH : '#'
// hh_MOD : 'hh'
// h_MOD : 'h'
// l_MOD : 'l'
// ll_MOD : 'll'
// j_MOD : 'j'
// z_MOD : 'z'
// t_MOD : 't'
// L_MOD : 'L'
// STAR : '*'
// c_CONV : 'c'
// s_CONV : 's'
// d_CONV : 'd'
// i_CONV : 'i'
// o_CONV : 'o'
// x_CONV : 'x'
// X_CONV : 'X'
// u_CONV : 'u'
// f_CONV : 'f'
// F_CONV : 'F'
// e_CONV : 'e'
// E_CONV : 'E'
// a_CONV : 'a'
// A_CONV : 'A'
// g_CONV : 'g'
// G_CONV : 'G'
// n_CONV : 'n'
// p_CONV : 'p'
class PFParser
{
public:
PFParser(FILE* streamout) : m_inSpec(false), m_inputStart(nullptr), m_currLoc(nullptr), m_argsExpected(0),
m_numMultArg(0), m_unsupported(false), m_error(false), m_streamOut(streamout) {};
void SetStart(char *start)
{
m_inputStart= m_currLoc = start;
// Prime the system with the first token
getToken();
}
void DumpMemory(unsigned char * memory);
void Flush(void);
protected:
private:
class Token
{
public:
enum TokenType { _None_, Error,
String, Percent, Minus, Plus, Space, Zero, Integer, Period, Hash, Star,
hh_Mod, h_Mod, l_Mod, ll_Mod, j_Mod, z_Mod, t_Mod, L_Mod,
c_Conv, s_Conv, d_Conv, i_Conv, o_Conv, x_Conv, X_Conv, u_Conv, f_Conv,
F_Conv, e_Conv, E_Conv, a_Conv, A_Conv, g_Conv, G_Conv, n_Conv, p_Conv,
End
};
Token() : tokenType(_None_), tokenInt(0) {};
bool operator==(const Token &other) const {
return tokenType == other.tokenType;
}
bool operator==(const TokenType &other) const {
return tokenType == other;
}
bool operator!=(const Token &other) const {
return tokenType != other.tokenType;
}
bool operator!=(const TokenType &other) const {
return tokenType != other;
}
TokenType tokenType;
std::string tokenString;
int tokenInt;
};
bool m_inSpec; // Mode for lexer - in spec mode or not
Token m_currToken; // The currently lexed token
Token m_prevToken; // The previously lexed token
char *m_inputStart; // The start of the input string
char *m_currLoc; // The current point of processing
int m_argsExpected; // For multi-arg format directives - how many still to process
int m_numMultArg; // Total number of multi-arg format directives in total
int m_args[2]; // Up to 2 int args can be used in multi-arg format directives
bool m_unsupported; // Has the latest parsed format directive contained unsupported
// directives (VS doesn't support them all so we can't print them)
bool m_error; // Error in latest parsed format directive
FILE *m_streamOut; // Output stream for kernel print
PRINT_FMT_STATUS GetNextFmtToken(char * tkn, size_t size);
bool outputToken(const char *tkn, PCM_PRINT_HEADER header);
void getToken(void);
void reset(void)
{
m_inputStart = m_currLoc;
m_unsupported = false;
m_error = false;
m_numMultArg = m_argsExpected = 0;
}
void error()
{
// We don't throw an error in this case
// Just set the error flag
m_error = true;
}
bool accept(Token::TokenType s);
bool expect(Token::TokenType s);
int format(void); // This function returns the number of args for the next format 0,1,2 or 3
int directive(void);
void flags(void);
int width(void);
int precision(void);
void length_modifier(void);
int conversion(void);
};
void DumpAllThreadOutput( FILE *streamOut, unsigned char * dumpMem, size_t buffersize);