diff --git a/presets/arm32/crt0.c b/presets/arm32/crt0.c deleted file mode 100644 index a8276119..00000000 --- a/presets/arm32/crt0.c +++ /dev/null @@ -1,9 +0,0 @@ - -int main(); - -void _start() { - asm("mov sp, #0x100000"); // stack pointer - main(); - asm(".long 0xdeadc0d3"); -} - diff --git a/presets/arm32/vidfill.c b/presets/arm32/vidfill.c index 9b725230..a5dd23ff 100644 --- a/presets/arm32/vidfill.c +++ b/presets/arm32/vidfill.c @@ -1,6 +1,4 @@ -//#link "crt0.c" - const char const str[] = "HELLO WORLD!"; int global = 0x1234; diff --git a/src/common/binutils.ts b/src/common/binutils.ts index c5b96c3f..5cebb460 100644 --- a/src/common/binutils.ts +++ b/src/common/binutils.ts @@ -1,4 +1,24 @@ - +/* + * Copyright (c) 2024 Steven E. Hugg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ function getASCII(view: DataView, offset: number): string { let s = ''; diff --git a/src/common/cpu/ARM.ts b/src/common/cpu/ARM.ts index 98da492c..361b8e45 100644 --- a/src/common/cpu/ARM.ts +++ b/src/common/cpu/ARM.ts @@ -3555,6 +3555,11 @@ ARMCore.prototype.compileArm = function(instruction) { var load = instruction & 0x00100000; var b = instruction & 0x00400000; var i = instruction & 0x02000000; + // test for UDF instruction + if ((instruction & 0xfff000f0) == (0xe7f000f0|0)) { + var immediate = instruction & 0x0000000f; // TODO: full range + throw new EmuHalt("Program exited (" + immediate + ")"); + } var address : AddressFunction = function() { throw new EmuHalt("Unimplemented memory access: 0x" + instruction.toString(16)); diff --git a/src/common/wasi/wasishim.ts b/src/common/wasi/wasishim.ts index bec8bd23..f4750795 100644 --- a/src/common/wasi/wasishim.ts +++ b/src/common/wasi/wasishim.ts @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2024 Steven E. Hugg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ // https://dev.to/ndesmic/building-a-minimal-wasi-polyfill-for-browsers-4nel // http://www.wasmtutor.com/webassembly-barebones-wasi @@ -154,7 +175,7 @@ export enum WASIErrors { export class WASIFileDescriptor { fdindex: number = -1; - data: Uint8Array = new Uint8Array(16); + protected data: Uint8Array = new Uint8Array(16); flags: number = 0; size: number = 0; offset: number = 0; @@ -224,6 +245,8 @@ class WASIStreamingFileDescriptor extends WASIFileDescriptor { export interface WASIFilesystem { getFile(name: string) : WASIFileDescriptor; + getFiles() : WASIFileDescriptor[]; + getDirectories() : WASIFileDescriptor[]; } export class WASIMemoryFilesystem implements WASIFilesystem { @@ -239,6 +262,13 @@ export class WASIMemoryFilesystem implements WASIFilesystem { } putDirectory(name: string, rights?: number) { if (!rights) rights = FDRights.PATH_OPEN | FDRights.PATH_CREATE_DIRECTORY | FDRights.PATH_CREATE_FILE; + if (name != '/' && name.endsWith('/')) name = name.substring(0, name.length - 1); + // add parent directory(s) + const parent = name.substring(0, name.lastIndexOf('/')); + if (parent && parent != name) { + this.putDirectory(parent, rights); + } + // add directory const dir = new WASIFileDescriptor(name, FDType.DIRECTORY, rights); this.dirs.set(name, dir); return dir; @@ -261,6 +291,12 @@ export class WASIMemoryFilesystem implements WASIFilesystem { } return file; } + getDirectories() { + return [...this.dirs.values()]; + } + getFiles() { + return [...this.files.values()]; + } } export class WASIRunner { diff --git a/src/ide/views/debugviews.ts b/src/ide/views/debugviews.ts index a7a72625..089d2691 100644 --- a/src/ide/views/debugviews.ts +++ b/src/ide/views/debugviews.ts @@ -23,8 +23,8 @@ export class MemoryView implements ProjectView { dumplines; maindiv : HTMLElement; recreateOnResize = true; - hibits = 0; - totalRows = 0x1400; + hibits = 0; // a hack to make it work with 32-bit addresses + totalRows = 0x1400; // a little more room in case we split lots of lines createDiv(parent : HTMLElement) { var div = document.createElement('div'); @@ -45,7 +45,7 @@ export class MemoryView implements ProjectView { var linediv = document.createElement("div"); if (this.dumplines) { var dlr = this.dumplines[row]; - if (dlr) linediv.classList.add('seg_' + this.getMemorySegment(this.dumplines[row].a)); + if (dlr) linediv.classList.add('seg_' + this.getMemorySegment(this.dumplines[row].a | this.hibits)); } linediv.appendChild(document.createTextNode(s)); return linediv; @@ -60,7 +60,8 @@ export class MemoryView implements ProjectView { scrollToAddress(addr : number) { if (this.dumplines) { - this.memorylist.scrollToItem(this.findMemoryWindowLine(addr)); + this.hibits = addr & 0xffff0000; + this.memorylist.scrollToItem(this.findMemoryWindowLine(addr & 0xffff)); } } @@ -131,7 +132,7 @@ export class MemoryView implements ProjectView { var sym; for (const _nextofs of Object.keys(addr2sym)) { var nextofs = parseInt(_nextofs); // convert from string (stupid JS) - var nextsym = addr2sym[nextofs]; + var nextsym = addr2sym[nextofs | this.hibits]; if (sym) { // ignore certain symbols if (ignoreSymbol(sym)) { @@ -280,8 +281,7 @@ export class MemoryMapView implements ProjectView { segdiv.click(() => { // TODO: what if memory browser does not exist? var memview = projectWindows.createOrShow('#memory') as MemoryView; - memview.hibits = seg.start & 0xffff0000; - memview.scrollToAddress(seg.start & 0xffff); + memview.scrollToAddress(seg.start); }); } diff --git a/src/machine/arm32.ts b/src/machine/arm32.ts index c2af5ca3..538b40db 100644 --- a/src/machine/arm32.ts +++ b/src/machine/arm32.ts @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2024 Steven E. Hugg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import { ARM32CPU, ARMCoreState } from "../common/cpu/ARM"; import { BasicScanlineMachine, Bus32, HasSerialIO, SerialEvent, SerialIOInterface } from "../common/devices"; diff --git a/src/platform/arm32.ts b/src/platform/arm32.ts index 5f5e637d..4a593e71 100644 --- a/src/platform/arm32.ts +++ b/src/platform/arm32.ts @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2024 Steven E. Hugg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import { Platform, DisasmLine, Machine, BaseMachinePlatform } from "../common/baseplatform"; import { PLATFORMS } from "../common/emu"; diff --git a/src/test/testelfparser.ts b/src/test/testelfparser.ts index 22229820..e2517533 100644 --- a/src/test/testelfparser.ts +++ b/src/test/testelfparser.ts @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2024 Steven E. Hugg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + import assert from "assert"; import { DWARFParser, ELFParser } from "../common/binutils"; diff --git a/src/worker/fs/arm32-fs.zip b/src/worker/fs/arm32-fs.zip new file mode 100644 index 00000000..49cb5161 Binary files /dev/null and b/src/worker/fs/arm32-fs.zip differ diff --git a/src/worker/lib/arm32/arm-tcc.o b/src/worker/lib/arm32/arm-tcc.o deleted file mode 100644 index e967251d..00000000 Binary files a/src/worker/lib/arm32/arm-tcc.o and /dev/null differ diff --git a/src/worker/lib/arm32/crt0.c b/src/worker/lib/arm32/crt0.c new file mode 100644 index 00000000..049b8275 --- /dev/null +++ b/src/worker/lib/arm32/crt0.c @@ -0,0 +1,15 @@ + +int entry(); + +__attribute__((weak, naked, noinline, noreturn)) void _start() { + asm(".global __bss_start__, __bss_end__"); + asm("__bss_start__ = _edata"); + asm("__bss_end__ = _end"); + asm("mov sp, #0x100000"); // stack pointer + entry(); + asm(".long 0xe7f000f0"); // udf #0 +} + +void _Exit(int ec) { + asm(".long 0xe7f000f0"); // udf #0 +} diff --git a/src/worker/lib/arm32/libc.a b/src/worker/lib/arm32/libc.a new file mode 100644 index 00000000..9c7553d3 Binary files /dev/null and b/src/worker/lib/arm32/libc.a differ diff --git a/src/worker/platforms.ts b/src/worker/platforms.ts index f945f684..12a5a384 100644 --- a/src/worker/platforms.ts +++ b/src/worker/platforms.ts @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2024 Steven E. Hugg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ export var PLATFORM_PARAMS = { 'vcs': { @@ -336,8 +357,11 @@ export var PLATFORM_PARAMS = { }, 'arm32': { arch: 'arm32', - define: ['__ARM__'], - extra_link_files: ['arm-tcc.o', 'arm-libtcc1.a'], + define: ['__ARM__', 'DISABLE_UNIMPLEMENTED_LIBC_APIS', 'PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT'], + extra_compile_args: ['-I./arch/arm/include', '-I./openlibm/include', '-I./openlibm/src', '-I./printf/src'], + extra_link_files: ['crt0.c', 'arm-libtcc1.a', 'libc.a'], + extra_link_args: ['arm-libtcc1.a', 'libc.a'], + crt0: 'crt0.c', }, }; diff --git a/src/worker/tools/arm.ts b/src/worker/tools/arm.ts index 0d2ef63d..be231230 100644 --- a/src/worker/tools/arm.ts +++ b/src/worker/tools/arm.ts @@ -1,9 +1,32 @@ +/* + * Copyright (c) 2024 Steven E. Hugg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import { ELFParser } from "../../common/binutils"; import { hex } from "../../common/util"; +import { WASIFilesystem } from "../../common/wasi/wasishim"; import { CodeListingMap, SourceLine, WorkerError, WorkerResult } from "../../common/workertypes"; import { BuildStep, BuildStepResult, gatherFiles, staleFiles, populateFiles, putWorkFile, anyTargetChanged, getPrefix, getWorkFileAsString, populateExtraFiles } from "../builder"; import { makeErrorMatcher, re_crlf } from "../listingutils"; +import { loadWASIFilesystemZip } from "../wasiutils"; import { loadNative, moduleInstFn, execMain, emglobal, EmscriptenModule } from "../wasmutils"; export function assembleARMIPS(step: BuildStep): WorkerResult { @@ -241,9 +264,11 @@ export function assembleVASMARM(step: BuildStep): BuildStepResult { } function tccErrorMatcher(errors: WorkerError[], mainpath: string) { - return makeErrorMatcher(errors, /(\w+|tcc):(\d+|\s*error): (.+)/, 2, 3, mainpath, 1);; + return makeErrorMatcher(errors, /([^:]+|tcc):(\d+|\s*error): (.+)/, 2, 3, mainpath, 1);; } +let armtcc_fs: WASIFilesystem | null = null; + export async function compileARMTCC(step: BuildStep): Promise { loadNative("arm-tcc"); const params = step.params; @@ -252,6 +277,10 @@ export async function compileARMTCC(step: BuildStep): Promise { const objpath = step.prefix + ".o"; const error_fn = tccErrorMatcher(errors, step.path); + if (!armtcc_fs) { + armtcc_fs = await loadWASIFilesystemZip("arm32-fs.zip"); + } + if (staleFiles(step, [objpath])) { const armtcc: EmscriptenModule = await emglobal.armtcc({ instantiateWasm: moduleInstFn('arm-tcc'), @@ -260,7 +289,7 @@ export async function compileARMTCC(step: BuildStep): Promise { printErr: error_fn, }); - var args = ['-I.', '-c', + var args = ['-c', '-I.', '-I./include', //'-std=c11', '-funsigned-char', '-Wwrite-strings', @@ -269,10 +298,21 @@ export async function compileARMTCC(step: BuildStep): Promise { if (params.define) { params.define.forEach((x) => args.push('-D' + x)); } + if (params.extra_compile_args) { + args = args.concat(params.extra_compile_args); + } args.push(step.path); const FS = armtcc.FS; + // TODO: only should do once? + armtcc_fs.getDirectories().forEach((dir) => { + if (dir.name != '/') FS.mkdir(dir.name); + }); + armtcc_fs.getFiles().forEach((file) => { + FS.writeFile(file.name, file.getBytes(), { encoding: 'binary' }); + }); populateExtraFiles(step, FS, params.extra_compile_files); + populateFiles(step, FS); execMain(step, armtcc, args); if (errors.length) @@ -312,18 +352,14 @@ export async function linkARMTCC(step: BuildStep): Promise { if (params.define) { params.define.forEach((x) => args.push('-D' + x)); } - let objfiles = step.files; - // sort so that crtxxx files are first - objfiles.sort((a, b) => { - let a0 = a.startsWith('crt') ? 0 : 1; - let b0 = b.startsWith('crt') ? 0 : 1; - a = a0 + a; - b = b0 + b; - return a.localeCompare(b); - }); - args = args.concat(objfiles); - args.push('arm-libtcc1.a'); - + if (params.crt0) { + args.push(params.crt0); + } + args = args.concat(step.files); + if (params.extra_link_args) { + args = args.concat(params.extra_link_args); + } + const FS = armtcc.FS; populateExtraFiles(step, FS, params.extra_link_files); populateFiles(step, FS); @@ -346,7 +382,7 @@ export async function linkARMTCC(step: BuildStep): Promise { elfparser.sectionHeaders.forEach((section, index) => { if (section.flags & 0x2) { let data = objout.slice(section.offset, section.offset + section.size); - console.log(section.name, section.vmaddr.toString(16), data); + //console.log(section.name, section.vmaddr.toString(16), data); rom.set(data, section.vmaddr); } });