lc2.js Documentation

<- Back to the documentation index

Constants

lc2.PAGE_BITS
Type: int. Default: 7. The number of bits in a page index.
lc2.PAGE_LOCS
Type: int. Default: 9. The number of bits in a page offset, which is the index of a memory location within a page.
lc2.REGISTERS
Type: int. Default: 8. The number of registers.
lc2.COND_POS
Type: int. Default: 2. The bit mask to access the P bit.
lc2.COND_ZERO
Type: int. Default: 1. The bit mask to access the Z bit.
lc2.COND_NEG
Type: int. Default: 4. The bit mask to access the N bit.

Attributes

lc2.halted
Type: boolean. Default: false. If true, the machine will not run.
lc2.debug
Type: boolean. Default: false. If true, log debug information to console.
lc2.conds
Type: number. Default: LC2.COND_ZERO (bit 2 set). Bit 0 is set if the previous result was negative. Bit 1 is set if the previous result was positive. Bit 2 is set if the previous result was zero.
lc2.pc
Type: Register. Default: 0. This is the program counter for the LC-2 control unit. This register stores the memory address of the next instruction to be evaluated.
lc2.ir
Type: Register. Default: 0. This is the instruction register for the LC-2 control unit. Once fetched, this register stores the value of the instruction being evaluated.
lc2.mem
Type: MemoryUnit. Controls access to the LC-2 memory. See class description above.
lc2.r
Type: array of 8 Registers, each initialized to 0.

Classes

Register
A 16 bit register.

To assign a value to register 0 on an LC2 instance lc2 evaluate: lc2.r[0].val = 42.

To read a value from the same register evaluate: lc2.r[0].val.

Example:

            var lc2 = new LC2;
            
            lc2.r[0].val = 42;         // set the value of r0 to 42
            
            console.log(lc2.r[0].val); // 42
          

MemoryUnit
Controls access to the LC-2 memory.

To retrieve the value at memory location 3000 from the memory unit of an LC2 instance lc2, first set the memory address register (MAR): lc2.mem.mar = 3000, then interrogate the memory unit: lc2.mem.interrogate(), then read from the memory data register (MDR): lc2.mem.mdr.

To write a value to memory location 3000 on the same memory unit, first set the MAR: lc2.mem.mar = 3000, then set the MDR: lc2.mem.mdr = 42, then interrogate with the write bit set: lc2.mem.interrogate(1).

Example:

            var lc2 = new LC2;
            
            lc2.mem.mar.val = 3000;
            lc2.mem.mdr.val = 8;
            lc2.mem.interrogate(1);       // write 8 to memory location 3000
            
            lc2.mem.mar.val = 3001;
            lc2.mem.mdr.val = 42;
            lc2.mem.interrogate(1);       // write 42 to memory location 3001
            
            lc2.mem.mar.val = 3000;
            lc2.mem.interrogate();
            console.log(lc2.mem.mdr.val); // 8
            
            lc2.mem.mar.val = 3001;
            lc2.mem.interrogate();
            console.log(lc2.mem.mdr.val); // 42
          

To retrieve an entire page, use the lc2.mem.getPage(pageNum) function. This returns Uint16Array copy of the page in memory.

To map memory access to an external function, use lc2.mem.map_memory(addr, fn). When addr is read from, the return value of fn() will be returned. When val is written to addr, fn(val) is called.

To bypass the memory unit and read directly from an address in memory, use lc2.mem.hw_get(addr). To write directly to memory, use lc2.mem.hw_set(addr, val).

Helper Methods

lc2.set_mcr()

Sets bit 15 at the address of MCR, which is 0xffff by default. This bit is set by default when the computer is insantiated, and must be set for the computer to process the next opcode.

lc2.clear_mcr()

Clears bit 15 at the address of MCR, which is 0xffff by default. This has the effect of halting the computer, since no opcodes will be processed after the bit is cleared.

lc2.set_kbsr()

Sets bit 15 at the address of KBSR, which is 0xf400 by default. This bit indicates that there is unread keyboard input in KBDR.

lc2.clear_kbsr()

Clears bit 15 at the address of KBSR.

lc2.set_kbdr(val)

Sets the value of KBDR to val. val should be the ASCII code corresponding to a keyboard button press. This also has the side-effect of setting KBSR, to indicate new keyboard input (as with lc2.set_kbsr() above).

lc2.set_console(fn)

Maps memory accesses to CRTDR to fn. By default, these memory accesses are sent to console.log, but this is quite clunky and should be replaced with something like a textarea.

lc2.load_program(prg, meta)

Load program prg, which is expected to be of the form: { addr0: instr0, addr1: instr1, ... } (the output of lc2.assemble(str) in lc2asm.js). Meta is an optional object with the following keys, all of which are optional:

lc2.run_cycle()

Fetches the memory at address pointed to by lc2.pc.val which is loaded into lc2.ir.val then lc2.pc.val is incremented. The instruction is then decoded and the appropriate method is run on the given operands.

Example:

            var lc2 = new LC2;
            
            // load an instruction into memory
            lc2.mem.mar.val = 3000;
            lc2.mem.mdr.val = parseInt('0001001010100101',2); // add(1,2,1,5)
            lc2.mem.interrogate(1);
            
            // point at the right instruction
            lc2.pc.val = 3000;
            lc2.run_cycle();
            
            console.log(lc2.r[1].val); // 5
            console.log(lc2.conds);    // 2     (positive)
            console.log(lc2.pc.val);   // 3001
          

Opcode Methods

lc2.add(dest_reg,src_reg,imm5_bit,last)

Add the value of the source register src_reg to another value and store the result in the destination register dest_reg.

If the value of imm5_bit is 0, interpret last as the number of a register whose value is to be added to the source register.

If the value of imm5_bit is 1, interpret last as a 5-bit immediate value to be added to the source register.

Example:

            var lc2 = new LC2;
            
            lc2.add(0,0,1,10);             // r0[0]  = r0[0]  + 10     = 10
            lc2.add(0,0,1,10);             // r0[10] = r0[10] + 10     = 20
            lc2.add(1,1,1,11);             // r1[0]  = r1[0]  + 11     = 11
            lc2.add(1,1,1,11);             // r1[11] = r1[11] + 11     = 22
            lc2.add(2,0,0,1);              // r2[0]  = r0[20] + r1[22] = 42
            
            console.log(lc2.r[2].val);     // 42
          

lc2.and(dest_reg,src_reg,imm5_bit,last)

Bitwise AND the value of the source register src_reg with another value and store the result in the destination register dest_reg.

If the value of imm5_bit is 0, interpret last as the number of a register whose value is to be ANDed with the source register.

If the value of imm5_bit is 1, interpret last as a 5-bit immediate value to be ANDed with the source register.

Example:

            var lc2 = new LC2;
            
            lc2.add(0,0,1,5);              // r0[0] = r0[0]  + 5     = 5
            lc2.add(1,1,1,3);              // r3[0] = r3[0]  + 3     = 3
            lc2.and(2,0,0,1);              // r2[0] = r0[5]  & r1[3] = 1
            
            console.log(lc2.r[2].val);     // 1
          

lc2.not(dest_reg,src_reg)

Bitwise NOT the value of the source register src_reg and store the result in the destination register dest_reg.

Example:

            var lc2 = new LC2;
            
            lc2.add(0,0,1,5);          // r0[0] = r0[0]  + 5     = 5
            lc2.not(1,0);              // r1[0] = ~r1[5]         = -6
            
            console.log(lc2.r[1].val); // -6
          

lc2.lea(dest_reg,imm)

Loads the Effective Address (LEA) of bitwise ORing the upper 7 bits of the value of the pc register with the 9 immediate bits of imm and stores the result in the destination register dest_reg.

Example:

            var lc2 = new LC2;
            
            lc2.pc.val = parseInt('4018',16);
            lc2.lea(5,parseInt('1fd',16));
            
            console.log(lc2.r[5].val.toString(16)); // 41fd
          

lc2.ld(dest_reg,dir)

Loads the Direct address (LD) of bitwise ORing the upper 7 bits of the value of the pc register with the 9 bits bits of dir, retrieves the value of the memory at that address and stores the result in the destination register dest_reg.

Example:

            var lc2 = new LC2;
            
            lc2.mem.mar.val = parseInt('31FD',16);
            lc2.mem.mdr.val = 42;
            lc2.mem.interrogate(1);
            
            lc2.pc.val = parseInt('3000',16);
            lc2.ld(5,parseInt('1fd',16));
            
            console.log(lc2.r[5].val); // 42
          

lc2.st(src_reg,dir)

STore (ST) the direct address of bitwise ORing the upper 7 bits of the value of the pc register with the 9 bits bits of dir, retrieves the value of the source register src_reg and stores the result in the memory at the calculated address.

Example:

            var lc2 = new LC2;

            lc2.r[5].val = 42;
            
            lc2.pc.val = parseInt('3000',16);
            lc2.ld(5,parseInt('1fd',16));
            
            lc2.mem.mar.val = parseInt('31FD',16);
            lc2.mem.interrogate();
            
            console.log(lc2.mem.mdr.val); // 42
          

lc2.ldi(dest_reg,indir)

LoaDs the Indirect address (LDI) of bitwise ORing the upper 7 bits of the value of the pc register with the 9 bits bits of indir, retrieves the value of the memory at that address and stores the value of the memory at the resulting address in the destination register dest_reg.

Example:

            var lc2 = new LC2;
            
            lc2.mem.mar.val = parseInt('4BCC',16);
            lc2.mem.mdr.val = parseInt('2110',16);
            lc2.mem.interrogate(1);
            
            lc2.mem.mar.val = parseInt('2110',16);
            lc2.mem.mdr.val = 42;
            lc2.mem.interrogate(1);
            
            lc2.pc.val = parseInt('4A1B',16);
            lc2.ldi(5,parseInt('1cc',16));
            
            console.log(lc2.r[5].val); // 42
          

lc2.sti(src_reg,indir)

STore the Indirect address (LDI) of bitwise ORing the upper 7 bits of the value of the pc register with the 9 bits bits of indir, stores the value of the source register src_reg at the memory address obtained by reading from the memory at the calculated address.

Example:

            var lc2 = new LC2;
            
            lc2.r[3].val = 42;
            lc2.mem.mar.val = parseInt('4BCC',16);
            lc2.mem.mdr.val = parseInt('2110',16);
            lc2.mem.interrogate(1);
            lc2.mem.mdr.val = 0;
            lc2.mem.interrogate();
            
            lc2.pc.val = parseInt('4A1B',16);
            lc2.sti(3,parseInt('1CC',16));
            lc2.mem.mar.val = parseInt('2110',16);
            lc2.mem.interrogate();
            console.log(lc2.mem.mdr.val); // 42
          

lc2.ldr(dest_reg,base_reg,offset)

LoaDs the base Register (LDR) plus offset. Add the value of the register with number base_reg to the literal value of the 6 bits of offset, which gives a memory location whose value is loaded into dest_reg.

Example:

            var lc2 = new LC2;

            lc2.r[2].val = parseInt('2345',16);
            lc2.mem.mar.val = parseInt('2362',16);
            lc2.mem.mdr.val = 42;
            lc2.mem.interrogate(1);

            lc2.ldr(1,2,parseInt('1D',16));
            console.log(lc2.r[1].val); // 42
          

lc2.str(src_reg,base_reg,offset)

STores the base Register (LDR) plus offset. Add the value of the register with number base_reg to the literal value of the 6 bits of offset, which gives a memory location whose value is set to the value of src_reg.

Example:

            var lc2 = new LC2;

            lc2.r[1].val = 42;
            lc2.r[2].val = parseInt('2345',16);
            lc2.str(1,2,parseInt('1D',16));
            lc2.mem.mar.val = parseInt('2362',16);
            lc2.mem.interrogate();
            console.log(lc2.mem.mdr.val); // 42
          

lc2.br(n,z,p,offset)

BRanch (BR) based on the conditional values. If bit n is set, inspect the N conditional bit. If bit z is set, inspect the Z conditional bit. If bit p is set, inspect the P conditional bit. If any of the inspected bits are set, set the value of the PC register to the result of bitwise ORing the upper 7 bits of the instruction address with the 9 bits of the offset parameter.

Example:

            var lc2 = new LC2;

            lc2.conds = LC2.COND_POS;
            
            lc2.pc.val = parseInt('3000',16);
            lc2.br(1,1,0,5);
            console.log(lc2.pc.val.toString(16)); // 3001

            lc2.pc.val = parseInt('3000',16);
            lc2.br(0,0,1,100);
            console.log(lc2.pc.val.toString(16)); // 3005
          

lc2.trap(vector)

Runs operating system code identified by vector. Under the hood, this simply saves the value of the PC register to register 7, then sets the PC to the value stored at vector.

Example:

            var lc2 = new LC2;
            lc2.mem.mar.val = parseInt('25',16);
            lc2.mem.mdr.val = parseInt('4000',16);
            lc2.mem.interrogate(1);
            
            lc2.trap(parseInt('25',16));
            console.log(lc2.pc.val.toString(16)); // 4000
          

lc2.ret()

RETurns (RET) to regular program execution after a long jump like trap. Under the hood, this sets the value of the PC register to the value of register 7.

Example:

            var lc2 = new LC2;
            
            lc2.r[7].val = parseInt('3000',16);
            lc2.ret();
            console.log(lc2.pc.val.toString(16)); // 3000
          

lc2.jsr(l,offset)

Jump and Save Register (JSR). Jump to the specified offset within the same page. If the l bit is set, save the PC register to register 7 for later return.

Example:

            var lc2 = new LC2;
            
            lc2.r[7].val = 42;
            lc2.pc.val = parseInt('3000',16);
            lc2.jsr(0, 5);
            console.log(lc2.pc.val.toString(16)); // 3005
            console.log(lc2.r[7].val);            // 42
          

lc2.jsrr(l,base_reg,offset)

Jump and Save Register to Register (JSRR). Jump to the memory location obtained by adding the value of register base_reg to the value of offset. If the l bit is set, save the PC register to register 7 for later return.

Example:

            var lc2 = new LC2;
            
            lc2.r[7].val = 42;
            lc2.r[5].val = parseInt('5000',16);
            lc2.pc.val = parseInt('3000',16);
            lc2.jsrr(1,5,parseInt('3F',16));
            console.log(lc2.pc.val.toString(16));   // 503f
            console.log(lc2.r[7].val.toString(16)); // 3000
          

lc2.rti()

ReTurns Indirectly (RTI) to regular program execution after a jump that saves the PC register to memory at the address specified by the value of register 7.

Example:

            var lc2 = new LC2;
            
            lc2.r[7].val = parseInt('5000',16);
            lc2.mem.mar.val = parseInt('5000',16);
            lc2.mem.mdr.val = 42;
            lc2.mem.interrogate(1);
            lc2.rti();
            console.log(lc2.pc.val); // 42