Skip to content

implementation of LCC in JavaScript for educational purposes

Notifications You must be signed in to change notification settings

avidrucker/lccjs

Repository files navigation

LCC.js & LCC+js - An Educational Assembler and Interpreter

Overview

LCC.js is a JavaScript-based assembler and interpreter for a simple 16-bit virtual machine architecture. Inspired by educational projects like the Low-Cost Computer (LCC), it provides a platform for learning assembly language programming and understanding how high-level code translates to machine operations.

Building on LCC.js, LCC+js introduces an extended assembly instruction set and real-time execution features for more interactive, game-oriented applications. This extension adds new instructions (e.g., for non-blocking input, screen manipulation, and timed delays) and separate .ap / .ep file formats, making it possible to write assembly-based terminal games or simulations.

Table of Contents

  1. Features
  2. Getting Started
  3. Usage
  4. Understanding the Components
  5. Testing
  6. Architecture Details
  7. Contributing
  8. License
  9. Contact

Features

  • Educational Focus: Ideal for learning the basics of assembly language and virtual machine architectures.
  • Cross-Platform: Runs anywhere Node.js is available.
  • Modular Design: Separate components for assembling, linking, interpreting, plus extended “plus” modules for advanced use.
  • Real-Time Extensions (LCC+js): Non-blocking input, screen clearing, timed delays, and other game-oriented features.
  • Extensible: Straightforward to add new instructions or behaviors.

Getting Started

Prerequisites

Installation

Clone the repository:

git clone git@github.com:avidrucker/lccjs.git
cd lccjs

Setup aliases on UNIX systems:

chmod u+x alias.sh  
./alias.sh  
source ~/.bashrc

Usage

Assembling and Running Code with lcc.js

For a standard .a assembly file:

node ./src/core/lcc.js path/to/yourfile.a
  • lcc.js automatically detects file type, assembles the source, and interprets the resulting .e executable.

Using assembler.js and interpreter.js Separately

  • Assemble a .a file:

    node ./src/core/assembler.js path/to/yourfile.a

    This generates a .e or .o file (depending on directives) in the same folder.

  • Interpret the produced executable:

    node ./src/core/interpreter.js path/to/yourfile.e

LCC+js Assembly and Execution

For LCC+js features (non-blocking input, screen manipulation, real-time instructions, etc.):

  1. AssemblerPlus processes .ap files, generating .ep executables:
    node ./src/plus/assemblerplus.js path/to/yourfile.ap
  2. InterpreterPlus runs the resulting .ep:
    node ./src/plus/interpreterplus.js path/to/yourfile.ep
  3. LccPlus (combined) for one-step assembly and execution:
    node ./src/plus/lccplus.js path/to/yourfile.ap

These tools introduce extended instructions like clear, sleep, nbain, and more. See Instruction Set (LCC.js & LCC+js) for details.


Understanding the Components

lcc.js

  • Purpose: A high-level command-line tool that orchestrates assembly, linking, and execution.
  • Functionality:
    • Automatically detects file types (.a or .o, etc.).
    • Assembles .a files, interprets .e files.
    • Provides a simple CLI for a one-step workflow.

assembler.js

  • Purpose: Translates .a assembly code into machine code (.e or .o).
  • Key Features:
    • Two-Pass Assembly: Builds symbol table (pass 1) and generates code (pass 2).
    • Symbol Table and Directives: Handles labels, .start, .globl, .word, etc.
    • Error Reporting: Provides errors and warnings if assembly issues occur.

interpreter.js

  • Purpose: Executes .e machine code on a simulated 16-bit virtual machine.
  • Key Features:
    • Registers & Memory: Manages an 8-register set and 65,536 words of memory.
    • Instruction Decoding: Implements the standard LCC.js instruction set (arithmetic, logic, control flow, I/O via TRAP).
    • Execution Cap: Defaults to 500,000 instructions to prevent infinite loops.

linker.js

  • Purpose: Combines multiple object files (.o) into a single executable (.e).
  • Key Features:
    • Symbol Resolution: Merges global and external symbols.
    • Adjusts Addresses: Ensures references and offsets are correct in the final combined output.

assemblerplus.js & interpreterplus.js (LCC+js)

  • Purpose: Extend LCC.js for real-time, interactive applications (games, demos).
  • New Instructions:
    • clear, sleep, nbain, cursor, srand, rand, millis, resetc, etc.
    • Allows partial screen clearing, non-blocking input, timed delays, etc.
  • File Extensions:
    • .apAssemblerPlus.ep
    • .epInterpreterPlus → runs advanced instructions in real time.
  • Non-Blocking Execution: The interpreter uses an event loop for continuous stepping and immediate keystroke handling.

disassembler.js & linkerStepsPrinter.js (Extra)

  • disassembler.js: Takes an .e file and disassembles machine code back to a textual instruction representation—useful for debugging.
  • linkerStepsPrinter.js: Outputs the step-by-step linking process to help visualize how symbols and references are resolved.

Directory Structure

  • core/: Contains primary modules for LCC.js (assembler.js, interpreter.js, etc.).
  • utils/: Utility scripts for generating listings/statistics, name handling, and other shared functionality.
  • plus/: Modules for LCC+js (assemblerplus.js, interpreterplus.js, lccplus.js) adding extended features.
  • test/: Houses all test files—both integration tests and end-to-end (e2e).
  • extra/: Holds additional tools like disassembler.js and linkerStepsPrinter.js.

Testing

Extensive end-to-end (e2e) and integration tests have been implemented for assembler.js, linker.js, interpreter.js, and lcc.js—covering a wide range of functionality. Further edge cases can always be added to improve coverage.

Run all tests:

npm test

Note: If you encounter issues with jest not being found, you may need to install it globally: npm install -g jest.

Run a specific test file:

npx jest test/integration/assembler.integration.test.js

While there are still opportunities for additional test cases (especially unit tests), the current suite provides strong coverage across the main features.


Architecture Details

Registers and Memory

  • Registers: 8 (r0–r7), with special roles for sp (r6), fp (r5), and lr (r7).
  • Memory: 65,536 words (16-bit each).

Instruction Set (LCC.js & LCC+js)

LCC.js includes:

  • Arithmetic: ADD, SUB, MUL, DIV, REM
  • Logical: AND, OR, XOR, NOT
  • Data Movement: MOV, LD, ST, LEA, LDR, STR, PUSH, POP
  • Control Flow: BR (brz, brn, etc.), JMP, JSR, RET, BL, BLR
  • I/O (TRAP): AOUT, DOUT, HOUT, SOUT, AIN, DIN, HIN, SIN, etc.

LCC+js introduces extended instructions (via assemblerplus.js & interpreterplus.js):

  • Non-Blocking Input: nbain
  • Screen Clearing: clear, partial reset with resetc
  • Timed Delay: sleep
  • Cursor Control: cursor (hide/show)
  • Randomness: srand, rand (seed-based random generation)
  • Milliseconds: millis (retrieve current time mod 1000)

Contributing

Areas for Improvement

  1. Debugging Tools: Symbolic debugger or additional introspection features.
  2. More LCC+js Demos: Additional example programs showing real-time features.
  3. Edge-Case Test Coverage: Adding more specialized test scenarios to further solidify reliability.
  4. Performance Optimization: Improving execution speed and memory usage.
  5. Documentation: Continually refining and expanding docs.

How to Contribute

  1. Fork the repository.
  2. Create a branch for your feature or fix.
  3. Submit a Pull Request with a clear explanation of changes.

License

This project is open-source under the MIT License.


Contact

For questions or feedback, please open an issue or submit a pull request.

About

implementation of LCC in JavaScript for educational purposes

Topics

Resources

Stars

Watchers

Forks

Contributors 3

  •  
  •  
  •