From ce2c1efc41470764126e9a1a7f4e0cfec4213587 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 14 Jul 2019 09:42:36 -0700 Subject: . --- html/subx/010---vm.cc.html | 415 ++++++++++++++++++++++----------------------- 1 file changed, 205 insertions(+), 210 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 ff722e43..5dcabeb4 100644 --- a/html/subx/010---vm.cc.html +++ b/html/subx/010---vm.cc.html @@ -3,8 +3,8 @@ Mu - subx/010---vm.cc - - + + @@ -14,15 +14,15 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background- body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.cSpecial { color: #008000; } .PreProc { color: #c000c0; } .LineNr { } .Constant { color: #008787; } +.Comment { color: #005faf; } .Delimiter { color: #c000c0; } .Special { color: #d70000; } .Identifier { color: #af5f00; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.Comment { color: #005faf; } +.cSpecial { color: #008000; } .SalientComment { color: #0000af; } --> @@ -40,7 +40,7 @@ function JumpToLine() if (lineNum.indexOf('L') == -1) { lineNum = 'L'+lineNum; } - lineElem = document.getElementById(lineNum); + var lineElem = document.getElementById(lineNum); /* Always jump to new location even if the line was hidden inside a fold, or * we corrected the raw number to a line ID. */ @@ -245,7 +245,7 @@ if ('onhashchange' in window) { 184 return static_cast<int8_t>(read_mem_u8(addr)); 185 } 186 inline uint32_t read_mem_u32(uint32_t addr) { -187 uint32_t* handle = mem_addr_u32(addr); // error messages get printed here +187 uint32_t* handle = mem_addr_u32(addr); // error messages get printed here 188 return handle ? *handle : 0; 189 } 190 inline int32_t read_mem_i32(uint32_t addr) { @@ -257,224 +257,219 @@ 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(); -206 } -207 return result; -208 } -209 inline int8_t* mem_addr_i8(uint32_t addr) { -210 return reinterpret_cast<int8_t*>(mem_addr_u8(addr)); -211 } -212 inline uint32_t* mem_addr_u32(uint32_t addr) { -213 uint32_t* result = NULL; -214 for (int i = 0; i < SIZE(Mem); ++i) { -215 if (Mem.at(i).match32(addr)) { -216 if (result) -217 raise << "address 0x" << HEXWORD << addr << " is in two segments\n" << end(); -218 result = reinterpret_cast<uint32_t*>(&Mem.at(i).data(addr)); -219 } -220 } -221 if (result == NULL) { -222 if (Trace_file) Trace_file.flush(); -223 raise << "Tried to access uninitialized memory at address 0x" << HEXWORD << addr << '\n' << end(); -224 raise << "The entire 4-byte word should be initialized and lie in a single segment.\n" << end(); -225 } -226 return result; -227 } -228 inline int32_t* mem_addr_i32(uint32_t addr) { -229 return reinterpret_cast<int32_t*>(mem_addr_u32(addr)); -230 } -231 // helper for some syscalls. But read-only. -232 inline const char* mem_addr_kernel_string(uint32_t addr) { -233 return reinterpret_cast<const char*>(mem_addr_u8(addr)); -234 } -235 inline string mem_addr_string(uint32_t addr, uint32_t size) { -236 ostringstream out; -237 for (size_t i = 0; i < size; ++i) -238 out << read_mem_u8(addr+i); -239 return out.str(); -240 } -241 +205 raise << "Tried to access uninitialized memory at address 0x" << HEXWORD << addr << '\n' << end(); +206 exit(1); +207 } +208 return result; +209 } +210 inline int8_t* mem_addr_i8(uint32_t addr) { +211 return reinterpret_cast<int8_t*>(mem_addr_u8(addr)); +212 } +213 inline uint32_t* mem_addr_u32(uint32_t addr) { +214 uint32_t* result = NULL; +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(); +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 -243 inline void write_mem_u8(uint32_t addr, uint8_t val) { -244 uint8_t* handle = mem_addr_u8(addr); -245 if (handle != NULL) *handle = val; -246 } -247 inline void write_mem_i8(uint32_t addr, int8_t val) { -248 int8_t* handle = mem_addr_i8(addr); -249 if (handle != NULL) *handle = val; -250 } -251 inline void write_mem_u32(uint32_t addr, uint32_t val) { -252 uint32_t* handle = mem_addr_u32(addr); -253 if (handle != NULL) *handle = val; -254 } -255 inline void write_mem_i32(uint32_t addr, int32_t val) { -256 int32_t* handle = mem_addr_i32(addr); -257 if (handle != NULL) *handle = val; -258 } -259 -260 inline bool already_allocated(uint32_t addr) { -261 bool result = false; -262 for (int i = 0; i < SIZE(Mem); ++i) { -263 if (Mem.at(i).match(addr)) { -264 if (result) -265 raise << "address 0x" << HEXWORD << addr << " is in two segments\n" << end(); -266 result = true; -267 } -268 } -269 return result; -270 } -271 -272 //:: core interpreter loop -273 -274 :(code) -275 // skeleton of how x86 instructions are decoded -276 void run_one_instruction() { -277 uint8_t op=0, op2=0, op3=0; -278 // Run One Instruction -279 if (Trace_file) { -280 dump_registers(); -281 // End Dump Info for Instruction -282 } -283 uint32_t inst_start_address = EIP; -284 op = next(); -285 trace(Callstack_depth+1, "run") << "0x" << HEXWORD << inst_start_address << " opcode: " << HEXBYTE << NUM(op) << end(); -286 switch (op) { -287 case 0xf4: // hlt -288 EIP = End_of_program; -289 break; -290 // End Single-Byte Opcodes -291 case 0x0f: -292 switch(op2 = next()) { -293 // End Two-Byte Opcodes Starting With 0f -294 default: -295 cerr << "unrecognized second opcode after 0f: " << HEXBYTE << NUM(op2) << '\n'; -296 DUMP(""); +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()) { +301 switch(op2 = next()) { 302 // End Two-Byte Opcodes Starting With f2 303 case 0x0f: -304 switch(op3 = next()) { +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 DUMP(""); -309 exit(1); -310 } -311 break; -312 default: -313 cerr << "unrecognized second opcode after f2: " << HEXBYTE << NUM(op2) << '\n'; -314 DUMP(""); -315 exit(1); -316 } -317 break; -318 case 0xf3: -319 switch(op2 = next()) { -320 // End Two-Byte Opcodes Starting With f3 -321 case 0x0f: -322 switch(op3 = next()) { -323 // End Three-Byte Opcodes Starting With f3 0f -324 default: -325 cerr << "unrecognized third opcode after f3 0f: " << HEXBYTE << NUM(op3) << '\n'; -326 DUMP(""); -327 exit(1); -328 } -329 break; -330 default: -331 cerr << "unrecognized second opcode after f3: " << HEXBYTE << NUM(op2) << '\n'; -332 DUMP(""); -333 exit(1); -334 } -335 break; -336 default: -337 cerr << "unrecognized opcode: " << HEXBYTE << NUM(op) << '\n'; -338 DUMP(""); -339 exit(1); -340 } -341 } -342 -343 inline uint8_t next() { -344 return read_mem_u8(EIP++); -345 } -346 -347 void dump_registers() { -348 ostringstream out; -349 out << "registers before: "; -350 for (int i = 0; i < NUM_INT_REGISTERS; ++i) { -351 if (i > 0) out << "; "; -352 out << " " << i << ": " << std::hex << std::setw(8) << std::setfill('_') << Reg[i].u; -353 } -354 out << " -- SF: " << SF << "; ZF: " << ZF << "; CF: " << CF << "; OF: " << OF; -355 trace(Callstack_depth+1, "run") << out.str() << end(); -356 } -357 -358 //: start tracking supported opcodes -359 :(before "End Globals") -360 map</*op*/string, string> Name; -361 map</*op*/string, string> Name_0f; -362 map</*op*/string, string> Name_f3; -363 map</*op*/string, string> Name_f3_0f; -364 :(before "End One-time Setup") -365 init_op_names(); -366 :(code) -367 void init_op_names() { -368 put(Name, "f4", "halt (hlt)"); -369 // End Initialize Op Names -370 } -371 -372 :(before "End Help Special-cases(key)") -373 if (key == "opcodes") { -374 cerr << "Opcodes currently supported by SubX:\n"; -375 for (map<string, string>::iterator p = Name.begin(); p != Name.end(); ++p) -376 cerr << " " << p->first << ": " << p->second << '\n'; -377 for (map<string, string>::iterator p = Name_0f.begin(); p != Name_0f.end(); ++p) -378 cerr << " 0f " << p->first << ": " << p->second << '\n'; -379 for (map<string, string>::iterator p = Name_f3.begin(); p != Name_f3.end(); ++p) -380 cerr << " f3 " << p->first << ": " << p->second << '\n'; -381 for (map<string, string>::iterator p = Name_f3_0f.begin(); p != Name_f3_0f.end(); ++p) -382 cerr << " f3 0f " << p->first << ": " << p->second << '\n'; -383 cerr << "Run `subx help instructions` for details on words like 'r32' and 'disp8'.\n" -384 "For complete details on these instructions, consult the IA-32 manual (volume 2).\n" -385 "There's various versions of it online, such as https://c9x.me/x86.\n" -386 "The mnemonics in brackets will help you locate each instruction.\n"; -387 return 0; -388 } -389 :(before "End Help Contents") -390 cerr << " opcodes\n"; -391 -392 //: Helpers for managing trace depths -393 //: -394 //: We're going to use trace depths primarily to segment code running at -395 //: different frames of the call stack. This will make it easy for the trace -396 //: browser to collapse over entire calls. -397 //: -398 //: Errors will be at depth 0. -399 //: Warnings will be at depth 1. -400 //: SubX instructions will occupy depth 2 and up to Max_depth, organized by -401 //: stack frames. Each instruction's internal details will be one level deeper -402 //: than its 'main' depth. So 'call' instruction details will be at the same -403 //: depth as the instructions of the function it calls. -404 :(before "End Globals") -405 extern const int Initial_callstack_depth = 2; -406 int Callstack_depth = Initial_callstack_depth; -407 :(before "End Reset") -408 Callstack_depth = Initial_callstack_depth; -409 -410 :(before "End Includes") -411 #include <iomanip> -412 #define HEXBYTE std::hex << std::setw(2) << std::setfill('0') -413 #define HEXWORD std::hex << std::setw(8) << std::setfill('0') -414 // ugly that iostream doesn't print uint8_t as an integer -415 #define NUM(X) static_cast<int>(X) -416 #include <stdint.h> +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> -- cgit 1.4.1-2-gfad0