From 3f3125ef43da09cd7e99c9cae0b90d0da943ce77 Mon Sep 17 00:00:00 2001 From: Asraelite Date: Fri, 17 May 2024 18:37:51 +0200 Subject: [PATCH] Add compiler --- .gitignore | 2 + .vscode/settings.json | 3 + assembler/index.html | 5 +- assembler/main.ts | 5 +- assembler/targets/bitzzy.ts | 792 +++++++++++++++++++++++++++ assembler/targets/parva_0_1.ts | 6 + assembler/util.ts | 11 +- compiler/Cargo.toml | 9 + compiler/examples/calculator_1.parva | 96 ++++ compiler/examples/test.parva | 6 + compiler/rustfmt.toml | 1 + compiler/src/compiler.rs | 137 +++++ compiler/src/compiler/assemble.rs | 11 + compiler/src/lexer.rs | 186 +++++++ compiler/src/main.rs | 71 +++ compiler/src/parser.rs | 378 +++++++++++++ compiler/src/parser/asm.rs | 20 + doc/lbp/general_tips.md | 7 + doc/lbp/logic_research.md | 63 +++ doc/other/bittzy.png | Bin 0 -> 73317 bytes doc/other/blizzy_opcodes.png | Bin 0 -> 72355 bytes doc/other/mazzetip_cpu | 0 doc/parva/assembly_0.2.md | 164 ++++++ doc/parva/design.md | 23 + doc/parva/ideas.md | 63 +++ programs/bitzzy/assembler_test | 184 +++++++ programs/parva_0.2/cat.parvalang | 61 +++ programs/parva_0.2/file.parva | 3 + programs/parva_0.2/simd_ideas.parva | 87 +++ programs/parva_0.2/split_args | 45 ++ programs/parva_0.2/tetris.parva | 189 +++++++ 31 files changed, 2625 insertions(+), 3 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 assembler/targets/bitzzy.ts create mode 100644 compiler/Cargo.toml create mode 100644 compiler/examples/calculator_1.parva create mode 100644 compiler/examples/test.parva create mode 100644 compiler/rustfmt.toml create mode 100644 compiler/src/compiler.rs create mode 100644 compiler/src/compiler/assemble.rs create mode 100644 compiler/src/lexer.rs create mode 100644 compiler/src/main.rs create mode 100644 compiler/src/parser.rs create mode 100644 compiler/src/parser/asm.rs create mode 100644 doc/lbp/general_tips.md create mode 100644 doc/lbp/logic_research.md create mode 100644 doc/other/bittzy.png create mode 100644 doc/other/blizzy_opcodes.png create mode 100644 doc/other/mazzetip_cpu create mode 100644 doc/parva/assembly_0.2.md create mode 100644 doc/parva/design.md create mode 100644 doc/parva/ideas.md create mode 100644 programs/bitzzy/assembler_test create mode 100644 programs/parva_0.2/cat.parvalang create mode 100644 programs/parva_0.2/file.parva create mode 100644 programs/parva_0.2/simd_ideas.parva create mode 100644 programs/parva_0.2/split_args create mode 100644 programs/parva_0.2/tetris.parva diff --git a/.gitignore b/.gitignore index fcd4f09..52ff572 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ package-lock.json assembler/**/*.js !assembler/ldt/** c/ +target/ +Cargo.lock diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..17c89cf --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.rulers": [100] +} diff --git a/assembler/index.html b/assembler/index.html index 11d8415..c09c2f7 100644 --- a/assembler/index.html +++ b/assembler/index.html @@ -10,8 +10,10 @@ - @@ -24,6 +26,7 @@ diff --git a/assembler/main.ts b/assembler/main.ts index c9c2a33..e88c1a0 100644 --- a/assembler/main.ts +++ b/assembler/main.ts @@ -2,13 +2,14 @@ import * as bitUtils from './bit_utils.js'; import targetV8 from './targets/v8.js'; import targetParva_0_1 from './targets/parva_0_1.js'; +import targetBitzzy from './targets/bitzzy.js'; import targetLodestar from './targets/lodestar.js'; import * as targetTest from './targets/test/test.js'; import { ArchName, ArchSpecification, AssemblyInput, AssemblyOutput, InstructionOutputLine } from './assembly.js'; import { toNote } from './util.js'; const CONFIG_VERSION: string = '1'; -const EMULATOR_SPEED = 30; +const EMULATOR_SPEED = 70; window.addEventListener('load', init); @@ -194,6 +195,8 @@ function getArch(name: string): ArchSpecification { return targetV8; } else if (name === 'parva_0_1') { return targetParva_0_1; + } else if (name === 'bitzzy') { + return targetBitzzy; } else if (name === 'lodestar') { return targetLodestar as any; } else { diff --git a/assembler/targets/bitzzy.ts b/assembler/targets/bitzzy.ts new file mode 100644 index 0000000..d1eb494 --- /dev/null +++ b/assembler/targets/bitzzy.ts @@ -0,0 +1,792 @@ +import type { OutputLine, AssemblyInput, ArchSpecification, AssemblyOutput, InputError, LineSource, Emulator } from '../assembly'; +import { toBitString } from '../util.js'; + +export type Reference = { + sourceAddress: number; + addressRelative: boolean; + bitCount: number; + value: string; +}; + +type ParsedLabel = { + tag: 'label'; + source: LineSource, + name: string; +}; + +type ParsedInstruction = { + tag: 'instruction'; + source: LineSource, + parts: Array; + address: number; +}; + +export type ParsedLinePart = string | Reference; +type ParsedLine = ParsedInstruction | ParsedLabel; + +function isNumber(value: string): boolean { + return toNumber(value) !== null; +} + +function toNumber(value: string): number { + let result = null; + if (value.startsWith('$')) { + result = parseInt(value.slice(1), 16); + } else if (value.startsWith('%')) { + result = parseInt(value.slice(1), 2); + } else if (value.startsWith('@')) { + result = parseInt(value.slice(1), 8); + } else { + result = parseInt(value, 10); + } + if (isNaN(result)) { + return null; + } + return result; +} + +type Binding = { tag: 'binding', name: string }; + +const NUMBER_RE = String.raw`%-?[01][01_]*|\$-?[\da-f][\da-f_]*|@-?[0-7][0-7_]*|-?\d[\d_]*`; +const VALUE_ATOM_RE = String.raw`(?:${NUMBER_RE}|[a-z0-9_-]+)`; +const VALUE_PAIR_RE = String.raw`\((${VALUE_ATOM_RE})\s*([\+\-])\s*(${VALUE_ATOM_RE})\)`; +const VALUE_RE = String.raw`${VALUE_ATOM_RE}|${VALUE_PAIR_RE}`; +const REGISTER_RE = 'x|y|z|X|Y|Z|YX|yx'; + +class Program { + currentAddress: number; + output: Array; + labels: Map; + constants: Map; + outputEnabled: boolean | null; + + constructor() { + this.currentAddress = 0; + this.output = []; + this.labels = new Map(); + this.constants = new Map(); + this.outputEnabled = null; + } + + instruction(parts: Array, wordCount: number, source: LineSource, count: number) { + if (this.outputEnabled === null || this.outputEnabled) { + this.output.push({ + tag: 'instruction', + source, + address: this.currentAddress, + parts, + }); + } + this.currentAddress += wordCount * count; + } + + label(name: string, source: LineSource) { + if (this.labels.has(name)) { + throw new Error(`Label '${name}' already defined`); + } + this.labels.set(name, this.currentAddress); + this.output.push({ + tag: 'label', + source, + name, + }); + } + + address(value: number) { + this.currentAddress = value; + } + + align(value: number) { + this.currentAddress = Math.ceil(this.currentAddress / value) * value; + } + + enable() { + if (this.outputEnabled === null) { + this.output = []; + } + this.outputEnabled = true; + } + + disable() { + this.outputEnabled = false; + } + + data(values: Array, source: LineSource) { + const numbers: Array = values.map(n => this.value(n, 8, true)); + for (const number of numbers) { + this.instruction([number], 1, { ...source, realInstruction: '(data)' }, 1); + } + return this; + } + + constant(name: string, value: number) { + this.constants.set(name, value); + } + + value(numberOrLabelText: string, bits: number, dynamic: boolean = false): ParsedLinePart { + if (isNumber(numberOrLabelText)) { + return toBitString(toNumber(numberOrLabelText), bits, false, 8); + } else { + return { + addressRelative: false, + sourceAddress: this.currentAddress, + bitCount: dynamic ? 16 : bits, + value: numberOrLabelText, + }; + } + } + + literal(numberText: string, bits: number, signed: boolean): number { + if (!isNumber(numberText)) { + throw new Error(`Expected number, got ${numberText}`); + } else { + return toNumber(numberText); + } + } + + parseSourceLine(sourceLine: string, lineNumber: number) { + // Remove comments beginning with ; and # + let commentIndex = sourceLine.length; + if (sourceLine.indexOf(';') !== -1) { + commentIndex = Math.min(commentIndex, sourceLine.indexOf(';')); + } + if (sourceLine.indexOf('//') !== -1) { + commentIndex = Math.min(commentIndex, sourceLine.indexOf('//')); + } + const uncommented = sourceLine.slice(0, commentIndex).trim(); + this.parse({ + lineNumber, + realInstruction: uncommented, + sourceInstruction: uncommented, + sourceInstructionCommented: sourceLine, + }); + } + + parse(source: LineSource) { + const line = source.realInstruction; + + if (line === '') { + return; + } + + let matchFound = false; + + const match = (...args: Array void)>) => { + if (matchFound) { + return; + } + const fn = args.pop() as any; + const expression = new RegExp('^' + args.join('') + '$', 'i'); + const result = line.match(expression); + if (result === null) { + return; + } + fn(result.groups); + matchFound = true; + } + const i = (...parts: Array) => { + this.instruction(parts, 1, source, 1); + }; + const i2 = (...parts: Array) => { + this.instruction(parts, 1, source, 2); + }; + const i3 = (...parts: Array) => { + this.instruction(parts, 1, source, 3); + }; + const i4 = (...parts: Array) => { + this.instruction(parts, 1, source, 4); + }; + const pseudo = (realInstruction: string) => this.parse({ ...source, realInstruction }); + const binding = (name: string): Binding => ({ tag: 'binding', name }); + const r = binding('r'); + const a = binding('a'); + const b = binding('b'); + + const bindablePattern = (regex: string, prefix: string = '', suffix: string = '') => (binding: Binding) => + `${prefix}(?<${binding.name}>${regex})${suffix}`; + const token = bindablePattern(VALUE_RE); + const register = bindablePattern(REGISTER_RE); + const immediate = bindablePattern(VALUE_RE, '#'); + const remainder = bindablePattern('.*'); + + window['numberRegex'] = NUMBER_RE; + + const s = String.raw`\s+`; + const so = String.raw`\s*`; + const sep = String.raw`\s*[,\s]\s*`; + const hardSep = String.raw`\s*,\s*`; + + const addr = bindablePattern(VALUE_RE); + const registerAndA = bindablePattern(REGISTER_RE, '', `${so},${so}A`); + const valueAndA = bindablePattern(VALUE_RE, '', `${so},${so}A`); + const x = '[xX]'; + const y = '[yY]'; + const z = '[zZ]'; + const yx = '[yY][xX]'; + + match('hlt', () => i('00000000')); + match('rti', () => i('00000010')); + match('eni', () => i('00000011')); + match('dsi', () => i('00000100')); + match('nop', () => i('00000101')); + + match('rem', s, x, () => i('00001000')); + match('rem', s, y, () => i('00001001')); + match('rem', s, z, () => i('00001010')); + match('clr', () => i('00001011')); + + match('jmp', s, addr(a), ({ a }) => { i3('00010000', this.value(a, 16)) }); + match('jmp', s, addr(a), sep, x, ({ a }) => { i3('00010001', this.value(a, 16)) }); + match('jmp', s, addr(a), sep, y, ({ a }) => { i3('00010010', this.value(a, 16)) }); + match('jmp', s, addr(a), sep, z, ({ a }) => { i3('00010011', this.value(a, 16)) }); + + match('jsr', s, addr(a), ({ a }) => { i3('00010100', this.value(a, 16)) }); + match('jsr', s, addr(a), sep, x, ({ a }) => { i3('00010101', this.value(a, 16)) }); + match('jsr', s, addr(a), sep, y, ({ a }) => { i3('00010110', this.value(a, 16)) }); + match('jsr', s, addr(a), sep, z, ({ a }) => { i3('00010111', this.value(a, 16)) }); + + match('swp', s, x, sep, y, () => { i('00011000') }); + match('swp', s, y, sep, x, () => pseudo('SWP X, Y')); + match('swp', s, x, sep, z, () => { i('00011001') }); + match('swp', s, z, sep, x, () => pseudo('SWP X, Z')); + match('swp', s, y, sep, z, () => { i('00011011') }); + match('swp', s, z, sep, y, () => pseudo('SWP Y, Z')); + + match('jmpez', s, x, sep, addr(a), ({ a }) => { i3('00100000', this.value(a, 16)) }); + match('jmpez', s, z, sep, addr(a), ({ a }) => { i3('00100001', this.value(a, 16)) }); + match('jmpez', s, register(r), sep, addr(a), () => { throw new Error('JMPEZ can only be used with registers X and Z') }); + match('jmpgt', s, x, sep, y, sep, addr(a), ({ a }) => { i3('00100010', this.value(a, 16)) }); + match('jmpgt', s, register(a), sep, register(b), sep, addr(r), () => { throw new Error('JMPGT can only be used with registers X and Y') }); + match('jmpeq', s, x, sep, y, sep, addr(a), ({ a }) => { i3('00100011', this.value(a, 16)) }); + match('jmpeq', s, y, sep, x, sep, addr(a), ({ a }) => pseudo(`JMPEQ X, Y, ${a}`)); + match('jmpeq', s, x, sep, z, sep, addr(a), ({ a }) => { i3('11110010', this.value(a, 16)) }); + match('jmpeq', s, z, sep, x, sep, addr(a), ({ a }) => pseudo(`JMPEQ X, Z, ${a}`)); + match('jmpeq', s, y, sep, z, sep, addr(a), ({ a }) => { i3('11110011', this.value(a, 16)) }); + match('jmpeq', s, z, sep, y, sep, addr(a), ({ a }) => pseudo(`JMPEQ Y, Z, ${a}`)); + match('jmprez', s, addr(a), ({ a }) => { i3('11110000', this.value(a, 16)) }); + match('jmprnz', s, addr(a), ({ a }) => { i3('11110001', this.value(a, 16)) }); + + match('jsrez', s, x, sep, addr(a), ({ a }) => { i3('00100100', this.value(a, 16)) }); + match('jsrez', s, z, sep, addr(a), ({ a }) => { i3('00100101', this.value(a, 16)) }); + match('jsrez', s, register(r), sep, addr(a), () => { throw new Error('JSREZ can only be used with registers X and Z') }); + match('jsrgt', s, x, sep, y, sep, addr(a), ({ a }) => { i3('00100110', this.value(a, 16)) }); + match('jsrgt', s, register(a), sep, register(b), sep, () => { throw new Error('JSRGT can only be used with registers X and Y') }); + match('jsreq', s, x, sep, y, sep, addr(a), + ({ a }) => { i3('00100111', this.value(a, 16)) }); + match('jsreq', s, y, sep, x, sep, addr(a), ({ a }) => pseudo(`JSREQ X, Y, ${a}`)); + match('jsreq', s, register(a), sep, register(b), sep, addr(r), () => { throw new Error('JSREQ can only be used with registers X and Y') }); + + match('ret', () => i('00000001')); + match('retrez', () => i('11110100')); + match('retrnz', () => i('11110101')); + + match('djnz', s, x, sep, addr(a), ({ a }) => i3('11100000', this.value(a, 16))); + match('djnz', s, y, sep, addr(a), ({ a }) => i3('11100001', this.value(a, 16))); + match('djnz', s, z, sep, addr(a), ({ a }) => i3('11100010', this.value(a, 16))); + + match('lod', s, x, sep, immediate(a), ({ a }) => i2('01111100', this.value(a, 8))); + match('lod', s, y, sep, immediate(a), ({ a }) => i2('01111101', this.value(a, 8))); + match('lod', s, z, sep, immediate(a), ({ a }) => i2('01111110', this.value(a, 8))); + match('lod', s, y, sep, x, () => i('00101000')); + match('lod', s, z, sep, x, () => i('00101001')); + match('lod', s, x, sep, y, () => i('00101010')); + match('lod', s, z, sep, y, () => i('00101011')); + match('lod', s, x, sep, z, () => i('00101100')); + match('lod', s, y, sep, z, () => i('00101101')); + + match('lod', s, x, sep, addr(a), ({ a }) => { i3('10100000', this.value(a, 16)) }); + match('lod', s, y, sep, addr(a), ({ a }) => { i3('10110000', this.value(a, 16)) }); + match('lod', s, z, sep, addr(a), ({ a }) => { i3('11000000', this.value(a, 16)) }); + match('lod', s, x, sep, addr(a), sep, y, + ({ a }) => { i3('10100001', this.value(a, 16)) }); + match('lod', s, x, sep, addr(a), sep, z, + ({ a }) => { i3('10100010', this.value(a, 16)) }); + match('lod', s, y, sep, addr(a), sep, x, + ({ a }) => { i3('10110001', this.value(a, 16)) }); + match('lod', s, y, sep, addr(a), sep, z, + ({ a }) => { i3('10110010', this.value(a, 16)) }); + match('lod', s, z, sep, addr(a), sep, x, + ({ a }) => { i3('11000001', this.value(a, 16)) }); + match('lod', s, z, sep, addr(a), sep, y, + ({ a }) => { i3('11000010', this.value(a, 16)) }); + + match('str', s, x, sep, addr(a), ({ a }) => { i3('10100100', this.value(a, 16)) }); + match('str', s, y, sep, addr(a), ({ a }) => { i3('10110100', this.value(a, 16)) }); + match('str', s, z, sep, addr(a), ({ a }) => { i3('11000100', this.value(a, 16)) }); + match('str', s, x, sep, addr(a), sep, y, + ({ a }) => { i3('10100101', this.value(a, 16)) }); + match('str', s, x, sep, addr(a), sep, z, + ({ a }) => { i3('10100110', this.value(a, 16)) }); + match('str', s, y, sep, addr(a), sep, x, + ({ a }) => { i3('10110101', this.value(a, 16)) }); + match('str', s, y, sep, addr(a), sep, z, + ({ a }) => { i3('10110110', this.value(a, 16)) }); + match('str', s, z, sep, addr(a), sep, x, + ({ a }) => { i3('11000101', this.value(a, 16)) }); + match('str', s, z, sep, addr(a), sep, y, + ({ a }) => { i3('11000110', this.value(a, 16)) }); + + match('str', s, immediate(a), sep, addr(b), sep, x, + ({ a, b }) => { i4('11010000', this.value(b, 16), this.value(a, 8)) }); + match('str', s, immediate(a), sep, addr(b), sep, y, + ({ a, b }) => { i4('11010001', this.value(b, 16), this.value(a, 8)) }); + match('str', s, immediate(a), sep, addr(b), sep, z, + ({ a, b }) => { i4('11010010', this.value(b, 16), this.value(a, 8)) }); + match('str', s, immediate(a), sep, addr(b), + ({ a, b }) => { i4('11010011', this.value(b, 16), this.value(a, 8)) }); + match('str', s, immediate(a), sep, addr(b), sep, yx, + ({ a, b }) => { i4('11010100', this.value(b, 16), this.value(a, 8)) }); + + match('lod', s, z, sep, addr(a), sep, yx, + ({ a }) => { i3('11000011', this.value(a, 16)) }); + match('str', s, z, sep, addr(a), sep, yx, + ({ a }) => { i3('11000111', this.value(a, 16)) }); + + match('jmp', s, addr(a), ({ a }) => { i3('00010000', this.value(a, 16)) }); + + match('inc', s, x, () => i('00110000')); + match('inc', s, y, () => i('00110001')); + match('inc', s, z, () => i('00110010')); + match('inc', s, addr(a), ({ a }) => i3('00110011', this.value(a, 16))); + + match('dec', s, x, () => i('00110100')); + match('dec', s, y, () => i('00110101')); + match('dec', s, z, () => i('00110110')); + match('dec', s, addr(a), ({ a }) => i3('00110111', this.value(a, 16))); + + match('add', s, x, sep, immediate(a), ({ a }) => i2('01000000', this.value(a, 8))); + match('add', s, y, sep, immediate(a), ({ a }) => i2('01010000', this.value(a, 8))); + match('add', s, z, sep, immediate(a), ({ a }) => i2('01100000', this.value(a, 8))); + // TODO: Check where result is stored and maybe remove the duplicate encodings if needed + match('add', s, x, sep, y, () => i('01000100')); + match('add', s, y, sep, x, () => i('01000100')); + match('add', s, x, sep, z, () => i('01000101')); + match('add', s, z, sep, x, () => i('01000101')); + match('add', s, y, sep, z, () => i('01010101')); + match('add', s, z, sep, y, () => i('01010101')); + + match('sub', s, x, sep, immediate(a), ({ a }) => i2('01000001', this.value(a, 8))); + match('sub', s, y, sep, immediate(a), ({ a }) => i2('01010001', this.value(a, 8))); + match('sub', s, z, sep, immediate(a), ({ a }) => i2('01100001', this.value(a, 8))); + match('sub', s, x, sep, y, () => i('01000110')); + match('sub', s, x, sep, z, () => i('01000111')); + match('sub', s, y, sep, x, () => i('01010110')); + match('sub', s, y, sep, z, () => i('01010111')); + match('sub', s, z, sep, x, () => i('01100110')); + match('sub', s, z, sep, y, () => i('01100111')); + + match('mul', s, x, sep, immediate(a), ({ a }) => i2('01000010', this.value(a, 8))); + match('mul', s, y, sep, immediate(a), ({ a }) => i2('01010010', this.value(a, 8))); + match('mul', s, z, sep, immediate(a), ({ a }) => i2('01100010', this.value(a, 8))); + match('mul', s, x, sep, y, () => i('01001000')); + match('mul', s, y, sep, x, () => i('01001000')); + match('mul', s, x, sep, z, () => i('01001001')); + match('mul', s, z, sep, x, () => i('01001001')); + match('mul', s, y, sep, z, () => i('01011001')); + match('mul', s, z, sep, y, () => i('01011001')); + + match('div', s, x, sep, immediate(a), ({ a }) => i2('01000011', this.value(a, 8))); + match('div', s, y, sep, immediate(a), ({ a }) => i2('01010011', this.value(a, 8))); + match('div', s, z, sep, immediate(a), ({ a }) => i2('01100011', this.value(a, 8))); + match('div', s, x, sep, y, () => i('01001010')); + match('div', s, x, sep, z, () => i('01001011')); + match('div', s, y, sep, x, () => i('01011010')); + match('div', s, y, sep, z, () => i('01011011')); + match('div', s, z, sep, x, () => i('01101010')); + match('div', s, z, sep, y, () => i('01101011')); + + match('mod', s, x, sep, immediate(a), ({ a }) => i2('10011100', this.value(a, 8))); + match('mod', s, y, sep, immediate(a), ({ a }) => i2('10011101', this.value(a, 8))); + match('mod', s, z, sep, immediate(a), ({ a }) => i2('10011110', this.value(a, 8))); + match('mod', s, x, sep, y, () => i('01001100')); + match('mod', s, x, sep, z, () => i('01001101')); + match('mod', s, y, sep, x, () => i('01011100')); + match('mod', s, y, sep, z, () => i('01011101')); + match('mod', s, z, sep, x, () => i('01101100')); + match('mod', s, z, sep, y, () => i('01101101')); + + match('lsl', s, x, () => i('01110000')); + match('lsl', s, y, () => i('01110001')); + match('lsl', s, z, () => i('01110010')); + + match('lsr', s, x, () => i('01110100')); + match('lsr', s, y, () => i('01110101')); + match('lsr', s, z, () => i('01110110')); + + match('not', s, x, () => i('01111000')); + match('not', s, y, () => i('01111001')); + match('not', s, z, () => i('01111010')); + + match('and', s, x, sep, immediate(a), ({ a }) => i2('10010000', this.value(a, 8))); + match('and', s, y, sep, immediate(a), ({ a }) => i2('10010001', this.value(a, 8))); + match('and', s, z, sep, immediate(a), ({ a }) => i2('10010010', this.value(a, 8))); + match('and', s, x, sep, y, () => i('10000000')); + match('and', s, y, sep, x, () => i('10000000')); + match('and', s, x, sep, z, () => i('10000001')); + match('and', s, z, sep, x, () => i('10000001')); + match('and', s, y, sep, z, () => i('10000010')); + match('and', s, z, sep, y, () => i('10000010')); + + match('xor', s, x, sep, immediate(a), ({ a }) => i2('10011000', this.value(a, 8))); + match('xor', s, y, sep, immediate(a), ({ a }) => i2('10011001', this.value(a, 8))); + match('xor', s, z, sep, immediate(a), ({ a }) => i2('10011010', this.value(a, 8))); + match('xor', s, x, sep, y, () => i('10000100')); + match('xor', s, y, sep, x, () => i('10000100')); + match('xor', s, x, sep, z, () => i('10000101')); + match('xor', s, z, sep, x, () => i('10000101')); + match('xor', s, y, sep, z, () => i('10000110')); + match('xor', s, z, sep, y, () => i('10000110')); + + match('or', s, x, sep, immediate(a), ({ a }) => i2('10010100', this.value(a, 8))); + match('or', s, y, sep, immediate(a), ({ a }) => i2('10010101', this.value(a, 8))); + match('or', s, z, sep, immediate(a), ({ a }) => i2('10010110', this.value(a, 8))); + match('or', s, x, sep, y, () => i('10001000')); + match('or', s, y, sep, x, () => i('10001000')); + match('or', s, x, sep, z, () => i('10001001')); + match('or', s, z, sep, x, () => i('10001001')); + match('or', s, y, sep, z, () => i('10001010')); + match('or', s, z, sep, y, () => i('10001010')); + + // Directives + + match(token(a), ':', ({ a }) => this.label(a, source)); + match('.data', s, remainder(a), + ({ a }) => this.data(a.split(new RegExp(hardSep)), { ...source, sourceInstruction: '.data' })); + match('.repeat', s, token(a), sep, token(b), + ({ a, b }) => this.data(new Array(this.literal(b, 8, false)).fill(a), { ...source, sourceInstruction: '.repeat' })); + match('.eq', s, token(a), sep, token(b), ({ a, b }) => this.constant(a, this.literal(b, 8, false))); + match('.address', s, token(a), ({ a }) => this.address(this.literal(a, 8, false))); + match('.align', s, token(a), ({ a }) => this.align(this.literal(a, 8, false))); + match('.start', () => this.enable()); + match('.end', () => this.disable()); + + if (!matchFound) { + throw new Error(`Unknown instruction: ${line}`); + } + } + + resolveParsedLine(instruction: ParsedLine): OutputLine { + if (instruction.tag === 'label') { + return { + tag: 'label', + name: instruction.name, + }; + } + + let bits = ''; + for (const part of instruction.parts) { + bits += this.resolveParsedLinePart(part); + } + if (bits.length % 8 !== 0) { + throw new Error(`Instruction ${instruction.source.realInstruction} is ${bits.length} bits long, but should be a multiple of 8`); + } + return { + tag: 'instruction', + bits, + address: instruction.address, + source: instruction.source, + }; + } + + resolveParsedLinePart(part: ParsedLinePart, littleEndian: boolean = true): string { + if (typeof part === 'string') { + return part; + } else if (isNumber(part.value)) { + return toBitString(toNumber(part.value), part.bitCount, part.addressRelative, littleEndian ? 8 : null); + } else if (this.labels.has(part.value)) { + const targetLabelAddress = this.labels.get(part.value); + const value = part.addressRelative ? targetLabelAddress - part.sourceAddress : targetLabelAddress; + return toBitString(value, part.bitCount, part.addressRelative, littleEndian ? 8 : null); + } + + const offsetMatch = part.value.match(new RegExp(VALUE_PAIR_RE, 'i')); + if (offsetMatch) { + const [base, operator, offset] = offsetMatch.slice(1); + + const baseValue = parseInt(this.resolveParsedLinePart({ + ...part, + value: base, + }, false), 2,); + const offsetValue = parseInt(this.resolveParsedLinePart({ + ...part, + addressRelative: false, + value: offset, + }, false), 2) * (operator === '+' ? 1 : -1); + return toBitString(baseValue + offsetValue, part.bitCount, part.addressRelative, littleEndian ? 8 : null); + } + + if (this.constants.has(part.value)) { + const value = this.constants.get(part.value); + return toBitString(value, part.bitCount, false, littleEndian ? 8 : null); + } else { + throw new Error(`Unknown label: ${part.value}`); + } + } +} + +function assemble(input: AssemblyInput): AssemblyOutput { + const program = new Program(); + const errors: Array = []; + + for (const [lineNumber, line] of input.source.split('\n').entries()) { + try { + program.parseSourceLine(line, lineNumber); + } catch (e) { + errors.push({ + line: lineNumber, + message: e.message, + }); + } + } + + const outputLines: Array = []; + for (const instruction of program.output) { + let resolved: OutputLine; + try { + resolved = program.resolveParsedLine(instruction); + outputLines.push(resolved); + } catch (e) { + errors.push({ + line: instruction.source.lineNumber, + message: e.message, + }); + } + } + + return { + lines: outputLines, + errors, + message: '', + }; +} + +const STACK_POINTER_ADDRESS = 0x7f; +const INTERRUPT_VECTOR_ADDRESS = 0xfe; +const RESET_VECTOR_ADDRESS = 0xff; + +class V8Emulator implements Emulator { + memory: Array = []; + registers: Array = []; + pc: number; + cycle: number; + carryFlag: boolean; + zeroFlag: boolean; + interruptsEnabled: boolean; + + constructor() { + this.init([]); + } + + init(memory: Array) { + this.memory = memory; + this.memory[STACK_POINTER_ADDRESS] = STACK_POINTER_ADDRESS - 1; + this.registers = new Array(8).fill(0); + this.pc = this.memory[RESET_VECTOR_ADDRESS] ?? 0; + this.cycle = 0; + this.carryFlag = false; + this.zeroFlag = false; + this.interruptsEnabled = true; + } + + step() { + + } + + printState(): string { + return 'Emulator not implemented'; + } +} + +const syntaxHighlighting = new window['Parser']({ + whitespace: /\s+/, + number: /#?(\$-?[\dA-Fa-f_]+|-?(\d+)|%-?[01_]+|@-?[0-7_]+)/, + comment: /\/\/[^\r\n]*|;[^\r\n]*/, + directive: /\.[a-zA-Z0-9_]+/, + label: /[a-zA-Z0-9_]+:/, + string: /"(\\.|[^"\r\n])*"|'(\\.|[^'\r\n])*'/, + register: /\b([xyz]|yx)\b/i, + instruction: /^[a-zA-Z0-9\.]+/, + other: /\S/, +}); + +const archSpecification: ArchSpecification = { + documentation: '', + syntaxHighlighting, + assemble, + maxWordsPerInstruction: 4, + wordSize: 8, + emulator: new V8Emulator(), +}; +export default archSpecification; + +archSpecification.documentation = ` +# Bitzzy + +An 8-bit CPU by Mazzetip with 16-bit addressing. + + +## Registers + +There are three registers: X, Y, and Z. Z is the accumulator. + + +## Assembler syntax + +Instructions and registers are case-insensitive. For example, \`INC X\` and \`inc x\` are both valid. + +Labels and constants are case-sensitive. For example, \`myLabel:\` and \`mylabel:\` are different labels. + +Comments begin with a semicolon. For example, \`; this is a comment\`. + +Labels can be offset by a value by placing them in parentheses. For example, \`(myLabel + 2)\` is two bytes after \`myLabel\`. + +<reg> indicates a register, i.e. X, Y, or Z. For example, the instruction \`INC \` can be used as \`INC X\`, \`INC Y\`, or \`INC Z\`. + +When an instruction takes two registers, they must not be the same. E.g. \`SWP x, y\` is okay but \`SWP x, x\` is illegal. + +<imm> indicates an 8-bit immediate value. This must be prefixed with '#' and can be signed or unsigned. For example, \`LOD X, #\$ff\` loads the value -1 into register X. + +<addr> indicates a 16-bit address. For example, \`JMP \$fa08\` jumps to address 0xfa08. + +When registers X and Y are used together to form a 16-bit address, they are written as YX. Y forms the upper 8 bits while X forms the lower 8 bits. + + +## Instructions + +HLT: Halt the CPU. + +RTI: Return from interrupt. + +ENI: Enable interrupts. + +DSI: Disable interrupts. + +NOP: No operation. + +REM <reg>: Set register <reg> to the remainder (the carry/borrow flag). + +CLR: Clear remainder. + +JMP <addr>: Jump to the address <addr>. + +JMP <addr>, <reg>: Jump to the address <addr> + register <reg>. + +JMPEZ X, <addr>: Jump to the address <addr> if register X is zero. + +JMPEZ Z, <addr>: Jump to the address <addr> if register Z is zero. + +JMPGT X, Z, <addr>: Jump to the address <addr> if X is greater than Y. + +JMPEQ <reg-a>, <reg-b>, <addr>: Jump to the address <addr> if register <reg-a> is equal to register <reg-b>. + +JMPRNZ <addr>: Jump to the address <addr> if the remainder is not zero. + +JMPREZ <addr>: Jump to the address <addr> if the remainder is zero. + +JSR <addr>: Jump to the address <addr> and push the return address onto the stack. + +JSR <addr>, <reg>: Jump to the address <addr> + register <reg> and push the return address onto the stack. + +JSREZ X, <addr>: Jump to the address <addr> if register X is zero and push the return address onto the stack. + +JSREZ Z, <addr>: Jump to the address <addr> if register Z is zero and push the return address onto the stack. + +JSRGT X, Z, <addr>: Jump to the address <addr> if X is greater than Y and push the return address onto the stack. + +JSREQ <reg-a>, <reg-b>, <addr>: Jump to the address <addr> if register <reg-a> is equal to register <reg-b> and push the return address onto the stack. + +DJNZ <reg>, <addr>: Decrement register <reg> and jump to the address <addr> if it is now not zero. + +RET: Return from subroutine. + +RETRNZ: Return from subroutine if the remainder is not zero. + +RETREZ: Jump to the address <addr> if the remainder is zero. + +INC <reg>: Increment register <reg>. + +INC <addr>: Increment value at address <addr>. + +DEC <reg>: Decrement register <reg>. + +DEC <addr>: Decrement value at address <addr>. + +ADD <reg-a>, <reg-b>: Add register <reg-b> to register <reg-a> and store the result in Z. + +ADD <reg>, <imm>: Add the immediate value <imm> to register <reg> and store the result in register <reg>. + +SUB <reg-a>, <reg-b>: Subtract register <reg-b> from register <reg-a> and store the result in Z. + +SUB <reg>, <imm>: Subtract the immediate value <imm> from register <reg> and store the result in register <reg>. + +LSL <reg>: Logical shift left register <reg> by one bit. + +LSR <reg>: Logical shift right register <reg> by one bit. + +AND <reg-a>, <reg-b>: Bitwise AND register <reg-a> with register <reg-b> and store the result in Z. + +AND <reg>, <imm>: Bitwise AND register <reg> with the immediate value <imm> and store the result in register <reg>. + +OR <reg-a>, <reg-b>: Bitwise OR register <reg-a> with register <reg-b> and store the result in Z. + +OR <reg>, <imm>: Bitwise OR register <reg> with the immediate value <imm> and store the result in register <reg>. + +XOR <reg-a>, <reg-b>: Bitwise XOR register <reg-a> with register <reg-b> and store the result in Z. + +XOR <reg>, <imm>: Bitwise XOR register <reg> with the immediate value <imm> and store the result in register <reg>. + +LOD <reg>, <imm>: Load the immediate value <imm> into register <reg>. + +LOD <reg-a>, <reg-b>: Load the value in register <reg-b> into register <reg-a>. + +LOD <reg>, <addr>: Load the value at address <addr> into register <reg>. + +LOD <reg-a>, <addr>, <reg-b>: Load the value at address <addr> + register <reg-b> into register <reg-a>. + +LOD Z, <addr>, YX: Load the value at address <addr> + the combined value of registers X and Y ($YYXX) into register Z. + +SWP <reg-a>, <reg-b>: Swap the values in registers <reg-a> and <reg-b>. + +STR <reg>, <addr>: Store the value in register <reg> at address <addr>. + +STR <reg-a>, <addr>, <reg-b>: Store the value in register <reg-a> at address <addr> + register <reg-b>. + +STR <imm>, <addr>: Store the immediate value <imm> to address <addr>. + +STR <imm>, <addr>, <reg>: Store the immediate value <imm> to address <addr> + register <reg>. + +STR Z, <addr>, YX: Store the value in register Z at address <addr> + the combined value of registers X and Y ($YYXX). + +MUL <reg-a>, <reg-b>: Multiply register <reg-a> by register <reg-b> and store the result in in Z. + +MUL <reg>, <imm>: Multiply register <reg> by the immediate value <imm> and store the result in register <reg>. + +DIV <reg-a>, <reg-b>: Divide register <reg-a> by register <reg-b> and store the result in in Z. + +DIV <reg>, <imm>: Divide register <reg> by the immediate value <imm> and store the result in register <reg>. + +MOD <reg-a>, <reg-b>: Divide register <reg-a> by register <reg-b> and store the remainder in in Z. + +MOD <reg>, <imm>: Divide register <reg> by the immediate value <imm> and store the remainder in register <reg>. + + +## Assembler directives + +\`:\` : Define a label. + +\`.data , , , ...\`: Store 8-bit values in memory. You can also use labels, in which case the 16-bit address of the label will be stored. + +\`.repeat , \`: Repeat in memory multiple times. + +\`.address \`: Set the current address to . + +\`.align \`: Align the current address to the next multiple of . + +\`.end\`: Ignore all following instructions. + +\`.start\`: Resume assembling instructions. + +\`.eq\ , \`: Define a constant. + + +`; diff --git a/assembler/targets/parva_0_1.ts b/assembler/targets/parva_0_1.ts index 4a60c2c..199a1d0 100644 --- a/assembler/targets/parva_0_1.ts +++ b/assembler/targets/parva_0_1.ts @@ -633,7 +633,12 @@ class ParvaEmulator implements Emulator { } step() { + const instructionsFetched = (2 - (this.pc % 2)) + (this.previousFrameAccessedMemory ? 0 : 2); + this.previousFrameAccessedMemory = false; + for (let i = 0; i < instructionsFetched; i++) { + if (this.stepCore()) break; + } } stepCore(): boolean { @@ -724,6 +729,7 @@ class ParvaEmulator implements Emulator { } this.previousFrameAccessedMemory = true; + coreTerminates = true; } else if (operationType === '11') { // branching const special = condition.startsWith('11'); diff --git a/assembler/util.ts b/assembler/util.ts index 3a9a786..350355c 100644 --- a/assembler/util.ts +++ b/assembler/util.ts @@ -1,4 +1,4 @@ -export function toBitString(n: number, bits: number, signed: boolean = false): string { +export function toBitString(n: number, bits: number, signed: boolean = false, littleEndianByteSize: null | number = null): string { const minimum = -(2 ** (bits - 1)); const maximum = signed ? (2 ** (bits - 1)) - 1 : 2 ** bits - 1; @@ -18,6 +18,15 @@ export function toBitString(n: number, bits: number, signed: boolean = false): s if (n !== 0) { throw new Error(`Internal error: ${n} not zero after conversion to ${bits}-bit ${signed ? 'signed' : 'unsigned'} integer`); } + + if (littleEndianByteSize !== null) { + const bytes = []; + for (let i = 0; i < result.length / littleEndianByteSize; i++) { + bytes.push(result.substring(i * littleEndianByteSize, (i + 1) * littleEndianByteSize)); + } + result = bytes.reverse().join(''); + } + return result; } diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml new file mode 100644 index 0000000..f067238 --- /dev/null +++ b/compiler/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "compiler" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nom = "7.1.3" diff --git a/compiler/examples/calculator_1.parva b/compiler/examples/calculator_1.parva new file mode 100644 index 0000000..fc24a8e --- /dev/null +++ b/compiler/examples/calculator_1.parva @@ -0,0 +1,96 @@ +# target parva_0_1 + +li sp, stack + +fn tokenize(input) { + let current_token_ptr = input - 1; + let temp = -1; + push(temp); // mark the beginning of the token stack + + loop { + current_token_ptr += 1; + let current_token = rw(current_token_ptr); + if current_token == 0 { + goto(tokenize_end); + } + if current_token == '0' { + goto(tokenize_symbol); + } + if current_token == '9' { + goto(tokenize_symbol); + } + let number_start_addr = sp + + + current_token_ptr + let token_value = current_token - '0'; + + lw x3, x2 + blt x3, x4, tokenize__number_gather_end + bgt x3, x5, tokenize__number_gather_end + b tokenize__number_gather +tokenize__number_gather_end: + li x0, 0 # x0 = sum + li x7, 1 # x7 = power of 10 +.align 2 +tokenize__number_sum: + pop x3 + mulu x3, x3, x7 + add x0, x0, x3 + mului x7, x7, 10 + bne x6, sp, tokenize__number_sum + + li x3, 1 # token type = 1 = number + push x3 + push x0 + b tokenize__loop + +tokenize__symbol: + xori x3, x3, 42 # todo, set to appropriate value for hashing symbols + lw x3, tokenize__symbol_hashtable(x3) + beqz x3, error_invalid_input + push x3 + b tokenize__loop +} + +tokenize__shunting_yard: + pop x3 + bnez x3, 3 + +} + +b end + +tokenize__output_queue: + .repeat 0 40 + +tokenize__symbol_hashtable: + .data 0 + .data 1 + .repeat 0 30 # todo + +error_invalid_input: + li a0, error_message_invalid_input + li a1, 1 + call print + b end + +# function +print: + # todo + ret + +end: + wfi + +input_string: +.string_encoding terminal +.string "125+23*8" +.string "\0" + +error_message_invalid_input: +.string_encoding ascii # todo, use correct encoding +.string "Invalid input\0" + +stack: + diff --git a/compiler/examples/test.parva b/compiler/examples/test.parva new file mode 100644 index 0000000..090490e --- /dev/null +++ b/compiler/examples/test.parva @@ -0,0 +1,6 @@ +x = (y + 3) + 5; +y += x; +z = foo; +fn test() { + poop = moop; +} diff --git a/compiler/rustfmt.toml b/compiler/rustfmt.toml new file mode 100644 index 0000000..218e203 --- /dev/null +++ b/compiler/rustfmt.toml @@ -0,0 +1 @@ +hard_tabs = true diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs new file mode 100644 index 0000000..8741b9f --- /dev/null +++ b/compiler/src/compiler.rs @@ -0,0 +1,137 @@ +use crate::{ + parser::{Expression, Statement}, + CompilationError, +}; + +struct Context { + temporary_counter: usize, +} + +impl Context { + fn new() -> Self { + Self { + temporary_counter: 0, + } + } + + fn new_temporary(&mut self) -> String { + let result = format!("__temp{}", self.temporary_counter); + self.temporary_counter += 1; + result + } +} + +pub fn compile(ast: Statement) -> Result { + let mut context = Context::new(); + println!("initial: {:#?}\n", ast); + let ast = ast_pass_0(ast)?; + println!("pass 0: {:#?}\n", ast); + let ast = ast_pass_1(&mut context, vec![ast])?; + println!("pass 1: {:#?}\n", ast); + Ok(format!("{:?}\n", ast)) +} + +/// Pass 0 +/// +/// Rewrites compound assignments into simple assignments, e.g. `a += 1` to `a = a + 1` +fn ast_pass_0(ast: Statement) -> Result { + let result = match ast { + Statement::Block(inner) => Statement::Block( + inner + .into_iter() + .map(ast_pass_0) + .collect::, _>>()?, + ), + Statement::AddAssign(name, expr) => Statement::Assign( + name.clone(), + Expression::Add(Box::new(Expression::Identifier(name)), Box::new(expr)), + ), + statement => statement, + }; + Ok(result) +} + +/// Pass 1 +/// +/// Expands nested expressions into simple expressions, +/// e.g. `a = (x + y) + z;` to `temp0 = x + y; a = temp0 + z;` +fn ast_pass_1( + context: &mut Context, + statements: Vec, +) -> Result, CompilationError> { + let mut statements_out = Vec::new(); + + for statement in statements { + match statement { + Statement::Block(inner) => { + statements_out.push(Statement::Block(ast_pass_1(context, inner)?)); + } + Statement::Assign(name, expr) => { + let (mut expression_statements, expression) = + flatten_expression(context, expr.clone())?; + + statements_out.extend(expression_statements); + statements_out.push(Statement::Assign(name.clone(), expression)); + } + statement => statements_out.push(statement), + }; + } + Ok(statements_out) +} + +fn flatten_expression( + context: &mut Context, + expression: Expression, +) -> Result<(Vec, Expression), CompilationError> { + let mut statements = Vec::new(); + + let result = match expression { + Expression::Identifier(name) => (vec![], Expression::Identifier(name)), + Expression::Number(name) => (vec![], Expression::Number(name)), + Expression::Add(left, right) => { + let (left_statements, left) = flatten_expression(context, *left)?; + statements.extend(left_statements); + + let (right_statements, right) = flatten_expression(context, *right)?; + statements.extend(right_statements); + + let temp_name = context.new_temporary(); + + let statement = Statement::Assign( + temp_name.clone(), + Expression::Add(Box::new(left), Box::new(right)), + ); + statements.push(statement); + (statements, Expression::Identifier(temp_name)) + } + expression => (vec![], expression), + }; + Ok(result) +} + +/// Pass 2 +/// +/// Convert to IR +fn ast_pass_2( + context: &mut Context, + statements: Vec, +) -> Result, CompilationError> { + let mut statements_out = Vec::new(); + + for statement in statements { + match statement { + Statement::Block(inner) => { + statements_out.push(Statement::Block(ast_pass_1(context, inner)?)); + } + Statement::Assign(name, expr) => { + let (mut expression_statements, expression) = + flatten_expression(context, expr.clone())?; + + statements_out.extend(expression_statements); + statements_out.push(Statement::Assign(name.clone(), expression)); + } + statement => statements_out.push(statement), + }; + } + Ok(statements_out) +} diff --git a/compiler/src/compiler/assemble.rs b/compiler/src/compiler/assemble.rs new file mode 100644 index 0000000..02fabdb --- /dev/null +++ b/compiler/src/compiler/assemble.rs @@ -0,0 +1,11 @@ +pub struct Variable { + name: String, +} + +pub enum PseudoInstruction { + Call(Variable), + Return, + Add(Variable, Variable, Variable), + Sub(Variable, Variable, Variable), + Li(Variable, i32), +} diff --git a/compiler/src/lexer.rs b/compiler/src/lexer.rs new file mode 100644 index 0000000..4281ba4 --- /dev/null +++ b/compiler/src/lexer.rs @@ -0,0 +1,186 @@ +use crate::CompilationError; + +#[derive(Debug, Clone)] +pub enum Token { + Identifier(String), + Character(char), + Number(i32), + Operator(Operator), + Colon, + AtSign, + OpenParenthesis, + CloseParenthesis, + OpenBrace, + CloseBrace, + Assignment(Assignment), + Comparison(Comparison), + Semicolon, + Keyword(Keyword), +} + +#[derive(Debug, Copy, Clone)] +pub enum Operator { + Plus, + Minus, + Star, + Slash, +} + +#[derive(Debug, Copy, Clone)] +pub enum Keyword { + Let, + Return, +} + +#[derive(Debug, Copy, Clone)] +pub enum Assignment { + Assign, + AddAssign, +} + +#[derive(Debug, Copy, Clone)] +pub enum Comparison { + Equals, + GreaterThan, + LessThan, +} + +#[derive(Debug, Clone)] +pub struct LexerConfiguration {} + +struct Lexer { + configuration: LexerConfiguration, + input: Vec, + position: usize, + line: usize, + line_start_position: usize, +} + +impl Lexer { + fn new(configuration: LexerConfiguration, input: &str) -> Self { + Self { + configuration: LexerConfiguration {}, + input: input.chars().collect(), + position: 0, + line: 0, + line_start_position: 0, + } + } + + fn next_token(&mut self) -> Result, CompilationError> { + while self.position < self.input.len() { + let next = &self.input[self.position..]; + self.position += 1; + + type Tk = Token; + + let token = match next { + ['=', '=', ..] => Tk::Comparison(Comparison::Equals), + ['>', ..] => Tk::Comparison(Comparison::GreaterThan), + ['<', ..] => Tk::Comparison(Comparison::LessThan), + ['=', ..] => Tk::Assignment(Assignment::Assign), + ['+', '=', ..] => Tk::Assignment(Assignment::AddAssign), + ['+', ..] => Tk::Operator(Operator::Plus), + ['-', ..] => Tk::Operator(Operator::Minus), + ['*', ..] => Tk::Operator(Operator::Star), + ['/', ..] => Tk::Operator(Operator::Slash), + ['(', ..] => Tk::OpenParenthesis, + [')', ..] => Tk::CloseParenthesis, + ['a'..='z' | 'A'..='Z' | '_', ..] => { + let start = self.position - 1; + while self.position < self.input.len() + && (self.input[self.position].is_alphanumeric() + || self.input[self.position] == '_') + { + self.position += 1; + } + let identifier = self.input[start..self.position].iter().collect::(); + + match identifier.as_str() { + "let" => Token::Keyword(Keyword::Let), + "return" => Token::Keyword(Keyword::Return), + _ => Token::Identifier(identifier), + } + } + ['{', ..] => Tk::OpenBrace, + ['}', ..] => Tk::CloseBrace, + [';', ..] => Tk::Semicolon, + [':', ..] => Tk::Colon, + ['@', ..] => Tk::AtSign, + ['\'', ..] => { + let start = self.position; + while self.position < self.input.len() && self.input[self.position] != '\'' { + self.position += 1; + } + if self.position >= self.input.len() { + return Err(CompilationError { + message: format!("Expected closing single quote"), + line: self.line, + column: start - self.line_start_position, + }); + } + self.position += 1; + let character = self.input[start..self.position - 1] + .iter() + .collect::() + .chars() + .next() + .unwrap(); + Token::Character(character) + } + ['0'..='9', ..] => { + let start = self.position - 1; + while self.position < self.input.len() && self.input[self.position].is_digit(10) + { + self.position += 1; + } + let number: i32 = self.input[start..self.position] + .iter() + .collect::() + .parse::() + .map_err(|err| CompilationError { + message: format!("Expected closing single quote"), + line: self.line, + column: start - self.line_start_position, + })?; + Token::Number(number) + } + + ['\n', ..] => { + self.line += 1; + self.line_start_position = self.position; + continue; + } + [' ', '\t', ..] => continue, + _ => continue, + }; + return Ok(Some(token)); + } + + Ok(None) + } +} + +pub fn lex(input: &str, configuration: LexerConfiguration) -> Result, String> { + let mut lexer = Lexer::new(configuration, input); + let mut tokens = Vec::new(); + + loop { + let token = match lexer.next_token() { + Ok(Some(token)) => token, + Ok(None) => break, + Err(CompilationError { + message, + line, + column, + }) => { + return Err(format!( + "Parsing failed at line {}:{}: {}", + line + 1, column + 1, message + )); + } + }; + tokens.push(token); + } + Ok(tokens) +} diff --git a/compiler/src/main.rs b/compiler/src/main.rs new file mode 100644 index 0000000..930f65d --- /dev/null +++ b/compiler/src/main.rs @@ -0,0 +1,71 @@ +#![allow(unused)] + +/* + +can only reorder instructions within a block +branch points delimit blocks + +*/ + +use std::env; +use std::fs; +use std::io::{self, Read}; + +mod compiler; +mod parser; + +#[derive(Debug)] +pub struct CompilationError { + pub message: String, + pub line: usize, + pub column: usize, +} + +impl CompilationError { + pub fn new(message: String, line: usize, column: usize) -> Self { + Self { + message, + line, + column, + } + } +} + +fn main() { + let args: Vec = env::args().collect(); + let input = if args.len() > 1 { + if ((args[1] == "-s") || (args[1] == "--source") && args.len() > 2) { + args[2].to_owned() + } else { + let filename = &args[1]; + if filename == "--" { + let mut buffer = String::new(); + io::stdin() + .read_to_string(&mut buffer) + .expect("Failed to read from stdin"); + buffer + } else { + fs::read_to_string(filename).expect("Failed to read file") + } + } + } else { + panic!("Expected a filename or '--' as argument"); + }; + + let parse_result = match parser::parse(&input) { + Ok(expr) => expr, + Err(err) => { + eprintln!("Error: {:?}", err); + std::process::exit(1); + } + }; + + let compile_result = match compiler::compile(parse_result) { + Ok(expr) => expr, + Err(err) => { + eprintln!("Error: {:?}", err); + std::process::exit(1); + } + }; + println!("Compiled: {:?}", compile_result); +} diff --git a/compiler/src/parser.rs b/compiler/src/parser.rs new file mode 100644 index 0000000..a1658de --- /dev/null +++ b/compiler/src/parser.rs @@ -0,0 +1,378 @@ +use crate::CompilationError; + +mod asm; + +use nom::{ + branch::alt, + bytes::complete::{tag, take_while}, + character::complete::{alpha1, alphanumeric1, char, one_of}, + combinator::{all_consuming, complete, map, map_res, opt, recognize}, + error::{dbg_dmp, ParseError}, + multi::{many0, many1, separated_list0}, + sequence::{delimited, preceded, terminated, tuple}, + Finish, IResult, +}; + +#[derive(Debug, Clone)] +pub enum Statement { + Block(Vec), + Label(String), + Assign(String, Expression), + AddAssign(String, Expression), + SubAssign(String, Expression), + MulAssign(String, Expression), + DivAssign(String, Expression), + FunctionDeclaration(String, Vec, Box), + SubroutineDeclaration(String, Box), +} + +#[derive(Debug, Copy, Clone)] +pub enum BinOp { + Add, + Sub, + Mul, + Div, + Sll, + Srl, + Sra, + BitAnd, + BitOr, + BitXor, + Index, +} + +#[derive(Debug, Clone)] +pub enum Expression { + Number(i64), + Identifier(String), + FunctionCall(String, Vec), + Add(Box, Box), + Sub(Box, Box), + Mul(Box, Box), + Div(Box, Box), + Sll(Box, Box), + Srl(Box, Box), + Sra(Box, Box), + BitNeg(Box, Box), + BitAnd(Box, Box), + BitOr(Box, Box), + BitXor(Box, Box), + Deref(Box), + Index(Box, Box), +} + +pub fn parse(input: &str) -> Result { + let parse_result = all_consuming(complete(program))(input).finish(); + let ast = match parse_result { + Ok((_, ast)) => ast, + Err(err) => { + // let (line, column) = get_line_and_column(input); + let (line, column) = (0, 0); // TODO + return Err(CompilationError::new( + format!("Failed to parse input: {:?}", err), + line, + column, + )); + } + }; + + Ok(ast) +} + +fn expression(input: &str) -> IResult<&str, Expression> { + alt(( + map_res( + tuple(( + primitive_expression, + whitespace, + tag("+"), + whitespace, + expression, + )), + |(left, _, _, _, right)| { + Ok::<_, nom::error::Error>(Expression::Add(Box::new(left), Box::new(right))) + }, + ), + map_res( + tuple(( + primitive_expression, + whitespace, + tag("-"), + whitespace, + expression, + )), + |(left, _, _, _, right)| { + Ok::<_, nom::error::Error>(Expression::Sub(Box::new(left), Box::new(right))) + }, + ), + map_res( + tuple(( + primitive_expression, + whitespace, + tag("*"), + whitespace, + expression, + )), + |(left, _, _, _, right)| { + Ok::<_, nom::error::Error>(Expression::Mul(Box::new(left), Box::new(right))) + }, + ), + map_res( + tuple(( + primitive_expression, + whitespace, + tag("/"), + whitespace, + expression, + )), + |(left, _, _, _, right)| { + Ok::<_, nom::error::Error>(Expression::Div(Box::new(left), Box::new(right))) + }, + ), + map_res( + tuple(( + primitive_expression, + whitespace, + tag("<<"), + whitespace, + expression, + )), + |(left, _, _, _, right)| { + Ok::<_, nom::error::Error>(Expression::Sll(Box::new(left), Box::new(right))) + }, + ), + map_res( + tuple(( + primitive_expression, + whitespace, + tag(">>"), + whitespace, + expression, + )), + |(left, _, _, _, right)| { + Ok::<_, nom::error::Error>(Expression::Srl(Box::new(left), Box::new(right))) + }, + ), + map_res( + tuple(( + primitive_expression, + whitespace, + tag("&"), + whitespace, + expression, + )), + |(left, _, _, _, right)| { + Ok::<_, nom::error::Error>(Expression::BitAnd( + Box::new(left), + Box::new(right), + )) + }, + ), + map_res( + tuple(( + primitive_expression, + whitespace, + tag("|"), + whitespace, + expression, + )), + |(left, _, _, _, right)| { + Ok::<_, nom::error::Error>(Expression::BitOr( + Box::new(left), + Box::new(right), + )) + }, + ), + map_res( + tuple(( + primitive_expression, + whitespace, + tag("^"), + whitespace, + expression, + )), + |(left, _, _, _, right)| { + Ok::<_, nom::error::Error>(Expression::BitXor( + Box::new(left), + Box::new(right), + )) + }, + ), + map_res( + tuple(( + identifier, + whitespace, + delimited( + tag("("), + separated_list0(tag(","), delimited(whitespace, expression, whitespace)), + tag(")"), + ), + )), + |(name, _, arguments)| { + Ok::<_, nom::error::Error>(Expression::FunctionCall( + name.to_string(), + arguments, + )) + }, + ), + map_res( + tuple(( + tag("*"), + whitespace, + expression, + )), + |(_, _, value)| { + Ok::<_, nom::error::Error>(Expression::Deref(Box::new(value))) + }, + ), + primitive_expression, + ))(input) +} + +fn primitive_expression(input: &str) -> IResult<&str, Expression> { + alt(( + variable, + number, + map_res( + tuple((tag("("), whitespace, expression, whitespace, tag(")"))), + |(_, _, expr, _, _)| Ok::<_, nom::error::Error>(expr), + ), + ))(input) +} + +fn statement(input: &str) -> IResult<&str, Statement> { + delimited(whitespace, alt((block, assignment, function)), whitespace)(input) +} + +fn block(input: &str) -> IResult<&str, Statement> { + let (input, (_, _, statements, _, _)) = + tuple((tag("{"), whitespace, many0(statement), whitespace, tag("}")))(input)?; + Ok((input, Statement::Block(statements))) +} + +fn program(input: &str) -> IResult<&str, Statement> { + let (input, (statements)) = many0(statement)(input)?; + Ok((input, Statement::Block(statements))) +} + +fn assignment(input: &str) -> IResult<&str, Statement> { + let (input, (name, _, operator, _, expr, _)) = tuple(( + identifier, + whitespace, + opt(one_of("+-/*")), + tag("="), + delimited(whitespace, expression, whitespace), + tag(";"), + ))(input)?; + let name = name.to_string(); + let statement = match operator { + Some('+') => Statement::AddAssign(name, expr), + Some('-') => Statement::SubAssign(name, expr), + Some('/') => Statement::SubAssign(name, expr), + Some('*') => Statement::SubAssign(name, expr), + None => Statement::Assign(name, expr), + _ => unreachable!(), + }; + Ok((input, statement)) +} + +fn function(input: &str) -> IResult<&str, Statement> { + let (input, (_, name, params, _, body)) = tuple(( + tag("fn"), + delimited(whitespace, identifier, whitespace), + delimited(tag("("), separated_list0(tag(","), identifier), tag(")")), + whitespace, + block, + ))(input)?; + + Ok(( + input, + Statement::FunctionDeclaration( + name.to_string(), + params.into_iter().map(String::from).collect(), + Box::new(body), + ), + )) +} + +fn variable(input: &str) -> IResult<&str, Expression> { + map(identifier, |name| Expression::Identifier(name.to_string()))(input) +} + +fn identifier(input: &str) -> IResult<&str, &str> { + recognize(tuple((alt((tag("_"), alpha1)), many0(alphanumeric1))))(input) +} + +fn number(input: &str) -> IResult<&str, Expression> { + let (input, number) = map( + alt(( + hexadecimal_number, + octal_number, + binary_number, + decimal_number, + )), + |number| Expression::Number(number), + )(input)?; + + Ok((input, number)) +} + +fn hexadecimal_number(input: &str) -> IResult<&str, i64> { + map_res( + preceded( + alt((tag("0x"), tag("0X"))), + recognize(many1(terminated( + one_of("0123456789abcdefABCDEF"), + many0(char('_')), + ))), + ), + |out: &str| i64::from_str_radix(&str::replace(&out, "_", ""), 16), + )(input) +} + +fn octal_number(input: &str) -> IResult<&str, i64> { + map_res( + preceded( + alt((tag("0o"), tag("0O"))), + recognize(many1(terminated(one_of("01234567"), many0(char('_'))))), + ), + |out: &str| i64::from_str_radix(&str::replace(&out, "_", ""), 8), + )(input) +} + +fn binary_number(input: &str) -> IResult<&str, i64> { + map_res( + preceded( + alt((tag("0b"), tag("0B"))), + recognize(many1(terminated(one_of("01"), many0(char('_'))))), + ), + |out: &str| i64::from_str_radix(&str::replace(&out, "_", ""), 2), + )(input) +} + +fn decimal_number(input: &str) -> IResult<&str, i64> { + map_res( + recognize(many1(terminated(one_of("0123456789"), many0(char('_'))))), + |out: &str| i64::from_str_radix(&str::replace(&out, "_", ""), 10), + )(input) +} + +fn whitespace(i: &str) -> IResult<&str, &str> { + recognize(many0(one_of(" \n\t")))(i) +} + +// fn expect<'a, F, E, T>(parser: F, error_msg: E) -> impl Fn(&'a str) -> IResult, T> +// where +// F: Fn(&'a str) -> IResult, +// E: ToString, +// { +// move |input| match parser(input) { +// Ok((remaining, out)) => Ok((remaining, Some(out))), +// Err(nom::Err::Error((input, _))) | Err(nom::Err::Failure((input, _))) => { +// let err = Error(input.to_range(), error_msg.to_string()); +// input.extra.report_error(err); // Push error onto stack. +// Ok((input, None)) // Parsing failed, but keep going. +// } +// Err(err) => Err(err), +// } +// } diff --git a/compiler/src/parser/asm.rs b/compiler/src/parser/asm.rs new file mode 100644 index 0000000..58d0877 --- /dev/null +++ b/compiler/src/parser/asm.rs @@ -0,0 +1,20 @@ +use nom::{ + branch::alt, + bytes::complete::tag, + character::complete::{alphanumeric1, char, one_of}, + combinator::{map, map_res, recognize}, + multi::{many0, many1, separated_list0}, + sequence::{preceded, terminated, tuple}, + IResult, +}; + +pub enum Instruction { + Add(Operand, Operand, Operand), + Sub(Operand, Operand, Operand), + Beqz(Operand, Operand), +} + +pub enum Operand { + Direct(u8), + Identifier(String), +} diff --git a/doc/lbp/general_tips.md b/doc/lbp/general_tips.md new file mode 100644 index 0000000..f78d6fe --- /dev/null +++ b/doc/lbp/general_tips.md @@ -0,0 +1,7 @@ +https://web.archive.org/web/20160324052734/http://www.lbpcentral.com/forums/showthread.php?92215-Tips-and-Tricks + +Logic is counted TWICE on the thermo when sackboy is in the level so if you have a complicated chip, it might be best to use a sackbot. (I set the controliinator for that sackbot to a color channel as nearest player seems to lag for me in beta) + +How to adjust the camera WHILE creating or moving stuff around: Pause, go to settings and in the bottom you'll see an option called ''Create'' There you'll find ''Touch create mode'' Then you can set it to ''Camera'' and be able to zoom and move the camera around, no matter what you're doing! + +Faster travel in the editor: Use Oddsock or Swoop while creating, they're much faster at moving and hovering around ( Of course you'll need to change character to test in-editor ) diff --git a/doc/lbp/logic_research.md b/doc/lbp/logic_research.md new file mode 100644 index 0000000..3031431 --- /dev/null +++ b/doc/lbp/logic_research.md @@ -0,0 +1,63 @@ +(when a gate has multiple inputs, unless specified otherwise, the speed applies to all of the inputs) + + +# General + +For multiple inputs, dependencies are evaluated by the order they appear on the gate, top to bottom. + + +# Selector + +Cycle input is slow. It does not evaluate its dependencies early. +Other inputs are fast and behave as normal gates. + + +# Microchip + +(with one input and no outputs) +All inputs fast + +The activate input is checked before and independently of the regular inputs. + +Other inputs are then checked top-to-bottom + +Activation before other, older gates? No + +With inner microchips and no inputs/outputs -> tag propogration is instant [microchip_activation_0] + + +# Sequencer + +(with one input and no outputs) +All inputs fast + + +# Sackbot trick + +Converting analog to digital with a sackbot is instant. It can be done multiple times per frame and occurs during the same phase as logic gates. + +A sackbot uses about 1/250th of a thermometer (~4000 units). It has 16 inputs that can be used (~250 thermometer units per analog-to-digital conversion). + +The output can be on for two frames instead of the expected one. + + + +# Physics + +Activating a destroyer and a tag on an object in the same frame causes the tag sensor to not activate. + + +# Non-terminal components + +Timer: fast +Counter: fast +Toggle: fast +Randomiser: fast +Wave generator: fast + + +# Terminal components + +Emitter: slow +Tag: slow +Mover: slow diff --git a/doc/other/bittzy.png b/doc/other/bittzy.png new file mode 100644 index 0000000000000000000000000000000000000000..3133182299d1d818d3dbf85b2b0eb81ba186f497 GIT binary patch literal 73317 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 z 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 lw/sw/ld/sd xD, I(zero) + +_idea_ +Data instructions relative to PC +Test if having dedicated instructions for this is worth it as opposed to auipc + add + lw + +_idea_ +Prefetch instruction. Set a cache line to load for the next frame, but do not stop execution. +Execution could maybe even be allowed to continue while fetching from main memory over multiple frames. + +_idea_ +Push/pop multiple, maybe using ld/sd, e.g. push s01, pop a01 + +_idea_ +Push/pop aligned pseudo-instruction, e.g. `pusha x0, x1, x3, x5, x8` -> `pushd d0; push x3; push x5; push x8; addi sp, sp, -1` +Combines registers into doublewords when possible, and aligns `sp` to a multiple a of 2 if necessary. + + +# Branching instructions (11) + +110CCC AAAA DDDD IIII IIIIII | bC xA, xD, I ; compare xA and xD for condition C and branch to [pc + I] +111000 AAAA IIII IIII IIIIII | j [xA + I] ; jump to [xA + I] +111110 AAAA DDDD BBBB IIIIII | jalr xD, [xA + xB + I] ; jump to [xA + xB + I] and set xD to pc + 1 + +_idea_ +011CCC AAAA iiii iiII IIIIII | bC xA, i, I ; compare xA and immediate i for condition C and branch to [pc + I] + +11CCC AAAA DDD IIIIII IIIIII | bC xA, xD, I ; compare xA and xD for condition C and branch to [pc + I] +11110 AAAA 000 IIIIII IIIIII | blt xA, zero, I +11111 AAAA 000 IIIIII IIIIII | bge xA, zero, I +11110 AAAA 100 IIIIII IIIIII | j I(xA) ; jump to [xA + I] +11111 AAAA 100 BBB000 000000 | j xB(xA) ; jump to [xA + xB] + +; Conditions (C) + +000 | beq, equals +010 | bltu, less than unsigned +100 | blt, less than +110 | (unused) +001 | bne, not equals +011 | bgeu, greater than or equal unsigned +101 | bge, greater than or equal +111 | (unused) + +beq: Z==1 +bne: Z==0 +blt: N!=V +bltu: C==0 +bge: N==V +bgeu: C==1 + +; Pseudo-instructions + +b I => beq x0, x0, I +b xB => j xB(pc) +j xB => j xB(zero) +wfi => beq x0, x0, 0 + +bgt xD, xA, I => blt xA, xD, I +bgtu xD, xA, I => bltu xA, xD, I +ble xD, xA, I => bge xA, xD, I +bleu xD, xA, I => bgeu xA, xD, I + +beqz xD, I => beq zero, xD, I +bltz xD, I => blt xD, zero, I +bnez xD, I => bne zero, xD, I +bgez xD, I => bge xD, zero, I +bgtz xD, I => blt zero, xD, I +blez xD, I => bge zero, xD, I + + +# Interrupts + +Trigger interrupt input +Two (three?) input bits to select which interrupt vector to use. +Some maskable, some not maskable +Single line in memory holding all control values (interrupt vectors, interrupts enabled bit, pc, timers, cpuid) +Contains two value inputs, these can be read as special registers + +Timer interrupts? + + +# I/O + +Write to special memory line, send I/O out signal diff --git a/doc/parva/design.md b/doc/parva/design.md new file mode 100644 index 0000000..901750f --- /dev/null +++ b/doc/parva/design.md @@ -0,0 +1,23 @@ + + + +# L2 data cache + +Writeback scenarios: + +1. Normal: write L1-0 to L2-0, L1-1 to L2-1 +2. Swap: write L1-0 to L2-1, L1-1 to L2-0 +3. Normal miss: write L1-0 to L2-1, L1-1 to L2-2 +4. Swap miss: write L1-0 to L2-2, L1-1 to L2-1 + + +On miss: + +Check if requested line is in L2. If so, send a move signal to that position. + + +# L2 instruction cache + +Same as data cache but with no writeback functionality + +Must pre-emptively fetch the next line after the PC diff --git a/doc/parva/ideas.md b/doc/parva/ideas.md new file mode 100644 index 0000000..1db351d --- /dev/null +++ b/doc/parva/ideas.md @@ -0,0 +1,63 @@ +# Instruction set + +Load relative address: rd <- pc + imm + +Load immediate with 14-bit value + +Splat/merge: 24-bit value into two registers, 12 bits each, or four registers, 6 bits each. + +Branch if least significant bit is set. + +Branch, comparing to immediate. Can either be two immediates in the instruction, or make it a 48-bit instruction. + +Branch if equal / not equal to zero for doubleword registers, e.g. `beqz x01, target`. + +Multiply 12-bits + +Single-frame binary to decimal by chaining together the multiply/divide parts of different ALUs. + +String manipulation instructions: +Truncate after first null character, e.g. doubleword "abcde\0fg" -> "abcde\0\0\0" +Length of doubleword up to first null character, e.g. "abcde\0fg" -> 5 +Left-align / right-align strings. + +All cores can do 12-bit bitwise operations. 24-bit operations are done by two cores in sequence. + + +# Registers + +Some registers can be read by any core, but only written to by a single core. +This could be a separate `mv` instruction, so generally the desination operand is only three bits. + + +# Memory + +No direct write ability, writes are only performed by the CPU core. + +3-tier memory: looping memory, L2 cache of several lines, L1 cache of e.g. two lines passed through the CPU pipeline. + +If a loop memory writeback is still in progress and the eviction of another line is requested, the memory controller can select the least recently used line which isn't dirty and evict that instead. + + +# Branch prediction + +Split instructions into groups of 3/4. + +When a branch is taken, store the instruction group that is branched to along with the target address. +E.g. a branch to address 15, where at address 15 there are instructions A, B, C, will store [15, A, B, C] into the branch prediction part of the instruction pipeline. + +Only every third core (or some other number) can perform branching. The branch prediction values only need to be passed to these cores. +Other cores can still check for branching, but not actually execute it. + +Two predicted paths could be stored with prioritization. When the most recently taken one is taken, nothing happens. When the less recently taken one is taken, the two swap positions. When a new branch is taken, the less recently taken one is overwritten. + + +# Specialization + +Only certain cores can perform certain actions, e.g. division, bitwise operations. + +Some registers are fast-read, slow-write. They only implement writing logic in an instruction that can be executed by certain cores, maybe once per frame. All other cores can read from them. + +B core: take branches +A core: bitwise arithmetic +M core: 24-bit multiplcation / division diff --git a/programs/bitzzy/assembler_test b/programs/bitzzy/assembler_test new file mode 100644 index 0000000..78b40cc --- /dev/null +++ b/programs/bitzzy/assembler_test @@ -0,0 +1,184 @@ +$0: +hlt +ret +rti +eni +dsi +nop +rem x +rem y +rem z +clr + +$1: +jmp 5 +jmp 5, x +jmp 5, y +jmp 5, z +jsr 5 +jsr 5 +jsr 5, x +jsr 5, y +jsr 5, z +swp x, y +swp y,x +swp x,z +swp z,x +swp z,y +swp y,z + +$2: +jmpez x, 5 +jmpez z, 5 +jmpgt x,y, 5 +jmpeq x,y, 5 +jsrez x, 5 +jsrez z, 5 +jsrgt x, y, 5 +jsreq x, y, 5 +lod y, x +lod z, x +lod y, x +lod y, z +lod x, z +lod y, z + +$3: +inc x +inc y +inc z +inc 5 +dec x +dec y +dec z +dec 5 +sub x, #5 +sub y, #5 +sub z, #5 +div x, #5 +div y, #5 +div z, #5 + +$4: +add x, #5 +sub x, #5 +mul x, #5 +div x, #5 +add x, y +add x, z +sub x, y +sub x,z +mul x,y +mul x,z +div x,y +div x,z +mod x,y +mod x,z + +$5: +add y, #5 +sub y, #5 +mul y, #5 +div y, #5 +add y, z +sub y,x +sub y,z +mul y,z +div y,x +div y,z +mod y,x +mod y,z + +$6: +add z, #5 +sub z,#5 +mul z,#5 +div z,#5 +sub z,x +sub z,y +div z,x +div z,y +mod z,x +mod z,y + + +$7: +lsl x +lsl y +lsl z +lsr x +lsr y +lsr z +not x +not y +not z +lod x, #5 +lod y, #5 +lod z, #5 + +$8: +and x,y +and x,z +and y,z +xor x,z +xor x,y +xor y,z +or x,y +or x,z +or y,z + +$9: +and x, #5 +and y, #5 +and z, #5 + +or x, #5 +or y, #5 +or z, #5 + +xor x, #5 +xor y, #5 +xor z, #5 + +mod x, #5 +mod y, #5 +mod z, #5 + +$a: +lod x, 5 +lod x, 5, y +lod x, 5, z + + +$b: +lod y, 5 +lod y, 5, x +lod y, 5, z + +$c: +lod z, 5 +lod z, 5, x +lod z, 5, y +lod z, 5, yx + +$d: +str x, 5 +str x, 5, y +str x, 5, z + +str #5, 3, x +str #5, 3, y +str #5, 3, z +str #5, 3 + +$e: +str y, 5 +str y, 5, x +str y, 5, z + +$f: +str z, 5 +str z, 5, x +str z, 5, y +str z, 5, yx +str #5, 3, yx diff --git a/programs/parva_0.2/cat.parvalang b/programs/parva_0.2/cat.parvalang new file mode 100644 index 0000000..0b2f3d7 --- /dev/null +++ b/programs/parva_0.2/cat.parvalang @@ -0,0 +1,61 @@ +# cat + +.extern f_open, f_close, f_read, write +.string_encoding system + +main: # fn (args: [cstr8]) -> int + let argv = %a0; + let argc = %a1; + # mv s0, a0 + # push a1 + let arg_index = 0; + +arg_loop: + beq arg_index, argc, end; + let filename = lw [argv + arg_index]; + %a0 = filename; + call f_open + let fd = %a0; + bltz fd, error_open; + %a0 = fd; + call f_read; + let file_contents = %a0; + + +arg_loop: + lw t0, 1(sp) + beq s1, t0, end + lw a0, 0(s0) + call f_open # a0 = file descriptor + bltz a0, error_open + push a0 + call f_read # a0 = pointer to contents + bltz a0, error_read + mv a1, a0 + li a0, 1 # stdout + call write + pop a0 + call f_close + addi s1, s1, 1 + b arg_loop + +error_read: + pop zero + mv s0, a1 + call f_close + mv a1, s0 +error_open: + mv s0, a1 + li a0, 1 + li a1, error_message + call write + mv a1, s0 + call write + b end +end: + li a0, 0 + ret + +error_message: + .string "\fr" # color red + .string "Error: \0" diff --git a/programs/parva_0.2/file.parva b/programs/parva_0.2/file.parva new file mode 100644 index 0000000..cd2e6e0 --- /dev/null +++ b/programs/parva_0.2/file.parva @@ -0,0 +1,3 @@ +# file + + diff --git a/programs/parva_0.2/simd_ideas.parva b/programs/parva_0.2/simd_ideas.parva new file mode 100644 index 0000000..0caadba --- /dev/null +++ b/programs/parva_0.2/simd_ideas.parva @@ -0,0 +1,87 @@ + +# x8: pointer to current char in input string + +# I think supporting semi-fast unaligned reads is cheaper than having this alignment logic. + +# andi x0, x8, 0b11 +# li x1, 4 +# sub x0, x1, x0 +# add x0, x0, x0 +# addi x0, x0, 1 +# b x0 + +# lw x0, [x8 + 0] +# beq x0, x2, (split + 3) +# lw x0, [x8 + 1] +# beq x0, x2, (split + 2) +# lw x0, [x8 + 1] +# beq x0, x2, (split + 1) + +# Frame 1 + +loop_0: + +sw x8, [x9] +addi x9, x9, 1 + +li x2, ' ' + +lq x4:7, x8 +b loop_1_no_align + +loop_1: + +andi x8, x8, 0b11 + +# Frame 2 + +loop_1_no_align: + +vindexof.6 x0, x1, x4 +bgez x0, split +addi x8, x8, 1 +vindexof.6 x0, x1, x5 +bgez x0, split +addi x8, x8, 1 +vindexof.6 x0, x1, x6 +bgez x0, split +addi x8, x8, 1 +vindexof.6 x0, x1, x7 +bgez x0, split +addi x8, x8, 1 +b loop_1 + +# Frame 8 + +split: + +slli x1, x0, 2 +add x1, x1, x0 +add x1, x1, x0 +sll x1, x2, x1 +lw x0, [x8] +xor x0, x0, x1 + +addi x8, x8, 1 + +# etc. + + +# Frame 15 + +hash: + +li x0, 5381 + +lw x2, [x3] + +loop_2: + +slli x1, x0, 5 +add x0, x0, x1 +add x0, x0, x1 +addi x3, x3, 1 +lw x2, [x3] +andi x1, x2, 0b111111 +bnez x1, loop_2 + diff --git a/programs/parva_0.2/split_args b/programs/parva_0.2/split_args new file mode 100644 index 0000000..2b6c8a5 --- /dev/null +++ b/programs/parva_0.2/split_args @@ -0,0 +1,45 @@ + +let input_string: *word; + + +let space: char; +li space, ' '; + +let parts: quad; +lq parts, input_string; + +b loop_1_no_align + +loop_1: + +andi input_string, input_string, 0b11 + +# Frame 2 + +loop_1_no_align: + +vindexof.6 x0, x1, x4 +bgez x0, split +addi x8, x8, 1 +vindexof.6 x0, x1, x5 +bgez x0, split +addi x8, x8, 1 +vindexof.6 x0, x1, x6 +bgez x0, split +addi x8, x8, 1 +vindexof.6 x0, x1, x7 +bgez x0, split +addi x8, x8, 1 +b loop_1 + +# Frame 8 + +split: + +@mul char_index, 6 +sll x1, x2, x1 +lw x0, [x8] +xor x0, x0, x1 + +addi x8, x8, 1 + diff --git a/programs/parva_0.2/tetris.parva b/programs/parva_0.2/tetris.parva new file mode 100644 index 0000000..33aafad --- /dev/null +++ b/programs/parva_0.2/tetris.parva @@ -0,0 +1,189 @@ +.arch parva_0_1 + +# 1(sp): score +# 2(sp): swap_block + +# x4: block lines 0/1 +# x5: block lines 2/3 +# x6: field lines 0/1 +# x7: field lines 2/3 + +.include consts +.include sys + +.string_encoding sys-6 + + +.data.ro + +srs_kick_table: +# XY, 0 = 0, 1 = +1, 2 = +2, 7 = -1, 6 = -2 +# I block +0o60_10_67_12 +0o70_20_72_27 +# TODO +# J, L, T, S, Z blocks +0o70_71_06_76 +0o10_17_02_12 +# TODO + +block_table: +# I 0 +0b_0_0000_000000_0_0_1111_000000_0 +0b_0_1111_000000_0_0_0000_000000_0 +# I 1 +0b_0_0010_000000_0_0_0010_000000_0 +0b_0_0010_000000_0_0_0010_000000_0 +# TODO + +hi_score_filename: .string "tet_hiscr.dat\0" +hi_score_file_error_message: .string .line_break 10 "could not open or create hi score file\0" +score_string: .string "score\0" +game_over_string: .string "game over\0" +.scores_button_string: .string "scores\0" +.start_button_string: .string "start\0" +.next_string: .string "next\0" + +.data.rw + +.align const.cache_line_size +swap_block: 0 +score: 0 +next_air_drop_time: 0 +next_floor_drop_time: 0 +stack: .repeat 0, 20 + +hi_scores: +.repeat 0, 20 + +.eq score_string_x 30 +.eq score_string_y 10 + + +.text + +_start: + +push ra + +load_hi_scores: + +li a0, hi_score_filename +li a1, hi_scores +li x0, 20 +call sys.read_file +li x0, -1 +beq a0, x0, create_hi_score_file + +create_hi_score_file: + +li a0, hi_score_filename +call sys.open_file + +bltz a0, error_hi_score_file + +wait: + +wait_loop: + +stub.kb.rdchar x0 + +beqi x0, const.char.left_arrow, move_left +beqi x0, const.char.right_arrow, move_right +beqi x0, const.char.up_arrow, rotate +beqi x0, const.char.space, hard_drop +beqi x0, const.char.backspace, swap + +b wait_loop + +rotate: + +# x2 = current pos / block / rotation, [0 * 8, 4 bits for position x, 0 * 7, 3 bits for block type, 2 bits for rotation] + +addi x3, x2, 1 +andi x3, x3, 0b00011 +andi x2, x2, 0b11100 +or x2, x2, x3 +ld d0, [x2 + block_table] + + +.align 4 +move_left: + +slli x0, x4, 1 +and x0, x0, x6 +bnez x0, fail +slli x0, x5, 1 +and x0, x0, x7 +bnez x0, fail + +slli x4, x4, 1 +slli x5, x5, 1 +b move_successful + +.align 4 +move_right: + +srli x0, x4, 1 +and x0, x0, x6 +bnez x0, fail +srli x0, x5, 1 +and x0, x0, x7 +bnez x0, fail + +srli x4, x4, 1 +srli x5, x5, 1 +b move_successful + +move_failed: + +# TODO + +move_successful: + +# TODO + +# decimal addition +# input: x0 = score change +.align 2 +add_score: + +lw x1, score +add x0, x0, x1 +li x1, 0o1166 +and x2, x0, 0o77 +li x3, 10 +blt x2, x3, 2 + +add x0, x0, x1 +slli x1, x1, 6 +srli x2, x0, 6 +andi x2, x0, 0o77 +blt x2, x3, end_score_change +add x0, x0, x1 + +slli x1, x1, 6 +srli x2, x0, 6 +andi x2, x0, 0o77 +blt x2, x3, end_score_change +add x0, x0, x1 +slli x1, x1, 6 + +srli x2 x0, 6 +andi x2, x0, 0o77 +blt x2, x3, end_score_change +add x0, x0, x1 + +.align 2 +end_score_change: + +sw x0, score + + + + +quit: + + + +pop ra