fork download
  1. #include<cstdlib>
  2. #include<cstdint>
  3. #include<cstddef>
  4. #include<cstdio>
  5. #include<initializer_list>
  6.  
  7.  
  8.  
  9. namespace test{
  10.  
  11.  
  12. enum class
  13. opcode
  14. {
  15. nop,
  16. addi,
  17. ori,
  18. lui,
  19. lt,
  20. brz,
  21. brnz,
  22. exi,
  23.  
  24. };
  25.  
  26.  
  27. struct nop{};
  28. struct exi{};
  29.  
  30. struct
  31. addi
  32. {
  33. uint8_t r1;
  34. uint8_t r2;
  35.  
  36. int16_t imm;
  37.  
  38. };
  39.  
  40.  
  41. struct
  42. lui
  43. {
  44. uint8_t r1;
  45.  
  46. uint16_t imm;
  47.  
  48. };
  49.  
  50.  
  51. struct
  52. ori
  53. {
  54. uint8_t r1;
  55. uint8_t r2;
  56.  
  57. uint16_t imm;
  58.  
  59. };
  60.  
  61.  
  62. struct
  63. lt
  64. {
  65. uint8_t r1;
  66. uint8_t r2;
  67. uint8_t r3;
  68.  
  69. };
  70.  
  71.  
  72. struct
  73. brz
  74. {
  75. uint8_t r1;
  76.  
  77. int16_t offset;
  78.  
  79. };
  80.  
  81.  
  82. struct
  83. brnz
  84. {
  85. uint8_t r1;
  86.  
  87. int16_t offset;
  88.  
  89. };
  90.  
  91.  
  92. struct
  93. inst_code
  94. {
  95. uint32_t m_data=0;
  96.  
  97. static constexpr uint32_t to_code(opcode c) noexcept{return static_cast<int>(c)<<26;}
  98.  
  99. public:
  100. constexpr inst_code() noexcept{}
  101.  
  102. constexpr inst_code(test::addi addi) noexcept:
  103. m_data(to_code(opcode::addi)|(addi.r1<<21)|(addi.r2<<16)|(addi.imm&0xFFFF)){}
  104.  
  105. constexpr inst_code(test::ori ori) noexcept:
  106. m_data(to_code(opcode::ori)|(ori.r1<<21)|(ori.r2<<16)|(ori.imm&0xFFFF)){}
  107.  
  108. constexpr inst_code(test::lui lui) noexcept:
  109. m_data(to_code(opcode::lui)|(lui.r1<<21)|(lui.imm&0xFFFF)){}
  110.  
  111. constexpr inst_code(test::lt lt) noexcept:
  112. m_data(to_code(opcode::lt)|(lt.r1<<21)|(lt.r2<<16)|lt.r3){}
  113.  
  114. constexpr inst_code(test::brz brz) noexcept:
  115. m_data(to_code(opcode::brz)|(brz.r1<<21)|(brz.offset&0xFFFF)){}
  116.  
  117. constexpr inst_code(test::brnz brnz) noexcept:
  118. m_data(to_code(opcode::brnz)|(brnz.r1<<21)|(brnz.offset&0xFFFF)){}
  119.  
  120. constexpr inst_code(test::exi exi) noexcept:
  121. m_data(to_code(opcode::exi)){}
  122.  
  123. constexpr opcode get_opcode() const noexcept
  124. {
  125. return static_cast<opcode>(m_data>>26);
  126. }
  127.  
  128. constexpr uint8_t get_r1() const noexcept{return (m_data>>21)&0x1F;}
  129. constexpr uint8_t get_r2() const noexcept{return (m_data>>16)&0x1F;}
  130. constexpr uint8_t get_r3() const noexcept{return (m_data )&0x1F;}
  131.  
  132. constexpr uint16_t get_imm_u16() const noexcept{return (m_data&0xFFFF);}
  133. constexpr int16_t get_imm_s16() const noexcept{return (m_data&0xFFFF);}
  134.  
  135. };
  136.  
  137.  
  138. class
  139. register_set
  140. {
  141. static constexpr int number_of_registers = 32;
  142.  
  143. int32_t m_registers[number_of_registers] = {0};
  144.  
  145. public:
  146. int32_t get(uint8_t i ) const noexcept{return m_registers[i] ;}
  147. void put(uint8_t i, int32_t v) noexcept{ m_registers[i] = v;}
  148.  
  149. void addi(uint8_t dst, uint8_t src, int16_t imm) noexcept
  150. {
  151. m_registers[dst] = m_registers[src]+imm;
  152. }
  153.  
  154. void ori(uint8_t dst, uint8_t src, uint16_t imm) noexcept
  155. {
  156. m_registers[dst] = m_registers[src]|imm;
  157. }
  158.  
  159. void lui(uint8_t dst, int16_t imm) noexcept
  160. {
  161. m_registers[dst] = imm<<16;
  162. }
  163.  
  164. void lt(uint8_t dst, uint8_t src1, uint8_t src2) noexcept
  165. {
  166. m_registers[dst] = (m_registers[src1] < m_registers[src2])? 1:0;
  167. }
  168.  
  169. };
  170.  
  171.  
  172. class
  173. memory_space
  174. {
  175. static constexpr size_t data_size = 256;
  176.  
  177. uint8_t m_data[data_size];
  178.  
  179. public:
  180. memory_space() noexcept{}
  181. memory_space(std::initializer_list<inst_code> ls) noexcept{assign(ls);}
  182.  
  183. void assign(std::initializer_list<inst_code> ls) noexcept
  184. {
  185. auto p = reinterpret_cast<inst_code*>(&m_data[0]);
  186.  
  187. for(auto icode: ls)
  188. {
  189. *p++ = icode;
  190. }
  191. }
  192.  
  193.  
  194. inst_code fetch(uint32_t pc) const noexcept{return *reinterpret_cast<const inst_code*>(&m_data[pc&~3]);}
  195.  
  196. size_t size() const noexcept{return data_size;}
  197.  
  198. uint8_t& get_u8( uint32_t address) noexcept{return m_data[address];}
  199. int8_t& get_s8( uint32_t address) noexcept{return reinterpret_cast< int8_t&>(m_data[address ]);}
  200. uint16_t& get_u16(uint32_t address) noexcept{return reinterpret_cast<uint16_t&>(m_data[address&~1]);}
  201. int16_t& get_s16(uint32_t address) noexcept{return reinterpret_cast< int16_t&>(m_data[address&~1]);}
  202. uint32_t& get_u32(uint32_t address) noexcept{return reinterpret_cast<uint32_t&>(m_data[address&~3]);}
  203. int32_t& get_s32(uint32_t address) noexcept{return reinterpret_cast< int32_t&>(m_data[address&~3]);}
  204.  
  205. };
  206.  
  207.  
  208. class
  209. vm
  210. {
  211. uint32_t m_pc=0;
  212.  
  213. register_set* m_register_set=nullptr;
  214. memory_space* m_memory_space=nullptr;
  215.  
  216. bool m_is_exited=false;
  217.  
  218. public:
  219. vm(register_set& regset, memory_space& memsp) noexcept:
  220. m_register_set(&regset), m_memory_space(&memsp){}
  221.  
  222. bool is_exited() const noexcept{return m_is_exited;}
  223.  
  224. uint32_t get_pc() const noexcept{return m_pc;}
  225.  
  226. void step() noexcept
  227. {
  228. auto inst = m_memory_space->fetch(m_pc);
  229.  
  230. m_pc += 4;
  231.  
  232. switch(inst.get_opcode())
  233. {
  234. case(opcode::nop):
  235. break;
  236. case(opcode::addi):
  237. m_register_set->addi(inst.get_r1(),inst.get_r2(),inst.get_imm_s16());
  238. break;
  239. case(opcode::ori):
  240. m_register_set->ori(inst.get_r1(),inst.get_r2(),inst.get_imm_u16());
  241. break;
  242. case(opcode::lui):
  243. m_register_set->lui(inst.get_r1(),inst.get_imm_u16());
  244. break;
  245. case(opcode::lt):
  246. m_register_set->lt(inst.get_r1(),inst.get_r2(),inst.get_r3());
  247. break;
  248. case(opcode::brz):
  249. if(m_register_set->get(inst.get_r1()) == 0)
  250. {
  251. m_pc += inst.get_imm_s16()<<2;
  252. }
  253. break;
  254. case(opcode::brnz):
  255. if(m_register_set->get(inst.get_r1()))
  256. {
  257. m_pc += inst.get_imm_s16()<<2;
  258. }
  259. break;
  260. case(opcode::exi):
  261. m_is_exited = true;
  262. break;
  263. default:
  264. printf("[%d]",static_cast<int>(inst.get_opcode()));
  265. }
  266. }
  267.  
  268. };
  269.  
  270.  
  271.  
  272. }
  273.  
  274.  
  275. int
  276. main(int argc, char** argv)
  277. {
  278. using namespace test;
  279.  
  280. bool pr = (argc > 1);
  281.  
  282. test::memory_space mem({
  283. inst_code(addi{1,0,0}),
  284. inst_code(lui{2,0xFF}),
  285. inst_code(ori{2,2,0xFFFF}),
  286. inst_code(lt{3,1,2}),
  287. inst_code(brz{3,2}),
  288.  
  289. inst_code(addi{1,1,1}),
  290.  
  291. inst_code(brz{0,-4}),
  292. inst_code(exi{}),
  293. });
  294.  
  295.  
  296. test::register_set regset;
  297.  
  298. test::vm vm(regset,mem);
  299.  
  300. while(!vm.is_exited())
  301. {
  302. if(pr){printf("%8d",vm.get_pc());}
  303. vm.step();
  304.  
  305. if(pr){printf(" %d\n",regset.get(1));}
  306. }
  307.  
  308.  
  309.  
  310. return 0;
  311. }
  312.  
  313.  
  314.  
  315.  
Success #stdin #stdout 0.31s 4420KB
stdin
Standard input is empty
stdout
Standard output is empty