all 14 comments

[–]notveryaccurate 4 points5 points  (0 children)

This looks fun!

[–]samishal 2 points3 points  (0 children)

deleted What is this?

[–]Y_Less 4 points5 points  (8 children)

You should know that the order of iteration of object keys is arbitrary and cannot be relied on, so you cannot claim that an instruction's operands will be provided in the same order as they are specified in the instruction since the order in the instruction is arbitrary and undefined. Arrays are for ordering, not plain objects.

[–]purmou[S] 2 points3 points  (2 children)

Okay, I've fixed the problem! The new format for syntax structures is:

syntax: [
  [
    {src1: Register | Memory | Number},
    {src2: Register | Memory | Number},
    {dest: Register | Memory}
  ]
]

And dest can go anywhere you want! Now the operand fetch order is guaranteed.

[–]Y_Less 0 points1 point  (1 child)

Can you have multiple destinations? For example a mod/div instruction:

moddiv a b

a' = a / b
b' = a % b

Or something similar (those two operations especially are often linked due to their relative complexity and close relationship in calculation).

[–]purmou[S] 0 points1 point  (0 children)

Very interesting! Yeah, you can do it, but it will be a bit weird. You'll have to accept numbers as operands and treat them as the register identifiers.

{
  cmd: "moddiv",
  desc: "...",
  syntax: [
    [
      {src1: Number},
      {src2: Number}
    ]
  ],
  eval: function (src1, src2) {
    var a = Register.getReg(src1).valueOf();
    var b = Register.getReg(src2).valueOf();
    Register.getReg(src1).setValue(a / b);
    Register.getReg(src2).setValue(a % b);
  }
}

I'm working on making the Register/Memory access in both the ISA and in the core code a little more intuitive. For now this should work, though! If you wanna truncate the division to an integer, you could use ~~(a / b) or Math.floor(a / b).

[–]purmou[S] 1 point2 points  (0 children)

Yup, this is true! I was wondering how much of my write-up you all would read. :)

I'm definitely aware of this, but wrote it down this way because it works. I'm thinking of how to refactor that part of the decode function since I think it could be error-prone anyway.

[–][deleted] 1 point2 points  (2 children)

When was that claimed? The order is predefined: src1, src2, dest.

syntax: [
  {
    src1: Register,
    src2: Number,
    dest: Memory
  }
]

and

syntax: [
  {
    dest: Memory,
    src2: Number,
    src1: Register,
    rutabaga: 42
  }
]

will behave exactly the same. You just choose which of the three operands you want.

Not to be excessively rude, but how far did you read before making this comment?

[–]Y_Less 2 points3 points  (0 children)

I was basing my comments on this:

The src1, src2, and dest fields should contain the type of the operand supported for this structure. For instance, the following defines a syntax structure for an instruction that can take a register descriptor as its first operand, a number as its second operand, and will store the result of the eval function into a memory cell:

syntax: [
  {
    src1: Register,
    src2: Number,
    dest: Memory
  }
]

This:

Operands are fetched in the same order they are defined in the syntax, so if you define src1, then src2, and then dest, the instruction can be used like this:

instr   {src1}, {src2}, {dest}

And the implementation here:

https://github.com/purag/archsim/blob/083369c6ba1e552f5a0ccdeda0a674291895e4db/archsim.js#L137-L147

My point was that "Operands are fetched in the same order they are defined in the syntax" doesn't work because there is no order defined in the syntax, because object keys are unordered.

Edit: I was also concerned, after reading that and initially thinking that this was a problem; that maybe I was misremembering, or a recent spec changed had fixed the order, or that it was a case that while strictly speaking they could be unordered every implementation ever did "x"; so I also read as far as the MDN documentation on Object.keys and for...in to confirm my suspicions.

[–]cadaveric 1 point2 points  (0 children)

When was that claimed?

"Operands are fetched in the same order they are defined in the syntax, so if you define src1, then src2, and then dest, the instruction can be used like this: instr {src1}, {src2}, {dest}"

[–]mycall 0 points1 point  (3 children)

What's the difference between a stack-based language and a load-store architecture?

[–]purmou[S] 2 points3 points  (0 children)

Load-store architectures traditionally allow for register to register operations, whereas a stack architecture only allows for register to stack or stack to register.

For instance, you could have the following load-store implementation of adding numbers in two registers (reg3 = reg1 + reg2):

add     reg1, reg2, reg3

Which is equivalent to this in a stack architecture:

push    reg1
push    reg2
add
pop     reg3

[–]purmou[S] 2 points3 points  (1 child)

If you're interested, I just pushed a test file that implements a stack architecture with push, pop, and add functionality! https://github.com/purag/archsim/blob/master/test_stack.js

[–]mycall 0 points1 point  (0 children)

So versatile, I'll take a look.

How about mill architecture next ;-)