From 695f9bf8d0a7d0a871b8ab75270ceb29715d9be3 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Thu, 25 Jul 2019 00:08:23 -0700 Subject: 5468 --- html/subx/010---vm.cc.html | 385 +++++++++++++++++++++++---------------------- 1 file changed, 193 insertions(+), 192 deletions(-) (limited to 'html/subx/010---vm.cc.html') diff --git a/html/subx/010---vm.cc.html b/html/subx/010---vm.cc.html index 5dcabeb4..5266d5ab 100644 --- a/html/subx/010---vm.cc.html +++ b/html/subx/010---vm.cc.html @@ -257,13 +257,13 @@ if ('onhashchange' in window) { 196 for (int i = 0; i < SIZE(Mem); ++i) { 197 if (Mem.at(i).match(addr)) { 198 if (result) -199 raise << "address 0x" << HEXWORD << addr << " is in two segments\n" << end(); +199 raise << "address 0x" << HEXWORD << addr << " is in two segments\n" << end(); 200 result = &Mem.at(i).data(addr); 201 } 202 } 203 if (result == NULL) { -204 if (Trace_file) Trace_file.flush(); -205 raise << "Tried to access uninitialized memory at address 0x" << HEXWORD << addr << '\n' << end(); +204 if (Trace_file) Trace_file.flush(); +205 raise << "Tried to access uninitialized memory at address 0x" << HEXWORD << addr << '\n' << end(); 206 exit(1); 207 } 208 return result; @@ -276,200 +276,201 @@ if ('onhashchange' in window) { 215 for (int i = 0; i < SIZE(Mem); ++i) { 216 if (Mem.at(i).match32(addr)) { 217 if (result) -218 raise << "address 0x" << HEXWORD << addr << " is in two segments\n" << end(); +218 raise << "address 0x" << HEXWORD << addr << " is in two segments\n" << end(); 219 result = reinterpret_cast<uint32_t*>(&Mem.at(i).data(addr)); 220 } 221 } 222 if (result == NULL) { -223 if (Trace_file) Trace_file.flush(); -224 raise << "Tried to access uninitialized memory at address 0x" << HEXWORD << addr << '\n' << end(); -225 raise << "The entire 4-byte word should be initialized and lie in a single segment.\n" << end(); -226 } -227 return result; -228 } -229 inline int32_t* mem_addr_i32(uint32_t addr) { -230 return reinterpret_cast<int32_t*>(mem_addr_u32(addr)); -231 } -232 // helper for some syscalls. But read-only. -233 inline const char* mem_addr_kernel_string(uint32_t addr) { -234 return reinterpret_cast<const char*>(mem_addr_u8(addr)); -235 } -236 inline string mem_addr_string(uint32_t addr, uint32_t size) { -237 ostringstream out; -238 for (size_t i = 0; i < size; ++i) -239 out << read_mem_u8(addr+i); -240 return out.str(); -241 } -242 +223 if (Trace_file) Trace_file.flush(); +224 raise << "Tried to access uninitialized memory at address 0x" << HEXWORD << addr << '\n' << end(); +225 raise << "The entire 4-byte word should be initialized and lie in a single segment.\n" << end(); +226 exit(1); +227 } +228 return result; +229 } +230 inline int32_t* mem_addr_i32(uint32_t addr) { +231 return reinterpret_cast<int32_t*>(mem_addr_u32(addr)); +232 } +233 // helper for some syscalls. But read-only. +234 inline const char* mem_addr_kernel_string(uint32_t addr) { +235 return reinterpret_cast<const char*>(mem_addr_u8(addr)); +236 } +237 inline string mem_addr_string(uint32_t addr, uint32_t size) { +238 ostringstream out; +239 for (size_t i = 0; i < size; ++i) +240 out << read_mem_u8(addr+i); +241 return out.str(); +242 } 243 -244 inline void write_mem_u8(uint32_t addr, uint8_t val) { -245 uint8_t* handle = mem_addr_u8(addr); -246 if (handle != NULL) *handle = val; -247 } -248 inline void write_mem_i8(uint32_t addr, int8_t val) { -249 int8_t* handle = mem_addr_i8(addr); -250 if (handle != NULL) *handle = val; -251 } -252 inline void write_mem_u32(uint32_t addr, uint32_t val) { -253 uint32_t* handle = mem_addr_u32(addr); -254 if (handle != NULL) *handle = val; -255 } -256 inline void write_mem_i32(uint32_t addr, int32_t val) { -257 int32_t* handle = mem_addr_i32(addr); -258 if (handle != NULL) *handle = val; -259 } -260 -261 inline bool already_allocated(uint32_t addr) { -262 bool result = false; -263 for (int i = 0; i < SIZE(Mem); ++i) { -264 if (Mem.at(i).match(addr)) { -265 if (result) -266 raise << "address 0x" << HEXWORD << addr << " is in two segments\n" << end(); -267 result = true; -268 } -269 } -270 return result; -271 } -272 -273 //:: core interpreter loop -274 -275 :(code) -276 // skeleton of how x86 instructions are decoded -277 void run_one_instruction() { -278 uint8_t op=0, op2=0, op3=0; -279 // Run One Instruction -280 if (Trace_file) { -281 dump_registers(); -282 // End Dump Info for Instruction -283 } -284 uint32_t inst_start_address = EIP; -285 op = next(); -286 trace(Callstack_depth+1, "run") << "0x" << HEXWORD << inst_start_address << " opcode: " << HEXBYTE << NUM(op) << end(); -287 switch (op) { -288 case 0xf4: // hlt -289 EIP = End_of_program; -290 break; -291 // End Single-Byte Opcodes -292 case 0x0f: -293 switch(op2 = next()) { -294 // End Two-Byte Opcodes Starting With 0f -295 default: -296 cerr << "unrecognized second opcode after 0f: " << HEXBYTE << NUM(op2) << '\n'; -297 exit(1); -298 } -299 break; -300 case 0xf2: -301 switch(op2 = next()) { -302 // End Two-Byte Opcodes Starting With f2 -303 case 0x0f: -304 switch(op3 = next()) { -305 // End Three-Byte Opcodes Starting With f2 0f -306 default: -307 cerr << "unrecognized third opcode after f2 0f: " << HEXBYTE << NUM(op3) << '\n'; -308 exit(1); -309 } -310 break; -311 default: -312 cerr << "unrecognized second opcode after f2: " << HEXBYTE << NUM(op2) << '\n'; -313 exit(1); -314 } -315 break; -316 case 0xf3: -317 switch(op2 = next()) { -318 // End Two-Byte Opcodes Starting With f3 -319 case 0x0f: -320 switch(op3 = next()) { -321 // End Three-Byte Opcodes Starting With f3 0f -322 default: -323 cerr << "unrecognized third opcode after f3 0f: " << HEXBYTE << NUM(op3) << '\n'; -324 exit(1); -325 } -326 break; -327 default: -328 cerr << "unrecognized second opcode after f3: " << HEXBYTE << NUM(op2) << '\n'; -329 exit(1); -330 } -331 break; -332 default: -333 cerr << "unrecognized opcode: " << HEXBYTE << NUM(op) << '\n'; -334 exit(1); -335 } -336 } -337 -338 inline uint8_t next() { -339 return read_mem_u8(EIP++); -340 } -341 -342 void dump_registers() { -343 ostringstream out; -344 out << "registers before: "; -345 for (int i = 0; i < NUM_INT_REGISTERS; ++i) { -346 if (i > 0) out << "; "; -347 out << " " << i << ": " << std::hex << std::setw(8) << std::setfill('_') << Reg[i].u; -348 } -349 out << " -- SF: " << SF << "; ZF: " << ZF << "; CF: " << CF << "; OF: " << OF; -350 trace(Callstack_depth+1, "run") << out.str() << end(); -351 } -352 -353 //: start tracking supported opcodes -354 :(before "End Globals") -355 map</*op*/string, string> Name; -356 map</*op*/string, string> Name_0f; -357 map</*op*/string, string> Name_f3; -358 map</*op*/string, string> Name_f3_0f; -359 :(before "End One-time Setup") -360 init_op_names(); -361 :(code) -362 void init_op_names() { -363 put(Name, "f4", "halt (hlt)"); -364 // End Initialize Op Names -365 } -366 -367 :(before "End Help Special-cases(key)") -368 if (key == "opcodes") { -369 cerr << "Opcodes currently supported by SubX:\n"; -370 for (map<string, string>::iterator p = Name.begin(); p != Name.end(); ++p) -371 cerr << " " << p->first << ": " << p->second << '\n'; -372 for (map<string, string>::iterator p = Name_0f.begin(); p != Name_0f.end(); ++p) -373 cerr << " 0f " << p->first << ": " << p->second << '\n'; -374 for (map<string, string>::iterator p = Name_f3.begin(); p != Name_f3.end(); ++p) -375 cerr << " f3 " << p->first << ": " << p->second << '\n'; -376 for (map<string, string>::iterator p = Name_f3_0f.begin(); p != Name_f3_0f.end(); ++p) -377 cerr << " f3 0f " << p->first << ": " << p->second << '\n'; -378 cerr << "Run `subx help instructions` for details on words like 'r32' and 'disp8'.\n" -379 "For complete details on these instructions, consult the IA-32 manual (volume 2).\n" -380 "There's various versions of it online, such as https://c9x.me/x86.\n" -381 "The mnemonics in brackets will help you locate each instruction.\n"; -382 return 0; -383 } -384 :(before "End Help Contents") -385 cerr << " opcodes\n"; -386 -387 //: Helpers for managing trace depths -388 //: -389 //: We're going to use trace depths primarily to segment code running at -390 //: different frames of the call stack. This will make it easy for the trace -391 //: browser to collapse over entire calls. -392 //: -393 //: Errors will be at depth 0. -394 //: Warnings will be at depth 1. -395 //: SubX instructions will occupy depth 2 and up to Max_depth, organized by -396 //: stack frames. Each instruction's internal details will be one level deeper -397 //: than its 'main' depth. So 'call' instruction details will be at the same -398 //: depth as the instructions of the function it calls. -399 :(before "End Globals") -400 extern const int Initial_callstack_depth = 2; -401 int Callstack_depth = Initial_callstack_depth; -402 :(before "End Reset") -403 Callstack_depth = Initial_callstack_depth; -404 -405 :(before "End Includes") -406 #include <iomanip> -407 #define HEXBYTE std::hex << std::setw(2) << std::setfill('0') -408 #define HEXWORD std::hex << std::setw(8) << std::setfill('0') -409 // ugly that iostream doesn't print uint8_t as an integer -410 #define NUM(X) static_cast<int>(X) -411 #include <stdint.h> +244 +245 inline void write_mem_u8(uint32_t addr, uint8_t val) { +246 uint8_t* handle = mem_addr_u8(addr); +247 if (handle != NULL) *handle = val; +248 } +249 inline void write_mem_i8(uint32_t addr, int8_t val) { +250 int8_t* handle = mem_addr_i8(addr); +251 if (handle != NULL) *handle = val; +252 } +253 inline void write_mem_u32(uint32_t addr, uint32_t val) { +254 uint32_t* handle = mem_addr_u32(addr); +255 if (handle != NULL) *handle = val; +256 } +257 inline void write_mem_i32(uint32_t addr, int32_t val) { +258 int32_t* handle = mem_addr_i32(addr); +259 if (handle != NULL) *handle = val; +260 } +261 +262 inline bool already_allocated(uint32_t addr) { +263 bool result = false; +264 for (int i = 0; i < SIZE(Mem); ++i) { +265 if (Mem.at(i).match(addr)) { +266 if (result) +267 raise << "address 0x" << HEXWORD << addr << " is in two segments\n" << end(); +268 result = true; +269 } +270 } +271 return result; +272 } +273 +274 //:: core interpreter loop +275 +276 :(code) +277 // skeleton of how x86 instructions are decoded +278 void run_one_instruction() { +279 uint8_t op=0, op2=0, op3=0; +280 // Run One Instruction +281 if (Trace_file) { +282 dump_registers(); +283 // End Dump Info for Instruction +284 } +285 uint32_t inst_start_address = EIP; +286 op = next(); +287 trace(Callstack_depth+1, "run") << "0x" << HEXWORD << inst_start_address << " opcode: " << HEXBYTE << NUM(op) << end(); +288 switch (op) { +289 case 0xf4: // hlt +290 EIP = End_of_program; +291 break; +292 // End Single-Byte Opcodes +293 case 0x0f: +294 switch(op2 = next()) { +295 // End Two-Byte Opcodes Starting With 0f +296 default: +297 cerr << "unrecognized second opcode after 0f: " << HEXBYTE << NUM(op2) << '\n'; +298 exit(1); +299 } +300 break; +301 case 0xf2: +302 switch(op2 = next()) { +303 // End Two-Byte Opcodes Starting With f2 +304 case 0x0f: +305 switch(op3 = next()) { +306 // End Three-Byte Opcodes Starting With f2 0f +307 default: +308 cerr << "unrecognized third opcode after f2 0f: " << HEXBYTE << NUM(op3) << '\n'; +309 exit(1); +310 } +311 break; +312 default: +313 cerr << "unrecognized second opcode after f2: " << HEXBYTE << NUM(op2) << '\n'; +314 exit(1); +315 } +316 break; +317 case 0xf3: +318 switch(op2 = next()) { +319 // End Two-Byte Opcodes Starting With f3 +320 case 0x0f: +321 switch(op3 = next()) { +322 // End Three-Byte Opcodes Starting With f3 0f +323 default: +324 cerr << "unrecognized third opcode after f3 0f: " << HEXBYTE << NUM(op3) << '\n'; +325 exit(1); +326 } +327 break; +328 default: +329 cerr << "unrecognized second opcode after f3: " << HEXBYTE << NUM(op2) << '\n'; +330 exit(1); +331 } +332 break; +333 default: +334 cerr << "unrecognized opcode: " << HEXBYTE << NUM(op) << '\n'; +335 exit(1); +336 } +337 } +338 +339 inline uint8_t next() { +340 return read_mem_u8(EIP++); +341 } +342 +343 void dump_registers() { +344 ostringstream out; +345 out << "registers before: "; +346 for (int i = 0; i < NUM_INT_REGISTERS; ++i) { +347 if (i > 0) out << "; "; +348 out << " " << i << ": " << std::hex << std::setw(8) << std::setfill('_') << Reg[i].u; +349 } +350 out << " -- SF: " << SF << "; ZF: " << ZF << "; CF: " << CF << "; OF: " << OF; +351 trace(Callstack_depth+1, "run") << out.str() << end(); +352 } +353 +354 //: start tracking supported opcodes +355 :(before "End Globals") +356 map</*op*/string, string> Name; +357 map</*op*/string, string> Name_0f; +358 map</*op*/string, string> Name_f3; +359 map</*op*/string, string> Name_f3_0f; +360 :(before "End One-time Setup") +361 init_op_names(); +362 :(code) +363 void init_op_names() { +364 put(Name, "f4", "halt (hlt)"); +365 // End Initialize Op Names +366 } +367 +368 :(before "End Help Special-cases(key)") +369 if (key == "opcodes") { +370 cerr << "Opcodes currently supported by SubX:\n"; +371 for (map<string, string>::iterator p = Name.begin(); p != Name.end(); ++p) +372 cerr << " " << p->first << ": " << p->second << '\n'; +373 for (map<string, string>::iterator p = Name_0f.begin(); p != Name_0f.end(); ++p) +374 cerr << " 0f " << p->first << ": " << p->second << '\n'; +375 for (map<string, string>::iterator p = Name_f3.begin(); p != Name_f3.end(); ++p) +376 cerr << " f3 " << p->first << ": " << p->second << '\n'; +377 for (map<string, string>::iterator p = Name_f3_0f.begin(); p != Name_f3_0f.end(); ++p) +378 cerr << " f3 0f " << p->first << ": " << p->second << '\n'; +379 cerr << "Run `subx help instructions` for details on words like 'r32' and 'disp8'.\n" +380 "For complete details on these instructions, consult the IA-32 manual (volume 2).\n" +381 "There's various versions of it online, such as https://c9x.me/x86.\n" +382 "The mnemonics in brackets will help you locate each instruction.\n"; +383 return 0; +384 } +385 :(before "End Help Contents") +386 cerr << " opcodes\n"; +387 +388 //: Helpers for managing trace depths +389 //: +390 //: We're going to use trace depths primarily to segment code running at +391 //: different frames of the call stack. This will make it easy for the trace +392 //: browser to collapse over entire calls. +393 //: +394 //: Errors will be at depth 0. +395 //: Warnings will be at depth 1. +396 //: SubX instructions will occupy depth 2 and up to Max_depth, organized by +397 //: stack frames. Each instruction's internal details will be one level deeper +398 //: than its 'main' depth. So 'call' instruction details will be at the same +399 //: depth as the instructions of the function it calls. +400 :(before "End Globals") +401 extern const int Initial_callstack_depth = 2; +402 int Callstack_depth = Initial_callstack_depth; +403 :(before "End Reset") +404 Callstack_depth = Initial_callstack_depth; +405 +406 :(before "End Includes") +407 #include <iomanip> +408 #define HEXBYTE std::hex << std::setw(2) << std::setfill('0') +409 #define HEXWORD std::hex << std::setw(8) << std::setfill('0') +410 // ugly that iostream doesn't print uint8_t as an integer +411 #define NUM(X) static_cast<int>(X) +412 #include <stdint.h> -- cgit 1.4.1-2-gfad0