FRISCjs user interfaces (the browser Web app and NodeJs console app) are built as a layer on top of two generic, pure-JavaScript libraries. This document describes the API of these two libraries: the FRISC assembler and the FRISC simulator. Using this API, other user interfaces may be built for any platform supporting JavaScript.
In node, install using npm:
npm install friscjs
and then access the assembler and simulator:
var friscjs = require("friscjs");
var asm = friscjs.assembler;
var sim = friscjs.simulator;
In a browser, link to the browser script that contains both the assembler and simulator:
<script src="lib/friscjs-browser.js"></script>
and then access the assembler and simulator:
var asm = friscjs.assembler;
var sim = friscjs.simulator;
The assembler used for assembling FRISC source code using the parse()
method:
var result = asm.parse(frisc_code_string);
where frisc_code_string
is a single string containing FRISC code.
E.g.:
lab1 ADD R1, R2, R3
lab2 ADD r2, 5, r5
The result of invoking parse()
is a result
object containing two properties: result.mem
and result.ast
.
result.ast
is the parser AST output and should be used for debugging purposes only.
It is an array of parse objects, one for each instruction in the source code.
E.g.:
[ { op: 'ADD',
optype: 'aluop',
alusrc1: { type: 'reg', value: [ 'R', '1' ] },
alusrc2: { type: 'reg', value: [ 'R', '2' ] },
aludest: { type: 'reg', value: [ 'R', '3' ] },
curloc: 0,
line: 2,
machineCode: '00100000000000000000000000000000' },
{ op: 'ADD',
optype: 'aluop',
alusrc1: { type: 'reg', value: [ 'r', '2' ] },
alusrc2: { type: 'num', value: 5 },
aludest: { type: 'reg', value: [ 'r', '5' ] },
curloc: 4,
line: 3,
machineCode: '00100100000000000000000000000101' },
]
result.mem
is the binary code of the assembled program, which should be loaded into the FRISC simulator.
The binary code is an array of 8-character strings, each string representing the binary value to be stored in FRISC memory at that location.
E.g.:
[ '00000000', '00000000', '00000000', '00100000', '00000101', '00000000', '00000000', '00100100' ]
In case of parsing errors, the parse()
method will throw an exception which contains line
and column
properties which denote the line and column at which the parsing error occured:
try {
var result = asm.parse(frisc_code_string);
} catch (e) {
console.log("Parsing error on line " + e.line + " column " + e.column + " -- " + e.toString());
}
The simulator is a constructor for instantiating FRISCjs simulator objects:
var simulator = new sim();
A simulator instance object exposes two FRISC components: FRISC memory (simulator.MEM
) and FRISC cpu (simulator.MEM
).
The FRISC memory component exposes the following data properties and functions:
MEM._size
- the size of the memory defined as the number of 1-byte locations. By default, the memory has 256*1024 locations, or 256K.MEM._memory
- the memory array itself, containing integers representing bytes at specific locations.
MEM.reset()
- helper function that sets the value of each memory location to 0.
MEM.loadByteString(program)
, MEM.loadBytes(program)
, MEM.loadBinaryString(program)
- helper functions for loading binary FRISC code into memory. loadBinaryString
should be used to load the result of the FRISC assember into the memory:
simulator.MEM.loadBinaryString(result.mem);
MEM.readb(addr)
, MEM.readw(addr)
, MEM.read(addr)
- helper functions for reading a 1B, 2B or 4B integer value from locations starting from addr.
MEM.writeb(addr, val)
, MEM.writeb(addr, val)
, MEM.write(addr, val)
- helper functions for writing a 1B, 2B or 4B integer value val to locations starting from addr.The FRISC cpu component exposes the following data properties and functions:
CPU._r
- a map of the registers of the FRISC cpu: {r0:0, r1:0, r2:0, r3:0, r4:0, r5:0, r6:0, r7:0, pc:0, sr:0, iif:1}
CPU._frequency
- an integer defining the frequency of the cpu in Hz, by default 1 (Hz).
CPU.run()
- starts or resumes the cpu, periodically calling CPU.performCylce
CPU.pause()
- pauses cpu executionCPU.stop()
- stops cpu executionCPU.performCycle()
- executes one FRISC instruction pointed to by the program counterCPU.reset()
- resets the state of the cpu, setting register values to 0 and iif to 1CPU._decode(instruction)
- decodes a FRISC instruction (passed as an integer) and returns the instruction’s operation name and parametersThe FRISC cpu component also invokes the following event handlers, if they are specified:
CPU.onStop()
- invoked after the CPU.stop()
method was calledCPU.onBeforeRun()
- invoked after the CPU.run()
method was calledCPU.onBeforeCycle()
- invoked at the start of every invocation of CPU.performCycle()
CPU.onBeforeExecute(instruction)
- invoked during every invocation of CPU.performCycle()
, after the instruction to be executed was decoded, but before its executionCPU.onAfterCycle()
- invoked at the end of every invocation of CPU.performCylce()
Here is an example of setting an event handler that outputs the FRISC cpu register state after the cpu was stopped:
simulator.CPU.onStop = function() {
console.log("FRISC processor stopped!");
console.log("STATUS of registers:", simulator.CPU._r);
};