weisJ / Mima

Run Mima Code from a desktop UI
http://gbi.ira.uka.de/
MIT License
9 stars 0 forks source link

Support for JMS and JIND instructions #31

Open mkiesinger opened 5 years ago

mkiesinger commented 5 years ago

More of a feature request :) Would it be possible to implement the JMS and JIND instructions mentioned in http://ti.ira.uka.de/Visualisierungen/Mima/mima-aufgaben.pdf?

weisJ commented 5 years ago

The JMS instruction is currently implemented as CALL. Although I could not figure out how the processor (in the given examples) knows when to exit the subroutine (as there seems to be missing a return instruction).

Currently the jump mechanism is implemented by a lookup of the jump label in the current environment. This means that for each label only the index inside the AST (abstract syntax tree) and not the line index is stored. I will try my best to support jumping to number address values instead of labels (with the goal of not breaking the scope system) My first approach would be:

Fixing the JMP to allow numerical values as the parameter would yield simple implementations of JMI, JMS and JIND.

Note: without the ability to jump to addresses a JIND instruction would be pretty pointless, as obviously labels can't be stored inside memory.

weisJ commented 5 years ago

How would you like the index to work? A) The index corresponds to the line of the instruction inside the file(if multiple instructions are at the same line choose the first).

B) If the index is n it indicates that the instruction is the n-th instruction in the file.

mkiesinger commented 5 years ago

How would you like the index to work?

What the simulator should do is mimic exactly what the processor does, and when the MiMa starts running, it will execute code beginning from location 0 in RAM. Therefore indexing should be based on RAM locations, not on the lines in the assembly file, and it is also not possible for two instructions to have the same index. A label is basically a name for that location in memory, so it is easier to reference that location within different instructions.

I haven't written an assembler myself yet, but I'd go for a two step approach; first generating a representation of the program and how it should appear in memory, and in a second step simulating the program. Step one can also be divided again, first stripping all comments and empty lines while assigning each instruction its respective memory location, then resolving all the labels.

As for how to implement all the above, maybe have a look at cbdevnets assembler and simulator, I think it is one of the best performing MiMa simulators, but doesn't support MiMa X and doesn't have such a pretty gui ;) . He also does it in this two step approach. [https://github.com/cbdevnet/mima]()

Maybe a small example helps, I'm using cbdevnets assembly syntax:

Lets say we have this assembly program:

JMP    Start          // Jump to program entry point as MiMa will start executing here
TEMP1: DS 2           // Temporary variable, also just a label referring a memory location that is initialized to 2

Start: LDC 0        // Program start Label
       ADD 1        // Doesn't add 1, but 2, because it will add the value that later will be at ram location 1, which is TEMP1 
       STV TEMP1

       LDC End      // Labels should also be usable as constants because they are just fixed ram addresses
       STV TEMP1    // stores the Label in TEMP1
       JIND TEMP1   // Jump to End

End:   HALT

After resolving labels, the program in memory should look something like this and can be simulated:

0: JMP 3        // Jump to start, which is at ram loc 3
1: 2
2: LDC 0        // Start was here
3: ADD 1         
4: STV 1        // TEMP1 is at location 1
5: LDC 9        // End got translated to ram loc 9
6: STV 1
7: JIND 1       // jump to the location that is stored at loc 1
8: HALT

I hope this helps a bit, but I still didn't really understand though why you need the scope system or how it works. The JIND instruction is very important, as it lets the processor calculate jump addresses during runtime, the basic JMP instruction doesn't allow this, as it is given a specific address that needs to be known already at compile time. I wrote a translator a while ago that converts a higher level language to MiMa assembly and will upload it soon. It is using the JIND a lot, and maybe I can modify it in a way to produce code that can be run with your simulator.

Edit: corrected spelling

weisJ commented 5 years ago

The scope system allows multiple usages of the same label in one program, if they are inside different scopes. I'm already in the process of implementing the new instructions, but it still needs some more time. Although I still have some more questions regarding the details of how you would like those new features to behave:

  1. Should one be able to do something like DS 2?
  2. Should the instructions be loaded into the memory and made visible through the memory view? 2.1 If yes, should one be able to make programs that can perform self modification. (If the answer to this is yes as well, I'd need some more details to the specifications of the op code/argument structure)
  3. I can add an 'JMS' alias for the 'CALL' instruction. But the 'RET' instruction is still necessary to return out of a subroutine (How does this work here https://github.com/weisJ/Mima/issues/url ?There doesn't seem to be an corresponding instruction). Would an alias be necessary or can you work around this issue?
mkiesinger commented 5 years ago

Cool, so the scope System is quite nice. I got around that Problem by only generating unique label names, but scopes will make it easier for people to program in assembly, not having to do sth like "loop_1", "loop_2" and so on.

  1. It is not necessary, as it could be replaced by a sequence of instructions, it's more of a convenience thing for assembly programmers:

    * = 100     // All following instructions will be placed at memory locations 100+ 
    Temp: DS 2

    can be translated to a sequence of instructions that initialize Temp at runtime:

    LDC 2
    STV 100     // or just use STV Temp 
  2. It depends how extensive you want to make the simulator and memory view. For the MiMa X I don't think it's even possible, because I haven't seen any definition on how to translate the assembly to machine code, but for MiMa it is. For just simulating the program I don't think it's necessary. You could just split the memory into program and data segments, and only have the memory view show the data segment, or just display the instruction in memory view in assembly.

If you're interested how it's done for the MiMa, check https://github.com/mkiesinger/mimaFPGA#mima-specification

  1. Jump Subroutine is just name, no subroutine or anything is actually called, I guess the author chose that name because it can be used to implement subroutine calls and the return address is saved somewhere. In my opinion that instruction is silly. Usually you'd want program and data segments separated, with the program memory being read only. Allowing self modifying code during execution is just a mess and a security risk. The JMS addr instruction violates this concept, because it stores the return address in a memory location, then continues executing from that location +1. Usually you'd want to save the return address on a stack. The JMS is also not the same as CALL. CALL addr saves the return address in a register, not in a memory location, before jumping to addr.

Function calls can be realized without using the CALL and RETURN instructions from the MiMa X. They are just there to make the call and return processes a bit faster, but the whole process is more than just using those two instructions, they are part of it.

To implement function calls, you have to find a suitable caller-callee agreement. For example, caller pushes arguments on the stack, then return address, then actually executes the jump. The callee saves the register state on the stack, then doing some work, and when finished recreates the old register state, clears arguments and return address from the stack, pushes the return value on the stack and then jumps back to return address. For the caller it looks like the call never happened, and the arguments on the stack have been replaced with the returned value.

Using the MiMa X instructions, maybe check the examples here, skip the math blabla http://gbi.ira.uka.de/vorlesungen/k-22-mima-x-folien.pdf

weisJ commented 5 years ago

Thank you vary much for the clarification. Support for JIND is now added https://github.com/weisJ/Mima/commit/2cfee63b84c5980ed5bdd7079f388975de60cd5e (new binaries follow). In favor of not allowing program modification during runtime the JMS routine I won't add the JMS instruction. (Also because the program isn't stored anywhere in memory at the moment and having it open to changes during execution would need more reworking of the way the Interpreter communicates with the memory.)

Instead there will be a separate tab for viewing the assembly of the current program.

weisJ commented 5 years ago

New binaries with the instruction are available here.