1 // Copyright 2009 Dolphin Emulator Project
2 // Copyright 2005 Duddie
3 // Licensed under GPLv2+
4 // Refer to the license.txt file included.
5 
6 #pragma once
7 
8 #include <cstddef>
9 #include <map>
10 #include <string>
11 #include <vector>
12 
13 #include "Common/CommonTypes.h"
14 
15 #include "Core/DSP/DSPDisassembler.h"
16 #include "Core/DSP/DSPTables.h"
17 #include "Core/DSP/LabelMap.h"
18 
19 namespace DSP
20 {
21 enum class AssemblerError
22 {
23   OK,
24   Unknown,
25   UnknownOpcode,
26   NotEnoughParameters,
27   TooManyParameters,
28   WrongParameter,
29   ExpectedParamStr,
30   ExpectedParamVal,
31   ExpectedParamReg,
32   ExpectedParamMem,
33   ExpectedParamImm,
34   IncorrectBinary,
35   IncorrectHex,
36   IncorrectDecimal,
37   LabelAlreadyExists,
38   UnknownLabel,
39   NoMatchingBrackets,
40   CantExtendOpcode,
41   ExtensionParamsOnNonExtendableOpcode,
42   WrongParameterExpectedAccumulator,
43   WrongParameterExpectedMidAccumulator,
44   InvalidRegister,
45   NumberOutOfRange,
46   PCOutOfRange,
47 };
48 
49 // Unless you want labels to carry over between files, you probably
50 // want to create a new DSPAssembler for every file you assemble.
51 class DSPAssembler
52 {
53 public:
54   explicit DSPAssembler(const AssemblerSettings& settings);
55   ~DSPAssembler();
56 
57   // line_numbers is optional (and not yet implemented). It'll receieve a list of ints,
58   // one for each word of code, indicating the source assembler code line number it came from.
59 
60   // If returns false, call GetErrorString to get some text to present to the user.
61   bool Assemble(const std::string& text, std::vector<u16>& code,
62                 std::vector<int>* line_numbers = nullptr);
63 
GetErrorString()64   std::string GetErrorString() const { return m_last_error_str; }
GetError()65   AssemblerError GetError() const { return m_last_error; }
66 
67 private:
68   struct param_t
69   {
70     u32 val;
71     partype_t type;
72     char* str;
73   };
74 
75   enum segment_t
76   {
77     SEGMENT_CODE = 0,
78     SEGMENT_DATA,
79     SEGMENT_OVERLAY,
80     SEGMENT_MAX
81   };
82 
83   enum class OpcodeType
84   {
85     Primary,
86     Extension
87   };
88 
89   // Utility functions
90   s32 ParseValue(const char* str);
91   u32 ParseExpression(const char* ptr);
92 
93   u32 GetParams(char* parstr, param_t* par);
94 
95   void InitPass(int pass);
96   bool AssemblePass(const std::string& text, int pass);
97 
98   void ShowError(AssemblerError err_code, const char* extra_info = nullptr);
99 
100   char* FindBrackets(char* src, char* dst);
101   const DSPOPCTemplate* FindOpcode(std::string name, size_t par_count, OpcodeType type);
102   bool VerifyParams(const DSPOPCTemplate* opc, param_t* par, size_t count, OpcodeType type);
103   void BuildCode(const DSPOPCTemplate* opc, param_t* par, u32 par_count, u16* outbuf);
104 
105   std::vector<u16> m_output_buffer;
106 
107   std::string m_include_dir;
108   std::string m_cur_line;
109 
110   u32 m_cur_addr = 0;
111   int m_total_size = 0;
112   u8 m_cur_pass = 0;
113 
114   LabelMap m_labels;
115 
116   u32 m_code_line = 0;
117   bool m_failed = false;
118   std::string m_last_error_str;
119   AssemblerError m_last_error = AssemblerError::OK;
120 
121   using AliasMap = std::map<std::string, std::string>;
122   AliasMap m_aliases;
123 
124   segment_t m_cur_segment = SEGMENT_CODE;
125   u32 m_segment_addr[SEGMENT_MAX] = {};
126   int m_current_param = 0;
127   const AssemblerSettings m_settings;
128 };
129 }  // namespace DSP
130