diff options
author | Kartik Agaram <vc@akkartik.com> | 2018-07-20 17:08:55 -0700 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2018-07-20 17:08:55 -0700 |
commit | 0ca791cd8cb84f71da011b3f3827c61126011492 (patch) | |
tree | 8f6b27c56284c267dff5e2c2f6c122fa9bf220eb /subx | |
parent | 3fa78f1c16714cf39e388757a046ed4e010ef2b9 (diff) | |
download | mu-0ca791cd8cb84f71da011b3f3827c61126011492.tar.gz |
4376 - subx: online help includes supported opcodes
Diffstat (limited to 'subx')
-rw-r--r-- | subx/001help.cc | 8 | ||||
-rw-r--r-- | subx/010vm.cc | 12 | ||||
-rw-r--r-- | subx/011parse.cc | 23 | ||||
-rw-r--r-- | subx/012direct_addressing.cc | 47 | ||||
-rw-r--r-- | subx/013indirect_addressing.cc | 27 | ||||
-rw-r--r-- | subx/014immediate_addressing.cc | 34 | ||||
-rw-r--r-- | subx/016jump_relative.cc | 21 | ||||
-rw-r--r-- | subx/017jump_relative.cc | 3 |
8 files changed, 167 insertions, 8 deletions
diff --git a/subx/001help.cc b/subx/001help.cc index e6e0527d..340f7d33 100644 --- a/subx/001help.cc +++ b/subx/001help.cc @@ -15,12 +15,14 @@ if (is_equal(argv[1], "help")) { help_contents(); return 0; } - else if (contains_key(Help, argv[2])) { - cerr << get(Help, argv[2]); + string key(argv[2]); + // End Help Special-cases(key) + if (contains_key(Help, key)) { + cerr << get(Help, key); return 0; } else { - cerr << "No help found for '" << argv[2] << "'\n"; + cerr << "No help found for '" << key << "'\n"; help_contents(); cerr << "Please check your command for typos.\n"; return 1; diff --git a/subx/010vm.cc b/subx/010vm.cc index 67c407a8..9d6d047d 100644 --- a/subx/010vm.cc +++ b/subx/010vm.cc @@ -31,12 +31,14 @@ EIP = 1; // preserve null pointer cerr << " registers\n"; :(before "End Help Texts") put(Help, "registers", - "SubX currently supports 8 integer registers, numbered from 0 to 7.\n" + "SubX currently supports eight 32-bit integer registers: R0 to R7.\n" + "R4 contains the top of the stack.\n" "There's also a register for the address of the currently executing instruction. It is modified by jumps.\n" - "Various instructions modify one or more of 3 flags, as a side-effect:\n" - "- the sign flag: usually set if an arithmetic result is negative, or reset if not.\n" - "- the zero flag: usually set if a result is zero, or reset if not.\n" - "- the overflow flag: usually set if an arithmetic result overflows.\n" + "Various instructions modify one or more of three 1-bit 'flag' registers, as a side-effect:\n" + "- the sign flag (SF): usually set if an arithmetic result is negative, or reset if not.\n" + "- the zero flag (ZF): usually set if a result is zero, or reset if not.\n" + "- the overflow flag (OF): usually set if an arithmetic result overflows.\n" + "The flag bits are read by conditional jumps.\n" "We don't support non-integer (floating-point) registers yet.\n" ); diff --git a/subx/011parse.cc b/subx/011parse.cc index b5914d2c..c6d66ff4 100644 --- a/subx/011parse.cc +++ b/subx/011parse.cc @@ -225,3 +225,26 @@ int32_t imm32() { result |= (next()<<24); return result; } + +//: start tracking supported opcodes +:(before "End Globals") +map</*op*/uint8_t, string> name; +:(before "End One-time Setup") +init_op_names(); +:(code) +void init_op_names() { + put(name, 0xf4, "halt"); + put(name, 0x05, "add imm32 to register R0 (EAX)"); + // End Initialize Op Names(name) +} + +:(before "End Help Special-cases(key)") +if (key == "opcodes") { + cerr << "Opcodes currently supported by SubX:\n"; + for (map<uint8_t, string>::iterator p = name.begin(); p != name.end(); ++p) + cerr << " " << HEXBYTE << NUM(p->first) << ": " << p->second << '\n'; + cerr << "Coming soon: `subx help operands` for details on words like 'r32' and 'disp8'.\n"; + return 0; +} +:(before "End Help Contents") +cerr << " opcodes\n"; diff --git a/subx/012direct_addressing.cc b/subx/012direct_addressing.cc index bdad57ab..61eb3d9d 100644 --- a/subx/012direct_addressing.cc +++ b/subx/012direct_addressing.cc @@ -1,5 +1,8 @@ //: operating directly on a register +:(before "End Initialize Op Names(name)") +put(name, 0x01, "add r32 to rm32"); + :(scenario add_r32_to_r32) % Reg[EAX].i = 0x10; % Reg[EBX].i = 1; @@ -60,6 +63,9 @@ string rname(uint8_t r) { //:: subtract +:(before "End Initialize Op Names(name)") +put(name, 0x29, "subtract r32 from rm32"); + :(scenario subtract_r32_from_r32) % Reg[EAX].i = 10; % Reg[EBX].i = 1; @@ -83,6 +89,9 @@ case 0x29: { // subtract r32 from r/m32 //:: and +:(before "End Initialize Op Names(name)") +put(name, 0x21, "rm32 = bitwise AND of r32 with rm32"); + :(scenario and_r32_with_r32) % Reg[EAX].i = 0x0a0b0c0d; % Reg[EBX].i = 0x000000ff; @@ -106,6 +115,9 @@ case 0x21: { // and r32 with r/m32 //:: or +:(before "End Initialize Op Names(name)") +put(name, 0x09, "rm32 = bitwise OR of r32 with rm32"); + :(scenario or_r32_with_r32) % Reg[EAX].i = 0x0a0b0c0d; % Reg[EBX].i = 0xa0b0c0d0; @@ -129,6 +141,9 @@ case 0x09: { // or r32 with r/m32 //:: xor +:(before "End Initialize Op Names(name)") +put(name, 0x31, "rm32 = bitwise XOR of r32 with rm32"); + :(scenario xor_r32_with_r32) % Reg[EAX].i = 0x0a0b0c0d; % Reg[EBX].i = 0xaabbc0d0; @@ -152,6 +167,9 @@ case 0x31: { // xor r32 with r/m32 //:: not +:(before "End Initialize Op Names(name)") +put(name, 0xf7, "bitwise complement of rm32"); + :(scenario not_r32) % Reg[EBX].i = 0x0f0f00ff; == 0x1 @@ -177,6 +195,9 @@ case 0xf7: { // xor r32 with r/m32 //:: compare (cmp) +:(before "End Initialize Op Names(name)") +put(name, 0x39, "set SF if rm32 < r32"); + :(scenario compare_r32_with_r32_greater) % Reg[EAX].i = 0x0a0b0c0d; % Reg[EBX].i = 0x0a0b0c07; @@ -228,6 +249,9 @@ case 0x39: { // set SF if r/m32 < r32 //:: copy (mov) +:(before "End Initialize Op Names(name)") +put(name, 0x89, "copy r32 to rm32"); + :(scenario copy_r32_to_r32) % Reg[EBX].i = 0xaf; == 0x1 @@ -251,6 +275,9 @@ case 0x89: { // copy r32 to r/m32 //:: xchg +:(before "End Initialize Op Names(name)") +put(name, 0x01, "swap the contents of r32 and rm32"); + :(scenario xchg_r32_with_r32) % Reg[EBX].i = 0xaf; % Reg[EAX].i = 0x2e; @@ -279,6 +306,16 @@ case 0x87: { // exchange r32 with r/m32 //:: push +:(before "End Initialize Op Names(name)") +put(name, 0x50, "push R0 (EAX) to stack"); +put(name, 0x51, "push R1 (ECX) to stack"); +put(name, 0x52, "push R2 (EDX) to stack"); +put(name, 0x53, "push R3 (EBX) to stack"); +put(name, 0x54, "push R4 (ESP) to stack"); +put(name, 0x55, "push R5 (EBP) to stack"); +put(name, 0x56, "push R6 (ESI) to stack"); +put(name, 0x57, "push R7 (EDI) to stack"); + :(scenario push_r32) % Reg[ESP].u = 0x64; % Reg[EBX].i = 0x0000000a; @@ -313,6 +350,16 @@ void push(uint32_t val) { //:: pop +:(before "End Initialize Op Names(name)") +put(name, 0x58, "pop top of stack to R0 (EAX)"); +put(name, 0x59, "pop top of stack to R1 (ECX)"); +put(name, 0x5a, "pop top of stack to R2 (EDX)"); +put(name, 0x5b, "pop top of stack to R3 (EBX)"); +put(name, 0x5c, "pop top of stack to R4 (ESP)"); +put(name, 0x5d, "pop top of stack to R5 (EBP)"); +put(name, 0x5e, "pop top of stack to R6 (ESI)"); +put(name, 0x5f, "pop top of stack to R7 (EDI)"); + :(scenario pop_r32) % Reg[ESP].u = 0x60; % write_mem_i32(0x60, 0x0000000a); diff --git a/subx/013indirect_addressing.cc b/subx/013indirect_addressing.cc index 232b67de..4480e809 100644 --- a/subx/013indirect_addressing.cc +++ b/subx/013indirect_addressing.cc @@ -27,6 +27,9 @@ case 0: // indirect addressing //: +:(before "End Initialize Op Names(name)") +put(name, 0x03, "add rm32 to r32"); + :(scenario add_mem_at_r32_to_r32) % Reg[EAX].i = 0x60; % Reg[EBX].i = 0x10; @@ -67,6 +70,9 @@ case 0x03: { // add r/m32 to r32 //: +:(before "End Initialize Op Names(name)") +put(name, 0x2b, "subtract rm32 from r32"); + :(scenario subtract_mem_at_r32_from_r32) % Reg[EAX].i = 0x60; % Reg[EBX].i = 10; @@ -107,6 +113,9 @@ case 0x2b: { // subtract r/m32 from r32 //: +:(before "End Initialize Op Names(name)") +put(name, 0x23, "r32 = bitwise AND of r32 with rm32"); + :(scenario and_mem_at_r32_with_r32) % Reg[EAX].i = 0x60; % Reg[EBX].i = 0x0a0b0c0d; @@ -147,6 +156,9 @@ case 0x23: { // and r/m32 with r32 //: +:(before "End Initialize Op Names(name)") +put(name, 0x0b, "r32 = bitwise OR of r32 with rm32"); + :(scenario or_mem_at_r32_with_r32) % Reg[EAX].i = 0x60; % Reg[EBX].i = 0xa0b0c0d0; @@ -187,6 +199,9 @@ case 0x0b: { // or r/m32 with r32 //: +:(before "End Initialize Op Names(name)") +put(name, 0x33, "r32 = bitwise XOR of r32 with rm32"); + :(scenario xor_mem_at_r32_with_r32) % Reg[EAX].i = 0x60; % Reg[EBX].i = 0xa0b0c0d0; @@ -267,6 +282,9 @@ ff 00 0f 0f # 0x0f0f00ff //: +:(before "End Initialize Op Names(name)") +put(name, 0x3b, "set SF if rm32 > r32"); + :(scenario compare_r32_with_mem_at_r32_greater) % Reg[EAX].i = 0x60; % Reg[EBX].i = 0x0a0b0c0d; @@ -337,6 +355,9 @@ case 0x3b: { // set SF if r32 < r/m32 //: +:(before "End Initialize Op Names(name)") +put(name, 0x8b, "copy rm32 to r32"); + :(scenario copy_mem_at_r32_to_r32) % Reg[EAX].i = 0x60; == 0x1 # code segment @@ -362,6 +383,9 @@ case 0x8b: { // copy r32 to r/m32 //:: jump +:(before "End Initialize Op Names(name)") +put(name, 0xff, "jump/push/call rm32 depending on subop"); + :(scenario jump_mem_at_r32) % Reg[EAX].i = 0x60; == 0x1 # code segment @@ -422,6 +446,9 @@ case 6: { // push r/m32 to stack //:: pop +:(before "End Initialize Op Names(name)") +put(name, 0x8f, "pop top of stack to rm32"); + :(scenario pop_mem_at_r32) % Reg[EAX].i = 0x60; % Reg[ESP].u = 0x10; diff --git a/subx/014immediate_addressing.cc b/subx/014immediate_addressing.cc index 11e825b8..9a04215f 100644 --- a/subx/014immediate_addressing.cc +++ b/subx/014immediate_addressing.cc @@ -1,5 +1,8 @@ //: instructions that (immediately) contain an argument to act with +:(before "End Initialize Op Names(name)") +put(name, 0x81, "combine rm32 with imm32 based on subop"); + :(scenario add_imm32_to_r32) % Reg[EBX].i = 1; == 0x1 @@ -48,6 +51,9 @@ case 0x81: { // combine imm32 with r/m32 //:: subtract +:(before "End Initialize Op Names(name)") +put(name, 0x2d, "subtract imm32 from R0 (EAX)"); + :(scenario subtract_imm32_from_eax) % Reg[EAX].i = 0x0d0c0baa; == 0x1 @@ -101,6 +107,9 @@ case 5: { //:: and +:(before "End Initialize Op Names(name)") +put(name, 0x25, "R0 = bitwise AND of imm32 with R0 (EAX)"); + :(scenario and_imm32_with_eax) % Reg[EAX].i = 0xff; == 0x1 @@ -154,6 +163,9 @@ case 4: { //:: or +:(before "End Initialize Op Names(name)") +put(name, 0x0d, "R0 = bitwise OR of imm32 with R0 (EAX)"); + :(scenario or_imm32_with_eax) % Reg[EAX].i = 0xd0c0b0a0; == 0x1 @@ -205,6 +217,9 @@ case 1: { //:: xor +:(before "End Initialize Op Names(name)") +put(name, 0x35, "R0 = bitwise XOR of imm32 with R0 (EAX)"); + :(scenario xor_imm32_with_eax) % Reg[EAX].i = 0xddccb0a0; == 0x1 @@ -256,6 +271,9 @@ case 6: { //:: compare (cmp) +:(before "End Initialize Op Names(name)") +put(name, 0x3d, "subtract imm32 from R0 (EAX)"); + :(scenario compare_imm32_with_eax_greater) % Reg[EAX].i = 0x0d0c0b0a; == 0x1 @@ -377,6 +395,16 @@ case 7: { //:: copy (mov) +:(before "End Initialize Op Names(name)") +put(name, 0xb8, "copy imm32 to R0 (EAX)"); +put(name, 0xb9, "copy imm32 to R1 (ECX)"); +put(name, 0xba, "copy imm32 to R2 (EDX)"); +put(name, 0xbb, "copy imm32 to R3 (EBX)"); +put(name, 0xbc, "copy imm32 to R4 (ESP)"); +put(name, 0xbd, "copy imm32 to R5 (EBP)"); +put(name, 0xbe, "copy imm32 to R6 (ESI)"); +put(name, 0xbf, "copy imm32 to R7 (EDI)"); + :(scenario copy_imm32_to_r32) == 0x1 # op ModR/M SIB displacement immediate @@ -401,6 +429,9 @@ case 0xbf: { // copy imm32 to r32 //: +:(before "End Initialize Op Names(name)") +put(name, 0xc7, "copy imm32 to rm32"); + :(scenario copy_imm32_to_mem_at_r32) % Reg[EBX].i = 0x60; == 0x1 @@ -422,6 +453,9 @@ case 0xc7: { // copy imm32 to r32 //:: push +:(before "End Initialize Op Names(name)") +put(name, 0x68, "push imm32 to stack"); + :(scenario push_imm32) % Reg[ESP].u = 0x14; == 0x1 diff --git a/subx/016jump_relative.cc b/subx/016jump_relative.cc index 061a947f..9b411f07 100644 --- a/subx/016jump_relative.cc +++ b/subx/016jump_relative.cc @@ -2,6 +2,9 @@ //:: jump +:(before "End Initialize Op Names(name)") +put(name, 0xeb, "jump disp8 bytes away"); + :(scenario jump_rel8) == 0x1 # op ModR/M SIB displacement immediate @@ -23,6 +26,9 @@ case 0xeb: { // jump rel8 //:: jump if equal/zero +:(before "End Initialize Op Names(name)") +put(name, 0x74, "jump disp8 bytes away if ZF is set"); + :(scenario je_rel8_success) % ZF = true; == 0x1 @@ -59,6 +65,9 @@ case 0x74: { // jump rel8 if ZF //:: jump if not equal/not zero +:(before "End Initialize Op Names(name)") +put(name, 0x75, "jump disp8 bytes away if ZF is not set"); + :(scenario jne_rel8_success) % ZF = false; == 0x1 @@ -95,6 +104,9 @@ case 0x75: { // jump rel8 unless ZF //:: jump if greater +:(before "End Initialize Op Names(name)") +put(name, 0x7f, "jump disp8 bytes away if greater (ZF is unset, SF == OF)"); + :(scenario jg_rel8_success) % ZF = false; % SF = false; @@ -135,6 +147,9 @@ case 0x7f: { // jump rel8 if !SF and !ZF //:: jump if greater or equal +:(before "End Initialize Op Names(name)") +put(name, 0x7d, "jump disp8 bytes away if greater or equal (SF == OF)"); + :(scenario jge_rel8_success) % SF = false; % OF = false; @@ -173,6 +188,9 @@ case 0x7d: { // jump rel8 if !SF //:: jump if lesser +:(before "End Initialize Op Names(name)") +put(name, 0x7c, "jump disp8 bytes away if lesser (SF != OF)"); + :(scenario jl_rel8_success) % ZF = false; % SF = true; @@ -213,6 +231,9 @@ case 0x7c: { // jump rel8 if SF and !ZF //:: jump if lesser or equal +:(before "End Initialize Op Names(name)") +put(name, 0x7e, "jump disp8 bytes away if lesser or equal (ZF is set or SF != OF)"); + :(scenario jle_rel8_equal) % ZF = true; % SF = false; diff --git a/subx/017jump_relative.cc b/subx/017jump_relative.cc index 711a5b6a..d7553df7 100644 --- a/subx/017jump_relative.cc +++ b/subx/017jump_relative.cc @@ -2,6 +2,9 @@ //:: jump +:(before "End Initialize Op Names(name)") +put(name, 0xe9, "jump disp16 bytes away"); + :(scenario jump_rel16) == 0x1 # op ModR/M SIB displacement immediate |