Little Man Computer - Simulator Applet

If you’re nerdy like me, you might be into low level programming, which means fiddling with instructions. Unfortunately, the complexity easily spirals out of control, hence developing in a simple instruction-set is a great way to learn how a CPU works, and being able to write tiny applications that get things done.

An excellent example of such a language is Little-Man-Computer. It features a CPU with 1 register, 1 input, 1 output, 1 flag and 100 memory slots. It is minimalistic to the point that it lacks instructions for multiplication and division.

Specification of the instruction set:

[tr][td]1xx[/td][td]ADD xx[/td][td]ADD[/td][td]Add the value stored in mailbox xx to whatever value is currently on the accumulator.[/td][/tr]
[tr][td]2xx[/td][td]SUB xx[/td][td]SUBTRACT[/td][td]Subtract the value stored in mailbox xx from whatever value is currently on the accumulator.[/td][/tr]
[tr][td]3xx[/td][td]STA xx[/td][td]STORE[/td][td]Store the contents of the accumulator in mailbox xx.[/td][/tr]
[tr][td]5xx[/td][td]LDA xx[/td][td]LOAD[/td][td]Load the value from mailbox xx and enter it in the accumulator.[/td][/tr]
[tr][td]6xx[/td][td]BRA xx[/td][td]BRANCH (unconditional)[/td][td]Set the program counter to the given address (value xx).[/td][/tr]
[tr][td]7xx[/td][td]BRZ xx[/td][td]BRANCH IF ZERO (conditional)[/td][td]If the accumulator contains the value 0, set the program counter to the value xx.[/td][/tr]
[tr][td]8xx[/td][td]BRP xx[/td][td]BRANCH IF POSITIVE (conditional)[/td][td]If the accumulator is 0 or positive, set the program counter to the value xx.[/td][/tr]
[tr][td]901[/td][td]INP[/td][td]INPUT[/td][td]Go to the INBOX, fetch the value from the user, and put it in the accumulator[/td][/tr]
[tr][td]902[/td][td]OUT[/td][td]OUTPUT[/td][td]Copy the value from the accumulator to the OUTBOX.[/td][/tr]
[tr][td]000[/td][td]HLT[/td][td]HALT[/td][td]Stop working.[/td][/tr]
[tr][td]xxx[/td][td]n/a[/td][td]DATA[/td][td]Instruction which simply loads the value into the next available mailbox.[/td][/tr]

Simple program: (adds 13 and 14)
[tr][td]address[/td][td]instr[/td][td]code[/td][td]description[/td][/tr][tr][td]#0[/td][td]104[/td][td]ADD 4[/td][td]add value of address #4 to register[/td][/tr][tr][td]#1[/td][td]105[/td][td]ADD 5[/td][td]add value of address #5 to register[/td][/tr][tr][td]#2[/td][td]902[/td][td]OUT[/td][td]write register to output[/td][/tr][tr][td]#3[/td][td]0[/td][td]HLT[/td][td]halt execution of program[/td][/tr][tr][td]#4[/td][td]13[/td][td]DATA: 13[/td][td]store the value 13[/td][/tr][tr][td]#5[/td][td]14[/td][td]DATA: 14[/td][td]store the value 14[/td][/tr]

Obviously you can make (conditional) jumps, which allows you to make loops.

I created an applet which simulates this CPU, for you guys to play around. It really gets fun, once you get the hang of it.

[applet archive=lmc_ui.jar class=eden.emulator.lmc.LmcApplet width=512 height=256]

First thing you can do is trying to read two numbers from INPUT, subtract them, and write them to the OUTPUT. Next you can write code that is able to multiply two numbers. Maybe you feel naughty and try to raise N to the power of M. You’ll need to use self-modifying code, seriously.

Weird…

It’s 2am nearly here so I’m not going to try it yet but I love the new applet stuff in JGO :slight_smile:

Cas :slight_smile:

I see potential of great competitions.

When I fix the copy/paste functionality of the JTextArea… we can actually share code :persecutioncomplex:

Seems like this is caused by the sandbox: you cannot copy & paste to/from the app. :o Is this new behaviour?

Edit: Right… copy/paste is deemed a security threat since 6u24 :-X

Yeah…


http://blogs.oracle.com/kyle/entry/copy_and_paste_in_java

It’s weird.
And stupid I might add.

So how long have we been able to embed applets in the forum? Is it a ninja feature?

Developing it now… the only thing that’s missing is a safe way to upload the JARs.

Back ontopic:

I added syntax highlighting and highlighted the line of code currently executed, which is very convenient when developing stuff.


http://www.java-gaming.org/user-generated-content/members/12098/lmc_codedump.png

This is the code that calculates N to the power of 1,2,3,4,5,… etc (until it reaches 999, which is the maximum value of a memory cell).

You can see how you can define labels (multiply:) and use labels (:multiply)

INP // fetch 'base' value from user
STA :base
init: LDA :base
STA :countdown

multiply: LDA 91 // :base = @90, 91 is next
ADD 90
BRP :nxt // did we overflow ?
LDA :zero 
STA 91 // fill last addess with zero
HLT
nxt: STA 91
LDA :countdown // subtract one from countdown
SUB :one
STA :countdown
BRZ :display // reached zero in 'countdown'
BRA :multiply // back

display: LDA 91
OUT
BRA :selfmod

selfmod: LDA 4 // advance LDA & STA instructions
ADD :one
STA 4
LDA 5
ADD :one
STA 5
LDA 8
ADD :one
STA 8
LDA 10
ADD :one
STA 10
LDA 16 // for display
ADD :one
STA 16
BRA :init

stop: HLT

@90 base: 0
one: 1
end: 0
countdown: 0
zero: 0

Ok I am in need of some explanations:

  1. What is a register?
  2. What do you mean by input, output and flag?

registers are a type of memory location inside the processor.
You typically only interact or learn about them when doing assembly programming and whatnot.

common assembly code would be like
add $s0, $t0, $t1 # this would be equivalent to s0=t0+t1
the 3 variables shown are all registers
But in this case there are 3 registers instead of 1

It essentially will go from hard drive to memory(ram) to cpu’s registers(cpu’s memory) and then often times back and forth between cpu’s memory and ram’s memory quite a bit in a typical application.

I also, if I am not mistaken, the input/outputs are simply input from user, and output to user.

I am really fuzzy on all of it though, so I am sorry Riven if I explained incorrectly.

His program is in my opinion/mind is a very basic processor emulator in a low level (high level being C/C++/Java/etc…). One of the classes in computer science in college, sometimes called computer organization you learn about assembly or MIPs and get to design a basic CPU from the ground up. lots of binary/hex/registery/ and pain in the ass assembly code.

This all sounds really really really really fun! I’m gonna be playing around with this for hours on end.

@Riven
Could you please post the source code of your Little Man Computer applet?

This is what I (should) learn in college, thanks :smiley:

In the LMC spec, the input/output is poorly specified (I assume it is asynchronous), so if something is outputed twice, and you don’t read the OUTPUT values (externally) fast enough, you’ll lose data, and if you change the data in INPUT before the CPU has read them, they are lost too.

To keep it maintainable, I made both INPUT and OUTPUT blocking, with a modal dialog.


public class Lmc
{
   public static final int HLT                  = 0;
   public static final int ADD                  = 1;
   public static final int SUB                  = 2;
   public static final int STA                  = 3;
   public static final int LDA                  = 5;
   public static final int BRA                  = 6;
   public static final int BRZ                  = 7;
   public static final int BRP                  = 8;
   public static final int UIO                  = 9;

   private int             program_counter      = 0;
   private int             execute_counter      = 0;
   private int             last_reference       = 0;
   private int             last_program_counter = 0;
   private int[]           memory               = new int[100];
   private int             boxInput             = 0;
   private int             boxOutput            = 0;
   private int             register;
   private boolean         overflowFlag         = false;

   public Lmc()
   {
      this.init();
   }

   public void load(int[] memory)
   {
      if (memory.length != this.memory.length)
      {
         throw new IllegalStateException("expected " + this.memory.length + " memory values");
      }

      for (int i = 0; i < memory.length; i++)
      {
         if (memory[i] < 0 || memory[i] > 999)
            throw new IllegalStateException("illegal memory value @" + i + ": " + memory[i]);
         this.memory[i] = memory[i];
      }

      this.init();
   }

   public void init()
   {
      this.reset();
      this.execute_counter = 0;
   }

   public void reset()
   {
      this.boxInput = 0;
      this.boxOutput = 0;
      this.register = 0;
      this.overflowFlag = false;
      this.program_counter = 0;
      this.last_program_counter = -1;
      this.last_reference = -1;
   }

   public int getInstructionPointer()
   {
      return this.program_counter;
   }

   public int getLastInstructionPointer()
   {
      return this.last_program_counter;
   }

   public int getLastReference()
   {
      return this.last_reference;
   }

   public boolean getOverflowFlag()
   {
      return this.overflowFlag;
   }

   public int readInbox()
   {
      return this.boxInput;
   }

   public int readOutbox()
   {
      return this.boxOutput;
   }

   public int readRegister()
   {
      return this.register;
   }

   public int readMemory(int address)
   {
      return this.memory[address];
   }

   public int execute(EmulatorFeedback feedback) throws EmulatorCrash
   {
      // fetch instruction
      int data = this.memory[this.program_counter];
      
      this.last_program_counter = program_counter;

      // advance program counter
      this.program_counter += 1;
      this.execute_counter += 1;

      // decode instruction
      int instruction = data / 100;
      int arg = data % 100;
      this.last_reference = arg;

      switch (instruction)
      {
         case HLT:
            this.last_reference = -1;
            if (arg != 0)
            {
               feedback.invalidInstruction();
               throw new EmulatorCrash();
            }
            this.reset();
            feedback.halt();
            break;

         case ADD:
            int doAdd = this.memory[checkAddress(arg, feedback)];
            this.register = normalizeRegister(register + doAdd);
            break;

         case SUB:
            int doSub = this.memory[checkAddress(arg, feedback)];
            this.register = normalizeRegister(register - doSub);
            break;

         case LDA:
            this.register = this.memory[checkAddress(arg, feedback)];
            break;

         case STA:
            this.memory[checkAddress(arg, feedback)] = this.register;
            break;

         case BRA:
            this.program_counter = checkAddress(arg, feedback);
            break;

         case BRZ:
            if (this.register == 0)
               this.program_counter = checkAddress(arg, feedback);
            break;

         case BRP:
            if (!this.overflowFlag)
               this.program_counter = checkAddress(arg, feedback);
            break;

         case UIO:
            this.last_reference = -1;
            switch (arg)
            {
               case 1:
                  this.boxInput = feedback.input();
                  this.register = this.normalizeRegister(this.boxInput);
                  break;

               case 2:
                  this.boxOutput = this.register;
                  feedback.output(this.boxOutput);
                  break;

               default:
                  feedback.invalidInstruction();
                  throw new EmulatorCrash();
            }
            break;

         default:
            break;
      }

      return data;
   }

   private int normalizeRegister(int value)
   {
      final int max = 1000;

      this.overflowFlag = (value < 0 || value >= max);

      return ((value % max) + max) % max; // ensure value between 0 and 999
   }

   private static int checkAddress(int addr, EmulatorFeedback feedback) throws EmulatorCrash
   {
      if (addr < 0 || addr >= 100)
      {
         feedback.invalidAddress(addr);
         throw new EmulatorCrash();
      }
      return addr;
   }
}

Oh it’s in pure Java? Then why did you need to sign it?

To enable copy & paste >:(

Stupid Oracle >:(

Note: You can’t copy/paste from Flash apps either so this is not just Java. I don’t get it, what’s “not secure” about simple text?

Very interesting. I have a little naughty idea in my mind right now~ 8)
Do you want to release it as full open-source?