├── .gitattributes ├── .github └── workflows │ ├── make-docs.yml │ └── nightly.yml ├── .gitignore ├── .gitmodules ├── .vscode ├── launch.json └── settings.json ├── .zpm ├── pkgs.zig └── project.zpm ├── LICENSE ├── README.md ├── apps ├── ascii-printer │ └── main.asm ├── ashet-bios │ ├── main.asm │ └── main.old.asm ├── hello-world │ └── main.asm ├── library │ ├── ascii.inc │ ├── ashet │ │ ├── io-page.inc │ │ └── syscalls.inc │ └── bios.inc ├── minimal-firmware │ └── firmware.asm ├── minimal │ └── main.asm └── web-firmware │ ├── demo.asm │ └── main.asm ├── build.zig ├── castle.bin ├── documentation ├── app-notes │ ├── AN000 - Understanding the Instruction Set.md │ ├── AN001 - The SPU Assembly Language.md │ ├── AN002 - Standard Calling Convention.md │ └── AN003 - Writing efficient code.md ├── design │ ├── spu-mk-ii-logo-large.png │ ├── spu-mk-ii-logo-small.png │ ├── spu-mk-ii-logo.svg │ └── spu-mk-ii-logo.txt ├── figures │ ├── fr.svg │ ├── genbits.lua │ ├── instruction.svg │ └── ir.svg ├── index.md ├── livedemo.md ├── manuals │ ├── ashet-emulator.md │ ├── assembler.md │ ├── basic-emulator.md │ └── disassembler.md ├── metadata │ ├── an000.yaml │ ├── an001.yaml │ ├── an002.yaml │ ├── an003.yaml │ ├── ashet.yaml │ ├── isa.yaml │ ├── mmu.yaml │ ├── vchip.yaml │ └── vga.yaml ├── os │ ├── boot.md │ ├── index.md │ ├── syscalls.md │ └── ui.uxf ├── specs │ ├── ashet-register-space.md │ ├── ashet.md │ ├── dma.md │ ├── eth.md │ ├── ide.md │ ├── irq.md │ ├── joystick.md │ ├── mmu.md │ ├── parport.md │ ├── pcm.md │ ├── ps2.md │ ├── rtc.md │ ├── spu-mark-ii.md │ ├── timer.md │ ├── uart.md │ └── vga.md └── website │ ├── downloads.md │ ├── imprint.htm │ └── privacy.htm ├── mkdocs.yml ├── research-chamber ├── .gitignore ├── build.zig ├── libs │ └── lpc1768 │ │ └── lpc1768.zig └── src │ ├── boot.zig │ ├── linker.ld │ └── main.zig ├── resources ├── castle.bit ├── castle.pcx ├── example.bit ├── example.png └── keen.pcx ├── scratchpad └── scratch.asm ├── soc ├── architecture.uxf └── vhdl │ ├── ._Real_._Math_.vhd │ ├── .floorplanner.ini │ ├── .gitignore │ ├── .ncd_editor.ini │ ├── .setting.ini │ ├── .spread_sheet.ini │ ├── .spreadsheet_view.ini │ ├── env.sh │ ├── execve-trace.txt │ ├── firmware.mem │ ├── ip-cores │ ├── ._Real_._Math_.vhd │ ├── dist_boot_rom.edn │ ├── dist_boot_rom.ipx │ ├── dist_boot_rom.jhd │ ├── dist_boot_rom.lpc │ ├── dist_boot_rom.naf │ ├── dist_boot_rom.sym │ ├── dist_boot_rom.vhd │ ├── dist_boot_rom_tmpl.vhd │ ├── embedded_function_block.edn │ ├── embedded_function_block.ipx │ ├── embedded_function_block.jhd │ ├── embedded_function_block.lpc │ ├── embedded_function_block.naf │ ├── embedded_function_block.sym │ ├── embedded_function_block.vhd │ ├── embedded_function_block_tmpl.vhd │ ├── fastram_ebr.edn │ ├── fastram_ebr.ipx │ ├── fastram_ebr.jhd │ ├── fastram_ebr.lpc │ ├── fastram_ebr.naf │ ├── fastram_ebr.sym │ ├── fastram_ebr.vhd │ ├── fastram_ebr_tmpl.vhd │ ├── hw_mult_16.edn │ ├── hw_mult_16.ipx │ ├── hw_mult_16.jhd │ ├── hw_mult_16.lpc │ ├── hw_mult_16.naf │ ├── hw_mult_16.sym │ ├── hw_mult_16.vhd │ ├── hw_mult_16_tmpl.vhd │ ├── tb_boot_rom_tmpl.vhd │ ├── tb_dist_boot_rom_tmpl.vhd │ ├── tb_fastram_ebr_tmpl.vhd │ ├── tb_hw_mult_16_tmpl.vhd │ ├── tb_vga_ram_tmpl.vhd │ ├── tb_videoram_tmpl.vhd │ ├── vga_pll.edn │ ├── vga_pll.ipx │ ├── vga_pll.jhd │ ├── vga_pll.lpc │ ├── vga_pll.naf │ ├── vga_pll.sym │ ├── vga_pll.vhd │ ├── vga_pll_tmpl.vhd │ ├── videoram.edn │ ├── videoram.ipx │ ├── videoram.jhd │ ├── videoram.lpc │ ├── videoram.naf │ ├── videoram.sym │ ├── videoram.vhd │ └── videoram_tmpl.vhd │ ├── programmer-conf.xcf │ ├── simu │ ├── .gitignore │ ├── Makefile │ ├── ip-cores │ │ └── fastram_ebr.vhd │ └── spu.gtkw │ ├── spumark2.ldf │ ├── spumark2.lpf │ ├── src │ ├── builtin-rom.vhd │ ├── cpu.vhd │ ├── cpu_types.vhd │ ├── debug-port-in.vhd │ ├── debug-port-out.vhd │ ├── fastram.vhd │ ├── fifo.vhd │ ├── mmu.vhd │ ├── register-ram.vhd │ ├── rom.vhd │ ├── root.vhd │ ├── serial-port.vhd │ ├── soc.vhd │ ├── sram-controller.vhd │ ├── uart_receiver.vhd │ ├── uart_sender.vhd │ └── vga.vhd │ └── testbench.gtkw ├── specification ├── README.md ├── device_map.lua ├── devices │ ├── irq.lua │ └── uart.lua ├── gen-gpio-pins.lua ├── gen-register-space.lua ├── modules │ ├── Database.lua │ ├── Datasheet.lua │ └── Peripherial.lua └── render-documents.lua ├── tasks ├── README.md ├── build-website.sh └── run-basic-emulator.sh ├── test ├── README.md └── include.inc ├── todo.md ├── tools ├── assembler │ ├── main.zig │ └── mnemonics.zig ├── bit-loader │ ├── main.zig │ └── pcx.zig ├── common │ ├── spu-2.h │ ├── spu-mk2.zig │ └── vt100.h ├── disassembler │ └── main.zig ├── emulator │ ├── pc-main.zig │ ├── shared.zig │ └── web-main.zig ├── hex2bin │ └── main.zig └── vscode-ext │ ├── .eslintrc.json │ ├── .gitignore │ ├── .vscodeignore │ ├── CHANGELOG.md │ ├── README.md │ ├── language-configuration.json │ ├── out │ ├── main.js │ └── main.js.map │ ├── package-lock.json │ ├── package.json │ ├── render-mnemonics.zig │ ├── src │ ├── extension.js │ └── mnemonics.js │ ├── syntaxes │ └── asm.tmLanguage.json │ ├── update-mnemonics-js.sh │ └── vsc-extension-quickstart.md └── website ├── Makefile ├── livedemo.js ├── xterm ├── xterm.css └── xterm.js └── zip.py /.gitattributes: -------------------------------------------------------------------------------- 1 | *.zig text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/workflows/make-docs.yml: -------------------------------------------------------------------------------- 1 | name: Autogenerate Docs 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | with: 14 | submodules: "recursive" 15 | 16 | - name: Setup Python 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: '3.7' 20 | architecture: 'x64' 21 | 22 | - name: Install dependencies 23 | run: | 24 | python3 -m pip install --upgrade pip # install pip 25 | python3 -m pip install mkdocs # install mkdocs 26 | python3 -m pip install mkdocs-material # install material theme 27 | 28 | - name: Setup Zig 29 | uses: goto-bus-stop/setup-zig@v1 30 | with: 31 | version: master 32 | 33 | - name: Compile wasm emulator 34 | run: | 35 | mkdir -p zig-out/bin 36 | mkdir -p zig-out/firmware 37 | zig build wasm 38 | 39 | - name: Render site 40 | run: mkdocs build 41 | 42 | - name: Add static files 43 | run: cp -r website/* website-out/livedemo/ 44 | 45 | - name: Add emulator 46 | run: cp zig-out/lib/emulator.wasm website-out/livedemo/emulator.wasm 47 | 48 | # - name: Deploy to Server 49 | # uses: easingthemes/ssh-deploy@v2.1.1 50 | # env: 51 | # SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_KEY }} 52 | # ARGS: "-rltgoDzvO --delete" 53 | # SOURCE: "website-out/" 54 | # REMOTE_HOST: ${{ secrets.DEPLOY_HOST }} 55 | # REMOTE_USER: ${{ secrets.DEPLOY_USERNAME }} 56 | # TARGET: "/home/${{ secrets.DEPLOY_USERNAME }}/website" 57 | 58 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Build 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | schedule: 9 | - cron: "0 5 * * *" # run at 5 AM UTC 10 | 11 | jobs: 12 | build-linux: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | with: 18 | submodules: "recursive" 19 | 20 | - name: Install dependencies 21 | run: | 22 | sudo apt-get update 23 | sudo apt-get install --fix-missing libsdl2-dev libsdl2-image-dev 24 | 25 | - name: Setup Zig 26 | uses: goto-bus-stop/setup-zig@v1 27 | with: 28 | version: master 29 | 30 | - name: Build all software 31 | run: | 32 | mkdir -p zig-out/bin 33 | mkdir -p zig-out/firmware 34 | zig build install 35 | 36 | - name: Run Testsuite 37 | run: zig build test 38 | 39 | - name: Build firmware 40 | run: zig build firmware -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.elf 3 | *.hex 4 | *.exe 5 | zig-cache 6 | build/ 7 | zig-out/ 8 | website-out/ 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tools/modules/zig-args"] 2 | path = tools/modules/zig-args 3 | url = https://github.com/masterQ32/zig-args 4 | [submodule "tools/modules/zig-ihex"] 5 | path = tools/modules/zig-ihex 6 | url = https://github.com/MasterQ32/zig-ihex 7 | [submodule "tools/modules/zig-serial"] 8 | path = tools/modules/zig-serial 9 | url = https://github.com/MasterQ32/zig-serial 10 | [submodule "tools/modules/SDL.zig"] 11 | path = tools/modules/SDL.zig 12 | url = https://github.com/MasterQ32/SDL.zig 13 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}/tools/vscode-ext", 14 | "${workspaceFolder}/apps/firmware/main.asm" 15 | ] 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.useTabStops": false 3 | } -------------------------------------------------------------------------------- /.zpm/pkgs.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | fn pkgRoot() []const u8 { 4 | return std.fs.path.dirname(@src().file) orelse "."; 5 | } 6 | 7 | pub const pkgs = struct { 8 | pub const ihex = std.build.Pkg{ 9 | .name = "ihex", 10 | .path = .{ .path = pkgRoot() ++ "/../.zpm/../tools/modules/zig-ihex/ihex.zig" }, 11 | .dependencies = &[_]std.build.Pkg{}, 12 | }; 13 | pub const serial = std.build.Pkg{ 14 | .name = "serial", 15 | .path = .{ .path = pkgRoot() ++ "/../.zpm/../tools/modules/zig-serial/serial.zig" }, 16 | .dependencies = &[_]std.build.Pkg{}, 17 | }; 18 | pub const @"spu-mk2" = std.build.Pkg{ 19 | .name = "spu-mk2", 20 | .path = .{ .path = pkgRoot() ++ "/../.zpm/../tools/common/spu-mk2.zig" }, 21 | .dependencies = &[_]std.build.Pkg{}, 22 | }; 23 | pub const sdl2 = std.build.Pkg{ 24 | .name = "sdl2", 25 | .path = .{ .path = pkgRoot() ++ "/../.zpm/../tools/modules/SDL.zig/src/lib.zig" }, 26 | .dependencies = &[_]std.build.Pkg{}, 27 | }; 28 | pub const args = std.build.Pkg{ 29 | .name = "args", 30 | .path = .{ .path = pkgRoot() ++ "/../tools/modules/zig-args/args.zig" }, 31 | .dependencies = &[_]std.build.Pkg{}, 32 | }; 33 | }; 34 | 35 | pub const imports = struct { 36 | }; 37 | -------------------------------------------------------------------------------- /.zpm/project.zpm: -------------------------------------------------------------------------------- 1 | [ihex] 2 | file = ../tools/modules/zig-ihex/ihex.zig 3 | 4 | [serial] 5 | file = ../tools/modules/zig-serial/serial.zig 6 | 7 | [spu-mk2] 8 | file = ../tools/common/spu-mk2.zig 9 | 10 | [sdl2] 11 | file = ../tools/modules/SDL.zig/src/lib.zig 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Felix "xq" Queißner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The SPU Mark II Project 2 | 3 | A project that focuses on the development and improvement of the *SPU Mark II* instruction 4 | set architecture. 5 | 6 | Another focus is development and creation of a concrete implementation of the CPU in VHDL 7 | as well as building a small "home computer" around an FPGA board similar to other computers 8 | from the 80ies. 9 | 10 | ## SPU Mark II 11 | 12 | 13 | 14 | The SPU Mark II is a 16 bit *RISC*ish cpu that uses the [stack machine](https://en.wikipedia.org/wiki/Stack_machine) 15 | approach instead of a [register machine](https://en.wikipedia.org/wiki/Register_machine) approach. 16 | 17 | The instrution set is documented in [documentation/isa.md](documentation/isa.md). 18 | 19 | Short feature list: 20 | - Highly flexible instruction set 21 | - Conditional instructions instead of special conditional jumps or movs 22 | - Optional hardware multiplication/division units (WIP) 23 | - Optional interrupt handling (WIP) 24 | 25 | To get a feel for the instruction set, here's a small example for a `void puts(char*str)` function: 26 | 27 | ```asm 28 | puts: 29 | bpget ; function prologue 30 | spget 31 | bpset 32 | 33 | get 2 ; fetch arg 1 34 | puts_loop: 35 | ld8 [i0:peek] [f:yes] 36 | [ex:nonzero] st8 0x4000 ; Use MMIO for text output 37 | [ex:nonzero] add 1 38 | [ex:nonzero] jmp puts_loop 39 | pop 40 | 41 | bpget ; function epilogue 42 | spset 43 | bpset 44 | ret 45 | ``` 46 | 47 | ## Ashet Home Computer 48 | The *Ashet Home Computer* is a computer built on top of the *SPU Mark II* cpu and 49 | provides a small environment to use the cpu. 50 | 51 | ### Planned Features 52 | - [MMU](documentation/specs/mmu.md) 53 | - Video Output (either FBAS or VGA) 54 | - Audio Output (signed 16 bit PCM) 55 | - SD Card Storage 56 | - Keyboard Interface 57 | - Joystick Port (C64 style) 58 | - UART interface 59 | 60 | ### Current Memory Map 61 | 62 | Note that this memory map right now does not utilize the MMU, so bus width is 16 bit. 63 | 64 | | Range | Function | 65 | |---------------------|--------------------| 66 | | `0x0000` … `0x3FFF` | Builtin ROM | 67 | | `0x4000` … `0x4FFF` | UART Interface | 68 | | `0x6000` … `0x60FF` | 256 byte fast RAM | 69 | | `0x6100` … `0x7FFF` | *Unmapped* | 70 | | `0x8000` … `0xFFFF` | 32k byte slow RAM | 71 | -------------------------------------------------------------------------------- /apps/ascii-printer/main.asm: -------------------------------------------------------------------------------- 1 | ; Example application 2 | ; Repeatedly prints the values between 0x20 and 0x7F to the 3 | ; serial port 4 | 5 | .include "../library/bios.inc" 6 | 7 | .org APP_START 8 | st UART_TXD, '!' 9 | push 'A' 10 | loop: 11 | st UART_RXD [i1:peek] 12 | add 1 13 | 14 | cmp [i0:peek] 0x80 15 | [ex:zero] push ' ' [i1:pop] 16 | [ex:zero] st UART_TXD, '\r' 17 | [ex:zero] st UART_TXD, '\n' 18 | jmp loop 19 | end: -------------------------------------------------------------------------------- /apps/ashet-bios/main.asm: -------------------------------------------------------------------------------- 1 | .include "../library/ashet/syscalls.inc" 2 | .include "../library/ashet/io-page.inc" 3 | 4 | .org 0x0000 5 | 6 | ; interrupt table at the start of the ROM 7 | ; this must be fixed in location 8 | bios.vectors: 9 | .dw bios.entrypoint ; Reset 10 | .dw bios.interrupt.handler.nmi ; NMI 11 | .dw bios.interrupt.handler.bus ; BUS 12 | .dw 0x0000 ; RESERVED 13 | .dw bios.interrupt.handler.arith ; ARITH 14 | .dw bios.interrupt.handler.software ; SOFTWARE 15 | .dw bios.interrupt.handler.reserved ; RESERVED 16 | .dw bios.interrupt.handler.irq ; IRQ 17 | 18 | ; the bios syscall table 19 | ; this must be fixed in location, each slot in the list is 2 word wide. 20 | bios.syscall.table: 21 | jmp bios.syscall.uart.setup 22 | jmp bios.syscall.uart.status 23 | jmp bios.syscall.uart.writeChar 24 | jmp bios.syscall.uart.readChar 25 | 26 | ; we spare half of the first page for potential future syscall entries 27 | ; so we don't have to relocate everything 28 | 29 | ; so the rest of the bios code starts after the first half page 30 | .org 0x0800 31 | 32 | bios.syscall.invalid: 33 | ret 34 | 35 | ; uart.setup(mode_selector: u16, baud_selector: u16) void 36 | ; changes the UART configuration 37 | ; mode_selector: 38 | ; 0…7 => uart [ COM1, COM2, IR1, -, … ] 39 | ; 8…9 => parity [ none, even, odd, - ] 40 | ; 10…10 => stop bits [ one, two ] 41 | ; 11…13 => data width [ 5, 6, 7, 8, 9, -, -, - ] 42 | ; baud_selector: 43 | ; 0 => 1200 44 | ; 1 => 2400 45 | ; 2 => 4800 46 | ; 3 => 19200 47 | ; 4 => 38400 48 | ; 5 => 57600 49 | ; 6 => 115200 50 | ; 51 | bios.syscall.uart.setup: 52 | ; TODO: Implement this 53 | ret 54 | 55 | ; uart.status(uart: u16) u16 56 | ; returns the status of a uart 57 | ; uart: 58 | ; 0…7 => uart [ COM1, COM2, IR1, -, … ] 59 | ; : 60 | ; 0…0 => ??? 61 | ; 62 | bios.syscall.uart.status: 63 | set 2, 0x0000 ; just return empty status for now 64 | ret 65 | 66 | ; uart.writeChar(uart: u16, char: u16) void 67 | ; writes a character to the uart 68 | ; uart: 69 | ; 0…7 => uart [ COM1, COM2, IR1, -, … ] 70 | ; char: 71 | ; 0…9 => max bits to send over the wire 72 | ; 73 | bios.syscall.uart.writeChar: 74 | get -2 75 | st 0x4000 76 | ret 77 | 78 | ; uart.readChar(uart: u16) u16 79 | ; writes a character to the uart 80 | ; uart: 81 | ; 0…7 => uart [ COM1, COM2, IR1, -, … ] 82 | ; : 83 | ; 0…9 => the bits received from the wire 84 | ; 15…15 => if 1, the fifo was empty. 85 | ; FR.Z => if 1, the received bits are all 0 86 | ; FR.N => if 1, the fifo was empty. 87 | ; 88 | bios.syscall.uart.readChar: 89 | set 2, 0xFFFF ; just return "empty fifo" for now 90 | ret 91 | 92 | bios.interrupt.handler.nmi: 93 | st 'N', 0x4000 94 | jmp bios.hang 95 | 96 | bios.interrupt.handler.bus: 97 | st 'B', 0x4000 98 | jmp bios.hang 99 | 100 | bios.interrupt.handler.arith: 101 | st 'A', 0x4000 102 | iret 103 | 104 | bios.interrupt.handler.software: 105 | st 'S', 0x4000 106 | iret 107 | 108 | bios.interrupt.handler.reserved: 109 | st 'R', 0x4000 110 | iret 111 | 112 | bios.interrupt.handler.irq: 113 | st 'I', 0x4000 114 | iret 115 | 116 | bios.entrypoint: 117 | TODO: Rebuild this to be correct 118 | st 0x7FE1, 0xF002 ; map I/O page to second page 0x1000 119 | 120 | ; Map some RAM in the upper half 121 | st 0x8001, 0xF010 122 | st 0x8011, 0xF012 123 | st 0x8021, 0xF014 124 | st 0x8031, 0xF016 125 | st 0x8041, 0xF018 126 | st 0x8051, 0xF01A 127 | st 0x8061, 0xF01C 128 | st 0x8071, 0xF01E ; this will unmap the MMU from 0xF000 129 | 130 | st 0x0000, 0x1000 ; map framebuffer to 0x800000 131 | st 0x0080, 0x1002 132 | 133 | st 0x8101, 0x100E ; map RAM to 0x7000…0x7FFF for stack 134 | 135 | st 0x7F21, 0x1008 ; map UART0 to 0x4000 136 | 137 | ; init a stack 138 | spset 0x8000 139 | bpset 0x8000 140 | 141 | frset 0xFFF0, ~0x00F0 142 | 143 | st 'H', 0x4000 144 | st 'e', 0x4000 145 | st 'l', 0x4000 146 | st 'l', 0x4000 147 | st 'o', 0x4000 148 | st '\r', 0x4000 149 | st '\n', 0x4000 150 | 151 | push 0x80 152 | vga_loop: 153 | push 0x8000 ; push pixel offset 154 | vga_fill: 155 | 156 | dup ; duplicate address 157 | bswap [i0:peek] 158 | xor 159 | get -1 160 | add 161 | 162 | ;.dw 0x8001 ; enable tracing 163 | st8 [i1:peek]; store color to current pixel 164 | ;.dw 0x8000 ; disable tracing 165 | 166 | add 1 [f:yes] ; increment address by one 167 | [ex:nonzero] jmp vga_fill ; if it overflowed into 0x0000, stop looping 168 | pop ; remove address 169 | add 1 170 | jmp vga_loop 171 | 172 | .org 0x0500 173 | bios.hang: 174 | frset 0x0000 ; disable all maskable interrupts 175 | jmp bios.hang 176 | 177 | -------------------------------------------------------------------------------- /apps/hello-world/main.asm: -------------------------------------------------------------------------------- 1 | ; Example application 2 | ; Prints "Hello, World!\r\n" to the serial console 3 | ; by using ROM routines, then returns to the BIOS. 4 | 5 | .include "../library/bios.inc" 6 | 7 | .equ UART_RXD,0x1000 8 | 9 | ; Programs start at 0x8000 10 | .org APP_START 11 | 12 | ; call puts(app_msg) 13 | push app_msg 14 | ld ROM_PUTS 15 | call 16 | pop 17 | 18 | ; wait until we receive a character from serial 19 | app_loop: 20 | ld UART_RXD [f:yes] 21 | [ex:less] jmp app_loop [i1:pop] 22 | pop 23 | 24 | ret 25 | 26 | app_msg: 27 | .asciiz "\rHello, World!" 28 | .align 2 29 | -------------------------------------------------------------------------------- /apps/library/ascii.inc: -------------------------------------------------------------------------------- 1 | ; Provides common ASCII control characters as constants 2 | 3 | .equ ASCII_NUL, 0 ; null 4 | .equ ASCII_SOH, 1 ; start of heading 5 | .equ ASCII_STX, 2 ; start of text 6 | .equ ASCII_ETX, 3 ; end of text 7 | .equ ASCII_EOT, 4 ; end of transmission 8 | .equ ASCII_ENQ, 5 ; enquiry 9 | .equ ASCII_ACK, 6 ; acknowledge 10 | .equ ASCII_BEL, 7 ; bell 11 | .equ ASCII_BS, 8 ; backsace 12 | .equ ASCII_TAB, 9 ; horizontal tabulator 13 | .equ ASCII_LF, 10 ; line feed 14 | .equ ASCII_VT, 11 ; vertical tabulator 15 | .equ ASCII_FF, 12 ; form feed 16 | .equ ASCII_CR, 13 ; carriage return 17 | .equ ASCII_SO, 14 ; shift out 18 | .equ ASCII_SI, 15 ; shift in 19 | .equ ASCII_DLE, 16 ; data link escape 20 | .equ ASCII_DC1, 17 ; device control 1 21 | .equ ASCII_DC2, 18 ; device control 2 22 | .equ ASCII_DC3, 19 ; device control 3 23 | .equ ASCII_DC4, 20 ; device control 4 24 | .equ ASCII_NAK, 21 ; negative acknowledge 25 | .equ ASCII_SYN, 22 ; synchronous idle 26 | .equ ASCII_ETB, 23 ; end of transmission block 27 | .equ ASCII_CAN, 24 ; cancel 28 | .equ ASCII_EM, 25 ; end of medium 29 | .equ ASCII_SUB, 26 ; substitute 30 | .equ ASCII_ESC, 27 ; escape 31 | .equ ASCII_FS, 28 ; file separator 32 | .equ ASCII_GS, 29 ; group separator 33 | .equ ASCII_RS, 30 ; record separator 34 | .equ ASCII_US, 31 ; unit separator 35 | .equ ASCII_RUB, 127 ; rub out (what happens when you press the '<=' button that is called backspace -------------------------------------------------------------------------------- /apps/library/ashet/io-page.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /apps/library/ashet/syscalls.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | .equ SYS_UART_SETUP, 16 4 | .equ SYS_UART_STATUS, 20 5 | .equ SYS_UART_WRITE_CHAR, 24 6 | .equ SYS_UART_READ_CHAR, 28 -------------------------------------------------------------------------------- /apps/library/bios.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ; This is the location of `puts(char * str)` in the ROM. 5 | ; We can use this to clarify where we're jumping to 6 | .equ ROM_PUTS, 0x0006 7 | 8 | 9 | ; Entry point for applications, BIOS will jump here after 10 | ; loading the application to memory. 11 | .equ APP_START, 0x8000 12 | -------------------------------------------------------------------------------- /apps/minimal-firmware/firmware.asm: -------------------------------------------------------------------------------- 1 | .org 0x0000 2 | 3 | bpset 0x0000 4 | spset 0x0000 5 | 6 | 7 | 8 | push msg_hello 9 | ipget 2 10 | jmp serial_puts 11 | pop 12 | 13 | push 0x10 14 | 15 | mini_loop: 16 | push 0x0000 17 | ipget 2 18 | jmp sleep 19 | pop 20 | 21 | sub 1 [f:yes] 22 | [ex:nonzero] jmp mini_loop 23 | pop 24 | 25 | push msg_byte 26 | ipget 2 27 | jmp serial_puts 28 | pop 29 | 30 | .dw 0x8000 ; invalid opcode 31 | 32 | msg_hello: 33 | .asciiz "Hello, World!\r\n" 34 | msg_byte: 35 | .asciiz "Goodbye, Emulator!\r\n" 36 | 37 | ; fn(str: [*:0]const u8) void 38 | ; prints a string to the serial terminal 39 | .align 2 40 | serial_puts: 41 | bpget 42 | spget 43 | bpset 44 | 45 | get 2 ; arg 1 46 | .puts_loop: 47 | ld8 [i0:peek] [f:yes] 48 | [ex:nonzero] st8 0x4000 49 | [ex:nonzero] add 1 50 | [ex:nonzero] jmp .puts_loop 51 | pop 52 | 53 | bpget 54 | spset 55 | bpset 56 | ret 57 | 58 | 59 | sleep: 60 | bpget 61 | spget 62 | bpset 63 | 64 | get 0-2 65 | 66 | .loop: 67 | sub 1 [f:yes] 68 | nop 69 | nop 70 | [ex:nonzero] jmp .loop 71 | pop 72 | 73 | bpget 74 | spset 75 | bpset 76 | ret -------------------------------------------------------------------------------- /apps/minimal/main.asm: -------------------------------------------------------------------------------- 1 | .org 0x8000 2 | st 0x4000, '!' 3 | jmp . 4 | -------------------------------------------------------------------------------- /apps/web-firmware/demo.asm: -------------------------------------------------------------------------------- 1 | .equ ROM_START, 0x0000 2 | .equ SERIAL_PORT, 0x7FFE 3 | .equ RAM_START, 0x8000 4 | 5 | .org RAM_START 6 | 7 | entry_point: 8 | 9 | push message 10 | 11 | .loop: 12 | ld8 [i0:peek] [f:yes] 13 | [ex:zero] jmp .done 14 | st SERIAL_PORT 15 | add 1 16 | jmp .loop 17 | .done: 18 | pop ; remove 0 byte 19 | pop ; remove address 20 | 21 | ret ; return to bios 22 | 23 | message: 24 | .asciiz "Hello, World!\r\n" -------------------------------------------------------------------------------- /castle.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/castle.bin -------------------------------------------------------------------------------- /documentation/app-notes/AN000 - Understanding the Instruction Set.md: -------------------------------------------------------------------------------- 1 | # AN000 - Understanding the Instruction Set 2 | 3 | ## Instructions 4 | 5 | Each instruction is composed of a set of bit fields defining the behaviour: 6 | 7 | - Command 8 | - Execution 9 | - Input 0 10 | - Input 1 11 | - Output 12 | - Flag Modifier 13 | 14 | The most relevant field is the *command* part. It defines what the CPU actually does 15 | with your data. There are 32 commands from which are some still reserved. They provide 16 | the ability to modify data (ALU), modify memory (load/store) or modify aux registers. 17 | 18 | Each *command* has two input values: *input 0* and *input 1*. These get fetched by the 19 | cpu and get passed two the *command*. It will then process both values and will yield 20 | an *output*. The cpu will then dispatch the output value as specified in the instruction. 21 | 22 | An *output* can be discarded, pushed to the stack or used as a jump target. This means 23 | that actually *all instructions can be jump instructions*! Discarding an output might 24 | sound unnecessary, but it has its uses as well: 25 | 26 | To remove a value from the stack, the *command* `COPY` is used and the output is just 27 | discarded. This means that we can fetch values from the stack and don't push new ones. 28 | We successfully implemented `pop` by assembling an instruction. 29 | 30 | Each instruction has also a bit that, when set, will update the flags of the cpu 31 | according to the *output* of the command. There are two flags relevant for the 32 | normal program control flow: *zero* and *negative*. These flags will only be changed 33 | when an instruction has the *modify flags* bit set. Then, the *zero* flag will be set 34 | when *output* is zero and the *negative* flag will be set when the highest significant 35 | bit in *output* is set (and thus is negative in two's complement). 36 | 37 | The flags can then be used to execute instructions conditionally. The *execution* field 38 | of an instruction defines for which combination of flags the instruction is actually 39 | executed. This is similar to other architectures like ARM or the Parallax Propeller that 40 | allow instructions to be executed conditionally instead of having a dedicated *conditional jump*, 41 | *conditional move* or similar. It is also different from instructions like the AVR *skip* 42 | which requires an additional fetch cycle. 43 | 44 | Conditional execution checks for different combinations of flags that are semantically 45 | relevant. This yields 7 conditions: always, less-or-equal, greater-or-equal, less-than, 46 | greater-than, non-equal (or non-zero) and equal (or zero). 47 | 48 | Now only two fields are unexplained: *input 0* and *input 1*. Both fields have the same 49 | semantics and the same options: *zero*, *immediate*, *peek* and *pop*. 50 | 51 | *Zero* is the simplest one and means that the input field gets set to 0. *Immediate* means 52 | that value for that field is encoded in the instruction itself and is not dependent on 53 | runtime properties. This is usually used for addresses, offsets, magic numbers or similar. 54 | *Peek* and *pop* both take the value of the stack top, and *pop* will remove the value 55 | from the stack whereas *peek* will keep the stack pointer itself untouched. 56 | 57 | ## Registers 58 | 59 | > TODO: Explain what the four core registers do 60 | 61 | ## Common Patterns 62 | 63 | > TODO: Explain how some coding patters are and how 64 | > to write basic code for the processor. 65 | 66 | ```asm 67 | ; Check an an 8 bit value 68 | sgxt [f:yes] [out:discard] 69 | ``` -------------------------------------------------------------------------------- /documentation/app-notes/AN002 - Standard Calling Convention.md: -------------------------------------------------------------------------------- 1 | # AN002 - Standard Calling Convention 2 | 3 | ## Call Site 4 | 5 | The caller of a function follows this procedure: 6 | 7 | 1. If function has a return value, push placeholder for the return value 8 | 2. Push arguments back-to-front on the stack 9 | 3. Push return address on the stack 10 | 4. Jump to the target function 11 | 5. Pop all arguments from stack 12 | 6. Process return value if any 13 | 14 | For a function without args and return value, the simplest call looks like this: 15 | ```asm 16 | ipget 2 ; Position-independent getter for return address 17 | jmp func ; Jump to function 18 | ``` 19 | 20 | For a function with the C signature `int16_t sum(int16_t a, int16_t b)` the code 21 | looks like this: 22 | ```asm 23 | push 0 ; return value 24 | push b ; arg 2 25 | push a ; arg 1 26 | ipget 2 ; return address 27 | jmp func ; execute call 28 | pop ; remove arg 1 29 | pop ; remove arg 2 30 | ; here the return value is on top of the stack and can be processed further 31 | ``` 32 | 33 | ## Function Site 34 | 35 | Functions called with the Standard Calling Convention need to modify the 36 | Base Pointer in order to access both function arguments as well as the return 37 | type. before modifying the Base Pointer, the old Base Pointer must be saved: 38 | 39 | ```asm 40 | func: 41 | bpget ; save caller base pointer on the stack 42 | spget ; \ 43 | bpset ; + Set new base pointer to current stack stop 44 | 45 | … ; Function implement goes here 46 | 47 | bpget ; \ 48 | spset ; + Restore previous stack frame 49 | bpset ; Restore caller base pointer 50 | ret ; Return to caller 51 | ``` 52 | 53 | Inside the function, arguments, return value, return address and previous Base Pointer 54 | can be accessed by using `get` and `set`. The offsets for this are: 55 | 56 | | Offset | Value | 57 | |----------|---------------------| 58 | | 0 | caller Base Pointer | 59 | | 1 | return address | 60 | | 2+*c* | Argument *c* | 61 | | 2+*argc* | return value | 62 | 63 | Passing negative values to `get` or `set` will return values local to the function stack 64 | and thus allow simple access to local variables. 65 | 66 | A function implementing this C code: 67 | 68 | ```c 69 | int16_t sum(int16_t a, int16_t b) 70 | { 71 | return a + b; 72 | } 73 | ``` 74 | 75 | looks like this: 76 | 77 | ```asm 78 | func: 79 | bpget ; save caller base pointer on the stack 80 | spget ; \ 81 | bpset ; + Set new base pointer to current stack stop 82 | 83 | get 2 84 | get 3 85 | add 86 | set 4 87 | 88 | bpget ; \ 89 | spset ; + Restore previous stack frame 90 | bpset ; Restore caller base pointer 91 | ret ; Return to caller 92 | ``` 93 | -------------------------------------------------------------------------------- /documentation/app-notes/AN003 - Writing efficient code.md: -------------------------------------------------------------------------------- 1 | # AN003 - Writing efficient code 2 | 3 | ## When should I use a conditional jump? 4 | 5 | (TBD) 6 | 7 | ## Merging instructions and combine effects 8 | 9 | (TBD) -------------------------------------------------------------------------------- /documentation/design/spu-mk-ii-logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/documentation/design/spu-mk-ii-logo-large.png -------------------------------------------------------------------------------- /documentation/design/spu-mk-ii-logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/documentation/design/spu-mk-ii-logo-small.png -------------------------------------------------------------------------------- /documentation/design/spu-mk-ii-logo.txt: -------------------------------------------------------------------------------- 1 | Logo created by Kitsu 2 | 3 | Font used: 4 | https://fontstruct.com/fontstructions/show/738493/av02_jetforce 5 | 6 | AV02 Jetforce 7 | by AV Perth (ConEAP) 8 | CC BY-NC-ND 3.0 -------------------------------------------------------------------------------- /documentation/figures/fr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 12 | [15:8] 16 | 0 20 | 24 | [7:4] 28 | int_en 32 | 36 | [3] 40 | ce 44 | 48 | [2] 52 | c 56 | 60 | [1] 64 | n 68 | 72 | [0] 76 | z 80 | 81 | -------------------------------------------------------------------------------- /documentation/figures/genbits.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | local args = {...} 4 | 5 | local bits = { 6 | -- {"0", 1}, -- {name, bits} 7 | } 8 | 9 | local original = "./genbits.lua" 10 | for i = 1, #args, 2 do 11 | local num = tonumber(args[i + 1]) 12 | assert(num, "unable to numify " .. tostring(args[i + 1])) 13 | table.insert(bits, {args[i], num}) 14 | original = original .. " " .. args[i] .. " " .. num 15 | end 16 | 17 | local bitCount = 0 18 | for _, v in ipairs(bits) do 19 | bitCount = bitCount + v[2] 20 | end 21 | local highBit = bitCount - 1 22 | for _, v in ipairs(bits) do 23 | local lowBit = ((highBit - v[2]) + 1) 24 | if highBit == lowBit then 25 | v[3] = "[" .. highBit .. "]" 26 | else 27 | v[3] = "[" .. highBit .. ":" .. lowBit .. "]" 28 | end 29 | highBit = highBit - v[2] 30 | end 31 | 32 | local margin = 24 33 | local bitWidth = 80 34 | local bitHeight = 56 35 | local width = (margin * 2) + (bitCount * bitWidth) 36 | local height = 120 37 | local bitY = 48 38 | local textY = 88 39 | local textYUp = 40 40 | 41 | print("") 42 | print("") 43 | print("") 44 | local hX = margin 45 | 46 | print("") 50 | 51 | for _, v in ipairs(bits) do 52 | local lW = v[2] * bitWidth 53 | print("") 57 | 58 | print("" .. v[3] .. "") 62 | 63 | print("" .. v[1] .. "") 67 | hX = hX + lW 68 | end 69 | print("") 70 | -------------------------------------------------------------------------------- /documentation/figures/instruction.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 12 | [15] 16 | 0 20 | 24 | [14:9] 28 | cmd 32 | 36 | [8] 40 | out 44 | 48 | [7] 52 | flg 56 | 60 | [6:5] 64 | in1 68 | 72 | [4:3] 76 | in0 80 | 84 | [2:0] 88 | cond 92 | 93 | -------------------------------------------------------------------------------- /documentation/figures/ir.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 12 | [15:8] 16 | 0 20 | 24 | [7:4] 28 | int 32 | 36 | [3] 40 | 0 44 | 48 | [2] 52 | bus 56 | 60 | [1] 64 | nmi 68 | 72 | [0] 76 | rst 80 | 81 | -------------------------------------------------------------------------------- /documentation/index.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | The Ashet Home Computer, or short just *Ashet* is a late 80ies style inspired [home computer](https://en.wikipedia.org/wiki/Home_computer) with a 16 bit cpu. 4 | 5 | Most components of *Ashet* are self-developed chips and computer components, like the *SPU Mark II* CPU, the yet unnamed MMU, video chip and blitter DMA. 6 | 7 | ## Goal of the project 8 | 9 | The goal is to create a home computer around the *SPU Mark II* CPU that can be used for games, music and demos. The CPU is a quite novel approach on instruction set style as well as the attempt to create a CPU that is easily programmed by humans and compilers the like. 10 | 11 | To overcome the 64k memory limitation own to 16 bit cpus is overcome by a paging unit providing 16 pages a 4096 byte that can be mapped to *any* page in a 16 MB large memory space. The I/O architecture is inspirted by the [Amiga 500](https://en.wikipedia.org/wiki/Amiga_500), like a DMA chip ("blitter") that allows trivial image/block transfers in memory as well as a graphics chip with sprite support. In contrast to the Amiga though the *Ashet* uses a 256 color linear framebuffer with a configurable palette of 16 bit colors, allowing the user to chose 256 of 65536 possible colors. 12 | 13 | ## State of the project 14 | 15 | Right now, everything is work in progress and a lot of links on this site will be broken or the documents will be incomplete, but get filled in the future. If you want to support the project, [mail me](mailto:contact@ashet.computer)! 16 | 17 | Most core components are either in *concept phase* or in *implementation phase*, some even near-completion 18 | 19 | - Hardware 20 | - SPU Mark II (nearly complete, only missing 21 | - UART serial port (nearly completion, misses only a good MMIO interface) 22 | - RAM interface (complete, RAM test works) 23 | - MMU (planning done, implementation is up next) 24 | - Toolchain 25 | - Assembler (work-in-progress, misses some directives and expression evaluation) 26 | - Debugging iterface to the SOC 27 | - Emulator (mirrors the state of hardware, will be updated as soon as HW gains new features) -------------------------------------------------------------------------------- /documentation/manuals/ashet-emulator.md: -------------------------------------------------------------------------------- 1 | ## Ashet Emulator 2 | 3 | > (TBD) -------------------------------------------------------------------------------- /documentation/manuals/assembler.md: -------------------------------------------------------------------------------- 1 | ## SPU Mk 2 Assembler 2 | 3 | > (TBD) -------------------------------------------------------------------------------- /documentation/manuals/basic-emulator.md: -------------------------------------------------------------------------------- 1 | ## Basic SPU Mk 2 Assembler 2 | 3 | > (TBD) -------------------------------------------------------------------------------- /documentation/manuals/disassembler.md: -------------------------------------------------------------------------------- 1 | ## SPU Mk 2 Disassembler 2 | 3 | > (TBD) -------------------------------------------------------------------------------- /documentation/metadata/an000.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | title: Understanding the Instruction Set 3 | author: 4 | - Felix "xq" Queißner 5 | date: April 28, 2020 6 | abstract: | 7 | The SPU Mark II uses quite unique instruction set following a highly orthogonal programming style. 8 | In contrast to most cpus on the market, the SPU Mark II is a stack machine. This means that all operations move data to or from the stack. This does not mean that this cpu has no registers. There are auxiliary registers like a stack pointer SP or the instruction pointer IP. 9 | -------------------------------------------------------------------------------- /documentation/metadata/an001.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | title: The SPU Assembly Language 3 | author: 4 | - Felix "xq" Queißner 5 | date: April 28, 2020 6 | abstract: | 7 | The highly flexible nature of the instruction set of the *SPU Mark II* makes it 8 | different to put all possible instructions into useful mnemonics. So the assembly 9 | language allows the coder to put modifiers on each instruction. These modifiers 10 | allow to change any field of the instruction they are put on. 11 | -------------------------------------------------------------------------------- /documentation/metadata/an002.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | title: Standard Calling Convention 3 | author: 4 | - Felix "xq" Queißner 5 | date: April 28, 2020 6 | abstract: The Standard Calling Convention (SCC) is the default calling convention used for all SPU Mark II code. -------------------------------------------------------------------------------- /documentation/metadata/an003.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | title: Writing efficient code 3 | author: 4 | - Felix "xq" Queißner 5 | date: April 28, 2020 6 | abstract: The SPU Mark II allows one to write very compact and efficient code. In this document, you learn about different tricks on how to do this. -------------------------------------------------------------------------------- /documentation/metadata/ashet.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | title: Ashet Hardware Architecture 3 | author: 4 | - Felix "xq" Queißner 5 | date: Jan 19, 2021 6 | abstract: The document describes the system architecture of the Ashet Home Computer. 7 | -------------------------------------------------------------------------------- /documentation/metadata/isa.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | title: The SPU Mark II Instruction Set Architecture 3 | author: 4 | - Felix "xq" Queißner 5 | date: April 28, 2020 6 | abstract: This is the documentation for the SPU Mark II instruction set architecture. It is a stack based 16 bit processor that features a highly configurable instruction set. -------------------------------------------------------------------------------- /documentation/metadata/mmu.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | title: Ashet Primitive Bank Unit 3 | author: 4 | - Felix "xq" Queißner 5 | date: May 07, 2020 -------------------------------------------------------------------------------- /documentation/metadata/vchip.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | title: Unnamed DMA Chip 3 | author: 4 | - Felix "xq" Queißner 5 | date: May 07, 2020 6 | abstract: | 7 |

The RAM Blitter is a DMA unit that is developed for general purpose DMA transfers, as well as framebuffer modifications. It supports basic linear memory transfers as well as rectangle copies with image manipulation.

8 |

The RAM blitter also has a modes for drawing 2d vector graphics and a filling operation that allows color transfers.

9 | -------------------------------------------------------------------------------- /documentation/metadata/vga.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | title: VGA Chip 3 | author: 4 | - Felix "xq" Queißner 5 | date: May 07, 2020 6 | abstract: The VGA Chip provides a framebuffer with 256×128 pixels output. -------------------------------------------------------------------------------- /documentation/os/boot.md: -------------------------------------------------------------------------------- 1 | # Boot Process 2 | 3 | ## Brain Dump 4 | 5 | 1. `` Initialize default memory map 6 | 2. `` Initialize and detect HW 7 | 3. `` Create process "init" 8 | 4. `` Jump into "init" process 9 | 5. `` Check HDDs for an OS signature 10 | 6. `` Display boot menu 11 | 7. `` If nothing selected, create process with "ROM BASIC" 12 | 8. `` does its thing -------------------------------------------------------------------------------- /documentation/os/index.md: -------------------------------------------------------------------------------- 1 | # AshetOS Overview 2 | 3 | ## Features 4 | 5 | - Boot management 6 | - Provide boot menu 7 | - Boot application/os from HDD 8 | - Load application via serial port 9 | - BIOS style functions 10 | - mass storage 11 | - serial ports 12 | - display 13 | - … 14 | - Cooperative multitasking 15 | - Memory management 16 | 17 | ## Builtin BASIC 18 | 19 | The AshetOS provides a builtin BASIC implementation that allows the users to use the hardware without any OS installed. 20 | The BASIC is compatible to Microsoft BASIC 4.0, but has some Ashet-specific extensions. -------------------------------------------------------------------------------- /documentation/os/syscalls.md: -------------------------------------------------------------------------------- 1 | # List of Syscalls 2 | 3 | ## Serial Port 4 | 5 | - setup (baud, ...) 6 | - status 7 | - write char 8 | - read char 9 | 10 | ## Raw Mass Storage / Disk 11 | 12 | - detect 13 | - read sector 14 | - write sector 15 | 16 | ## File System I/O 17 | 18 | - stat 19 | - dir 20 | - open 21 | - read 22 | - write 23 | - close 24 | - mkdir 25 | - delete 26 | - truncate 27 | - move 28 | 29 | ## Display: 30 | 31 | - clear 32 | - loadPalette 33 | - loadBitmap 34 | - loadImage 35 | - printString 36 | - moveCursor 37 | - verticalScroll 38 | - horizontalScroll 39 | - setBorderColor 40 | - enableCursor 41 | 42 | ## Parallel Port 43 | 44 | - set direction 45 | - write 46 | - read 47 | 48 | ## Keyboard 49 | 50 | - status 51 | - read char 52 | - get key 53 | 54 | ## Mouse 55 | 56 | - status 57 | - readPos 58 | - show 59 | - hide 60 | 61 | ## Joystick 62 | 63 | - read 64 | 65 | ## RTC 66 | 67 | - read 68 | - write 69 | - read time 70 | - write time 71 | - read date 72 | - write date 73 | 74 | ## Memory 75 | 76 | - status 77 | - alloc page 78 | - free page 79 | 80 | ## Tasks 81 | 82 | - spawn 83 | - kill 84 | - status 85 | - yield 86 | - sleep 87 | - send 88 | - receive -------------------------------------------------------------------------------- /documentation/os/ui.uxf: -------------------------------------------------------------------------------- 1 | 10UMLClass280220470210SimpleClass -------------------------------------------------------------------------------- /documentation/specs/ashet-register-space.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Register Space 4 | 5 | ## Device Overview 6 | 7 | **[MMU](mmu.md):** 8 | 9 | - 1 Device 10 | - 18 Registers @ 16 Bit 11 | 12 | **[IRQ](irq.md):** 13 | 14 | - 1 Device 15 | - 6 Registers @ 16 Bit 16 | 17 | **[UART 16C550-Style](uart.md):** 18 | 19 | - 4 Devices 20 | - 8 Registers @ 8 Bit 21 | 22 | **[PS/2](ps2.md):** 23 | 24 | - 2 Devices 25 | - 2 Registers @ 16 Bit 26 | 27 | **[IDE / PATA](ide.md):** 28 | 29 | - 1 Device 30 | - 8 Registers @ 16 Bit 31 | 32 | **[Timer](timer.md):** 33 | 34 | - 2 Devices 35 | - 4 Registers @ 16 Bit 36 | 37 | **[RTC](rtc.md):** 38 | 39 | - 1 Device 40 | - 3 Registers @ 16 Bit 41 | - 8 Registers @ 8 Bit 42 | 43 | **[Joystick](joystick.md):** 44 | 45 | - 2 Devices 46 | - 1 Registers @ 8 Bit 47 | 48 | **[Parallel Port](parport.md):** 49 | 50 | - 1 Device 51 | - 3 Registers @ 8 Bit 52 | 53 | **[PCM Audio Control/Status](pcm.md):** 54 | 55 | - 1 Device 56 | 57 | **[DMA Control/Status](dma.md):** 58 | 59 | - 1 Device 60 | 61 | **[VGA Card](vga.md):** 62 | 63 | - 1 Device 64 | - 3 Registers @ 16 Bit 65 | - 2 Registers @ 8 Bit 66 | 67 | **[Ethernet](eth.md):** 68 | 69 | - 1 Device 70 | - 3 Registers @ 16 Bit 71 | - 7 Registers @ 8 Bit 72 | 73 | **[VGA Palette Memory](vga.md):** 74 | 75 | - 1 Device 76 | - 256 Registers @ 16 Bit 77 | 78 | ## Device Mapping 79 | 80 | | Address | Offset | Count | Peripherial | 81 | | ---------- | ------ | ----- | ---------------------------------- | 82 | | `0x7FE000` | 0 | 36 | [MMU](mmu.md) | 83 | | `0x7FE030` | 48 | 12 | [IRQ](irq.md) | 84 | | `0x7FE040` | 64 | 8 | [UART 16C550-Style (1)](uart.md) | 85 | | `0x7FE050` | 80 | 8 | [UART 16C550-Style (2)](uart.md) | 86 | | `0x7FE060` | 96 | 8 | [UART 16C550-Style (3)](uart.md) | 87 | | `0x7FE070` | 112 | 8 | [UART 16C550-Style (4)](uart.md) | 88 | | `0x7FE080` | 128 | 4 | [PS/2 (1)](ps2.md) | 89 | | `0x7FE090` | 144 | 4 | [PS/2 (2)](ps2.md) | 90 | | `0x7FE0A0` | 160 | 16 | [IDE / PATA](ide.md) | 91 | | `0x7FE0B0` | 176 | 8 | [Timer (1)](timer.md) | 92 | | `0x7FE0C0` | 192 | 8 | [Timer (2)](timer.md) | 93 | | `0x7FE0D0` | 208 | 14 | [RTC](rtc.md) | 94 | | `0x7FE0E0` | 224 | 1 | [Joystick (1)](joystick.md) | 95 | | `0x7FE0F0` | 240 | 1 | [Joystick (2)](joystick.md) | 96 | | `0x7FE100` | 256 | 3 | [Parallel Port](parport.md) | 97 | | `0x7FE110` | 272 | 0 | [PCM Audio Control/Status](pcm.md) | 98 | | `0x7FE110` | 272 | 0 | [DMA Control/Status](dma.md) | 99 | | `0x7FE110` | 272 | 8 | [VGA Card](vga.md) | 100 | | `0x7FE120` | 288 | 13 | [Ethernet](eth.md) | 101 | | `0x7FE200` | 512 | 512 | [VGA Palette Memory](vga.md) | 102 | | `0x7FE400` | 1024 | | _end of peripherials_ | 103 | -------------------------------------------------------------------------------- /documentation/specs/ashet.md: -------------------------------------------------------------------------------- 1 | # Ashet Home Computer Specification 2 | 3 | **DISCLAIMER: This is a living document, do not take anything here for granted!** 4 | 5 | ## Hardware 6 | 7 | ### CPU 8 | 9 | - SPU Mark II, a 16 bit processor 10 | 11 | ### Memory 12 | 13 | - 8 MB of flash 14 | - Up to 8 MB of ram 15 | 16 | ### Peripherials 17 | 18 | - VGA video 19 | - 4 serial ports 20 | - 2 * RS232 21 | - 1 * USB Serial 22 | - 1 infrared serial interface for wireless data transfers 23 | - 2 PS/2 ports for keyboard and mouse 24 | - 2 IDE slots for mass storage 25 | - 2 (digital) joystick ports, compatible to c64/amiga/cpc/… 26 | - IEEE 1284 II parallel port 27 | - PCM audio interface 28 | - Real time clock 29 | - 10 MBit Ethernet 30 | - Possibly based on ENC28J60 or ENC624J600 31 | 32 | ## Memory Map 33 | 34 | | Address Range | Memory Type | Component | 35 | |---------------|-----------------|-------------------------------------| 36 | | `0x0*****` | (*Memory*) | up to 8 MB Flash ROM | 37 | | `0x7FE***` | (*Peripherial*) | [I/O Page](ashet-register-space.md) | 38 | | `0x7FF***` | (*Peripherial*) | VGA Sprite Data | 39 | | `0x80****` | (*Memory*) | up to 8 MB of RAM | 40 | 41 | The [I/O Page](ashet-register-space.md) contains all peripherial registers and links to the peripherial devices. 42 | 43 | ## DMA Devices 44 | 45 | The following devices have memory access (with priority top-to-bottom): 46 | 47 | - VGA Controller 48 | - Audio Controller 49 | - CPU 50 | - DMA Controller 51 | 52 | ## IRQ Table 53 | 54 | | IRQ Number | Peripherial | 55 | |------------|--------------| 56 | | 0 | `COM1` | 57 | | 1 | `COM2` | 58 | | 2 | `COM3` | 59 | | 3 | `COM4` | 60 | | 4 | `PER1` | 61 | | 5 | `PER2` | 62 | | 6 | `PCM` | 63 | | 7 | `DMA` | 64 | | 8 | `TIMER0` | 65 | | 9 | `TIMER1` | 66 | | 10 | `VGA` | 67 | | 11 | `ETHERNET` | 68 | | 11 … 31 | *unused* | 69 | 70 | ## Serial Ports 71 | 72 | | COM Name | Connector | Base Address | 73 | |----------|-----------|--------------| 74 | | `COM1` | USB | (TBD) | 75 | | `COM2` | RS232 1 | (TBD) | 76 | | `COM3` | RS232 2 | (TBD) | 77 | | `COM4` | IR | (TBD) | 78 | 79 | ## PS/2 Ports 80 | 81 | | Function | Connector | Base Address | 82 | |----------|-----------|--------------| 83 | | `PER1` | KEYBOARD | (TBD) | 84 | | `PER2` | MOUSE | (TBD) | 85 | 86 | ## Timers and RTC 87 | 88 | Timer 0 runs at 1 MHz, Timer 1 runs at 1 kHz. -------------------------------------------------------------------------------- /documentation/specs/eth.md: -------------------------------------------------------------------------------- 1 | # Ethernet Interface 2 | 3 | ## Registers 4 | 5 | | Offset | Size | Access | Description | 6 | |---------|------|--------|------------------------| 7 | | `0x000` | 1 | R | Receive Data Register | 8 | | `0x000` | 1 | W | Send Data Register | 9 | | `0x002` | 2 | RW | Control/Status | 10 | | `0x004` | 2 | R | Receive Packet Length | 11 | | `0x006` | 2 | R | Send Packet Length | 12 | | `0x008` | 6*1 | R | Interface MAC address | 13 | 14 | ### `Control/Status` 15 | 16 | | Bit Range | Name |Access | Description | 17 | |-----------|-------|-------|--------------------------------------------------------------------------------------------------------| 18 | | `[0]` | `ENA` | RW | If `1`, the ethernet interface is enabled. | 19 | | `[1]` | `FUC` | RW | If `1`, unicast ethernet packets with a foreign MAC will be filtered. | 20 | | `[2]` | `FMC` | RW | If `1`, multicast ethernet packets will be filtered. | 21 | | `[3]` | `FBC` | RW | If `1`, broadcast ethernet packets will be filtered. | 22 | | `[4]` | `RTR` | RO | A packet is ready in the queue and can be read via the `Receive Data Register`. | 23 | | `[5]` | `RAK` | RW | Acknowledge received packet. Write this bit to `1` to signal that the incoming packet was fully processed and a new one can be provided if available. | 24 | | `[6]` | `SND` | RW | After bytes are written into `Send Data Register`, write `1` to signal that the packet should be sent. | 25 | | `[7]` | `SFL` | RW | Write `1` to this register to flush the send buffer and discard all bytes written. | 26 | | `[8]` | `PUC` | R | Is `1` when the currently ready receive packet is for the local MAC address | 27 | | `[9]` | `PMC` | R | Is `1` when the currently ready receive packet has a multicast MAC address. | 28 | | `[10]` | `PBC` | R | Is `1` when the currently ready receive packet has a broadcast MAC address. | 29 | | `[15:11]` | | | *reserved*, must be 0 | 30 | 31 | ### `Receive Packet Length` 32 | 33 | When a incoming packet is signalled via the `RTR` bit, this register will contain the remaining bytes of the packet to be read. 34 | 35 | Each read on the `Receive Data Register` will decrement this value until it reaches 0. 36 | 37 | ### `Send Packet Length` 38 | 39 | Contains the current number of bytes written into the `Send Data Register`. If 0, no bytes are currently in the send buffer. 40 | 41 | ### `Interface MAC address` 42 | 43 | These six byte contain the MAC address of the ethernet interface. -------------------------------------------------------------------------------- /documentation/specs/ide.md: -------------------------------------------------------------------------------- 1 | # IDE / P-ATA / CompactFlash Interface 2 | 3 | Parallel ATA-Interface to two compact flash slots. -------------------------------------------------------------------------------- /documentation/specs/irq.md: -------------------------------------------------------------------------------- 1 | 2 | # IRQ Controller 3 | 4 | - [Overview](#overview) 5 | - [Function](#function) 6 | - [Registers](#registers) 7 | 8 | ## Overview 9 | 10 | - Dispatch multiple IRQ lanes into a single lane 11 | - Acknowledge of IRQs 12 | - Masking of IRQs 13 | - up to 32 IRQs 14 | 15 | ## Function 16 | 17 | The IRQ controller manages up to 32 different IRQ sources that work with level-driven IRQs. 18 | If a source IRQ lane is *low*, the IRQ is assumed to be active. A IRQ becomes inactive when the 19 | source lane will go to *high*. 20 | 21 | When an IRQ becomes active, a corresponding bit is set in the `IRQ0` or `IRQ1` register and the output IRQ lane is pulled to *low*. 22 | The output IRQ lane is *low* until all bits in the `IRQ0` and `IRQ1` registers are `0`. 23 | 24 | To acknowledge that an IRQ was handled, write a `1` bit into `IRQ0` or `IRQ1` to tell the controller that this interrupt was handled. 25 | If the IRQ was previously active, it is now disabled. 26 | 27 | Masking interrupts is supported by writing a `1` bit to `MASK0` or `MASK1`. Interrupts will only become active when the IRQ lane is *low* and the corresponding bit in `MASK0` or `MASK1` is `0`. When the controller is reset, all interrupts are masked. 28 | 29 | ## Registers 30 | 31 | | Offset | Name | Size | Access | Description | 32 | |---------|-------|------|--------|--------------------------------------------| 33 | | `0x000` | IRQ0 | 2 | R | Active IRQs 0…15 | 34 | | `0x002` | IRQ1 | 2 | R | Active IRQs 16…31 | 35 | | `0x000` | ACK0 | 2 | W | Acknowledge IRQs 0…15 | 36 | | `0x002` | ACK1 | 2 | W | Acknowledge IRQs 16…31 | 37 | | `0x004` | MASK0 | 2 | R/W | Mask IRQs 0…15 | 38 | | `0x006` | MASK1 | 2 | R/W | Mask IRQs 16…31 | 39 | 40 | ### Active IRQs 0…15 41 | 42 | When read, all IRQs between 0 and 15 that were triggered since the last acknowledge are 43 | displayed as `1`. All non-triggered IRQs are `0`. 44 | 45 | ### Active IRQs 16…31 46 | 47 | When read, all IRQs between 16 and 31 that were triggered since the last acknowledge are 48 | displayed as `1`. All non-triggered IRQs are `0`. 49 | 50 | ### Acknowledge IRQs 0…15 51 | 52 | When writing to this register, all bits that are `1` in this register will be acknowledged and reset. 53 | 54 | ### Acknowledge IRQs 16…31 55 | 56 | When writing to this register, all bits that are `1` in this register will be acknowledged and reset. 57 | 58 | ### Mask IRQs 0…15 59 | 60 | When a bit is 1, the corresponding interrupt is masked and will not be able to get active. On controller reset, all interrupts are masked. 61 | 62 | ### Mask IRQs 16…31 63 | 64 | When a bit is 1, the corresponding interrupt is masked and will not be able to get active. On controller reset, all interrupts are masked. 65 | 66 | -------------------------------------------------------------------------------- /documentation/specs/joystick.md: -------------------------------------------------------------------------------- 1 | # Joystick Port 2 | 3 | -------------------------------------------------------------------------------- /documentation/specs/mmu.md: -------------------------------------------------------------------------------- 1 | # SimpleMMU 2 | 3 | ## Overview 4 | - 16 bit virtual addresses 5 | - 24 bit physical addresses 6 | - 16 banks a 4096 byte -> 64 kB address space 7 | 8 | ## Function 9 | The MMU translates virtual addresses in a physical addresses by utilizing 16 pages. 10 | 11 | Each page contains 4096 bytes of memory which can be write-protected. 12 | 13 | The physical address for a memory access is created by looking up the upper 12 bit in the page descriptor and taking the lower 12 bit of the virtual address: 14 | 15 | ``` 16 | physical[23:12] := mmuConfig[virt[15..12]][15..4] 17 | physical[11:0] := virt[11..0] 18 | ``` 19 | 20 | When a non-enabled page is accessed, the MMU raises a fault signal and sets the corresponding bit in the Page Fault Register. 21 | 22 | When a non-writeable page is beeing written, the MMU raises a fault signal and sets the corresponding bit in the Write Fault Register. 23 | 24 | ## Configuration 25 | The MMU configuration is mapped into the physical address space at a system-defined location and has the following layout: 26 | 27 | | Offset | Size | Access | Description | 28 | |---------|------|--------|-----------------------| 29 | | `0x000` | 2 | R/W | Page 0 Descriptor | 30 | | `0x002` | 2 | R/W | Page 1 Descriptor | 31 | | `0x004` | 2 | R/W | Page 2 Descriptor | 32 | | `0x006` | 2 | R/W | Page 3 Descriptor | 33 | | `0x008` | 2 | R/W | Page 4 Descriptor | 34 | | `0x00A` | 2 | R/W | Page 5 Descriptor | 35 | | `0x00C` | 2 | R/W | Page 6 Descriptor | 36 | | `0x00E` | 2 | R/W | Page 7 Descriptor | 37 | | `0x010` | 2 | R/W | Page 8 Descriptor | 38 | | `0x012` | 2 | R/W | Page 9 Descriptor | 39 | | `0x014` | 2 | R/W | Page 10 Descriptor | 40 | | `0x016` | 2 | R/W | Page 11 Descriptor | 41 | | `0x018` | 2 | R/W | Page 12 Descriptor | 42 | | `0x01A` | 2 | R/W | Page 13 Descriptor | 43 | | `0x01C` | 2 | R/W | Page 14 Descriptor | 44 | | `0x01E` | 2 | R/W | Page 15 Descriptor | 45 | | `0x020` | 2 | RO | Page Fault Register | 46 | | `0x022` | 2 | RO | Write Fault Register | 47 | 48 | Each page descriptor is 16 bit wide and organized in the following manner: 49 | 50 | | Bit Range | Name | Description | 51 | | --------- | ------ | ------------------------------------- | 52 | | `[0]` | **EN** | page mapping enabled | 53 | | `[1]` | **WP** | page is write protected | 54 | | `[2]` | **CA** | caching is enabled for this page | 55 | | `[3]` | | reserved, must be `0` | 56 | | `[15:4]` | **PA** | Upper 12 bits of the physical address | 57 | 58 | The Page Fault Register contains a bit for each page that flags if there was an access fault (page not mapped). 59 | 60 | The Write Fault Register contains a bit for each page that flags if there was a write fault (page was written, but write protected). 61 | 62 | Each Page Fault Register and Write Fault Register are beeing cleared to 0 after a read operation. 63 | 64 | ## I/Os 65 | 66 | - 24 output physical address lanes 67 | - 16 input virtual address lanes 68 | - 16 in/out data lanes to the bus 69 | - RE, WE input signal (from CPU) 70 | - RE, WE output signal (to Bus) 71 | - CS input to activate read-write access to the MMU 72 | 73 | ## Changelog 74 | 75 | ### v1.0 76 | - Initial version 77 | 78 | -------------------------------------------------------------------------------- /documentation/specs/parport.md: -------------------------------------------------------------------------------- 1 | # IEEE 1284 II Parallel Port 2 | 3 | A parallel port component compatible to the IEEE 1284 II standard. -------------------------------------------------------------------------------- /documentation/specs/pcm.md: -------------------------------------------------------------------------------- 1 | # PCM Audio Interface 2 | 3 | 4 | 5 | 6 | Required features: 7 | 8 | - Mute bit 9 | - Global gain register 10 | - Playback of 44100 Hz audio 11 | - 16 bit signed pcm 12 | -------------------------------------------------------------------------------- /documentation/specs/ps2.md: -------------------------------------------------------------------------------- 1 | # PS/2 Controller 2 | 3 | Planned features: 4 | - Communicate with a PS/2 device (mouse, keyboard) 5 | - One controller per device 6 | 7 | ## Registers 8 | 9 | | Offset | Size | Access | Description | 10 | |---------|------|--------|------------------------| 11 | | `0x000` | 2 | R | Status Reqister | 12 | | `0x002` | 2 | R | Data Input | 13 | | `0x002` | 2 | W | Data Output | 14 | 15 | ### Status Register 16 | 17 | 0: Device Present 18 | 1: Input FIFO not full 19 | 2: Input FIFO full 20 | 3: Output FIFO not full 21 | 4: Output FIFO full 22 | 23 | ### Data Input 24 | 25 | Reading from this port either returns the value read or all bits set if no value is present in the input fifo. 26 | 27 | ### Data Output 28 | 29 | Writing to this port will either put a byte into the send fifo if not full or discard the value. -------------------------------------------------------------------------------- /documentation/specs/rtc.md: -------------------------------------------------------------------------------- 1 | # RTC 2 | 3 | ## Registers 4 | 5 | | Offset | Size | Access | Description | 6 | |---------|------|--------|------------------------| 7 | | `0x000` | 1 | R | Current Day | 8 | | `0x001` | 1 | R | Current Month | 9 | | `0x002` | 2 | R | Current Year | 10 | | `0x004` | 1 | R | Current Hour | 11 | | `0x005` | 1 | R | Current Minute | 12 | | `0x006` | 1 | R | Set Data Day | 13 | | `0x007` | 1 | R | Set Data Month | 14 | | `0x008` | 2 | R | Set Data Year | 15 | | `0x00A` | 1 | R | Set Data Hour | 16 | | `0x00B` | 1 | R | Set Data Minute | 17 | | `0x00C` | 2 | RW | Control Register | 18 | 19 | ### `Control Register` 20 | 21 | | Bit Range | Description | 22 | |-----------|--------------------------------------------------------| 23 | | `[0]` | Write to `1` to write the time. Will always read as 0. | 24 | | `[15:1]` | *reserved*, must be 0 | -------------------------------------------------------------------------------- /documentation/specs/timer.md: -------------------------------------------------------------------------------- 1 | # Timer 2 | 3 | Each timer runs at a defined frequency that is not necessarily the cpu frequency. 4 | 5 | ## Registers 6 | 7 | | Offset | Size | Access | Description | 8 | |---------|------|--------|------------------------| 9 | | `0x000` | 2 | RW | Timer Value | 10 | | `0x002` | 2 | RW | Timer Limit | 11 | | `0x004` | 2 | RW | Prescaler | 12 | | `0x006` | 2 | RW | Control | 13 | 14 | `Timer Value` increments each time `Prescaler`-1 clocks have happened. When `Timer Value` reaches `Timer Limit`, the `Timer Value` is reset to 0 and a IRQ is raised if enabled. 15 | 16 | ### Status / Control 17 | 18 | | Bit Range | Description | 19 | |-----------|-----------------------| 20 | | `[0]` | Enable Timer | 21 | | `[1]` | Enable IRQ | 22 | | `[15:2]` | *reserved*, must be 0 | -------------------------------------------------------------------------------- /documentation/specs/uart.md: -------------------------------------------------------------------------------- 1 | 2 | # TinyUART 3 | 4 | A 16C550 compatible UART component. 5 | 6 | - [Features](#features) 7 | - [Registers](#registers) 8 | 9 | ## Features 10 | 11 | The TinyUART is a 16C550 compatible UART implementation that provides a fully featured UART interface including flow- and modem control. 12 | 13 | ## Registers 14 | 15 | | Offset | Name | Size | Access | Description | 16 | |---------|-------|------|--------|--------------------------------------------| 17 | | `0x000` | RBR | 1 | R | (DLAB=0) Receiver buffer | 18 | | `0x000` | THR | 1 | W | (DLAB=0) Transmitter holding register | 19 | | `0x001` | IER | 1 | R/W | (DLAB=0) Interrupt enable register | 20 | | `0x000` | DLL | 1 | R/W | (DLAB=1) Divisor latch (LSB) | 21 | | `0x001` | DLM | 1 | R/W | (DLAB=1) Divisor latch (MSB) | 22 | | `0x002` | IIR | 1 | R | Interrupt identification register | 23 | | `0x002` | FCR | 1 | W | FIFO control register | 24 | | `0x003` | LCR | 1 | R/W | Line control register | 25 | | `0x004` | MCR | 1 | R/W | Modem control register | 26 | | `0x005` | LSR | 1 | R | Line status register | 27 | | `0x006` | MSR | 1 | R | Modem status register | 28 | | `0x007` | SCR | 1 | R/W | Scratch register | 29 | 30 | -------------------------------------------------------------------------------- /documentation/specs/vga.md: -------------------------------------------------------------------------------- 1 | # BasicVGA 2 | 3 | Planned features: 4 | 5 | - Modes: 6 | - Graphic 256×128, 8bpp, 60 Hz 7 | - (*planned*) Graphic, 2bpp, 60 Hz 8 | - 256 color palette support for RGB565 9 | - Output signal is 640x480 with double scaling and a border color 10 | 11 | ``` 12 | # 640x480 59.38 Hz (CVT 0.31M3) hsync: 29.69 kHz; pclk: 23.75 MHz 13 | Modeline "640x480_60.00" 23.75 640 664 720 800 480 483 487 500 -hsync +vsync 14 | ``` 15 | 16 | # Registers 17 | 18 | | Offset | Size | Access | Description | 19 | |----------|------|--------|-----------------------| 20 | | `0x0000` | 4 | R/W | Framebuffer Address | 21 | | `0x0004` | 2 | R/W | Border Color | 22 | | `0x0006` | 1 | R | Status Register | 23 | | `0x0007` | 1 | W | Control Register | 24 | | `0x1000` | 2 | R/W | Palette Entry 0 | 25 | | `0x1***` | 2 | R/W | Palette Entry * | 26 | | `0x1FFE` | 2 | R/W | Palette Entry 255 | 27 | 28 | ## Framebuffer Address 29 | Start address of the linear framebuffer. The frame buffer 30 | is stored row-major, so the first 128 byte are the the first 31 | row of pixels. 32 | 33 | The address is in 24 bit address format, the upper 8 bit are 34 | ignored by the VGA module. Also, the address is in physical 35 | layout, so the memory must not be mapped to be visible. 36 | 37 | ## Status Register 38 | 39 | - 0: HighRes 40 | - 1: *unused* 41 | - 2: VSync Active 42 | - 3: HSync Active 43 | 44 | When *HighRes* is `1`, the graphic mode is switched from 256×128,8bpp to 512×256,2bpp. In this mode, only 4 colors are available, but the size is horizontally and vertically doubled. 45 | 46 | ## Control Register 47 | Mirror register of the status register that allows writing several control commands into the VGA. 48 | 49 | - 0: HighRes 50 | - 1: *unused* 51 | - 2: N/A 52 | - 3: N/A 53 | 54 | # Sprite Unit 55 | 56 | **This part of the document isn't written yet. Please consider this not even a working draft.** 57 | 58 | The sprite unit is a built into two parts: 59 | 60 | - A 4096 byte memory section that stores both sprite pixels and sprite definitions 61 | - A set of registers that enable up to 8 sprites 62 | 63 | Facts: 64 | 65 | - 4096 byte storage for sprite data (one page) 66 | - Sprite size can be set in steps of 4 pixels width and height 67 | - Sprite size can be from 4×4 to 64×64 pixels. 68 | - Sprites always use 255 colors from the palette, color 0 is transparent 69 | 70 | ```c 71 | struct SpriteDef { 72 | u16 pixeldata_addr; 73 | u16 next_sprite_addr; 74 | i16 x; 75 | i8 y; 76 | u4 width; 77 | u4 height; 78 | } 79 | ``` 80 | 81 | width = u4 & "00" 82 | height = u4 & "00" 83 | 84 | -------------------------------------------------------------------------------- /documentation/website/downloads.md: -------------------------------------------------------------------------------- 1 | # Downloads 2 | 3 | ## Toolchain 4 | 5 | This bundle contains all available tools, core libraries, manuals (in html format) and other documents. 6 | 7 | - [Windows 64bit](downloads/ashet-toolchain-windows-x86_64.zip) 8 | - [Linux 64bit](downloads/ashet-toolchain-linux-x86_64.zip) 9 | 10 | ## Emulator 11 | 12 | - [Windows 64bit](downloads/emulator-windows-x86_64.exe) 13 | - [Linux 64bit](downloads/emulator-linux-x86_64) 14 | 15 | ## Assembler 16 | 17 | - [Windows 64bit](downloads/assembler-windows-x86_64.exe) 18 | - [Linux 64bit](downloads/assembler-linux-x86_64) 19 | 20 | ## Disassembler 21 | 22 | - [Windows 64bit](downloads/disassembler-windows-x86_64.exe) 23 | - [Linux 64bit](downloads/disassembler-linux-x86_64) 24 | 25 | -------------------------------------------------------------------------------- /documentation/website/imprint.htm: -------------------------------------------------------------------------------- 1 |

Legal Disclosure

2 | Information in accordance with Section 5 TMG 3 |

Felix Queißner
Schellingstraße 13
72622 Nürtingen
4 |

Contact Information

5 | Telephone: 070229099654
E-Mail: imprint@ashet.computer
6 | 10 |

Disclaimer

11 | Accountability for content
12 | The contents of our pages have been created with the utmost care. However, we cannot guarantee the contents' 13 | accuracy, completeness or topicality. According to statutory provisions, we are furthermore responsible for 14 | our own content on these web pages. In this matter, please note that we are not obliged to monitor 15 | the transmitted or saved information of third parties, or investigate circumstances pointing to illegal activity. 16 | Our obligations to remove or block the use of information under generally applicable laws remain unaffected by this as 17 | per 18 | §§ 8 to 10 of the Telemedia Act (TMG). 19 | 20 |

Accountability for links
21 | Responsibility for the content of 22 | external links (to web pages of third parties) lies solely with the operators of the linked pages. No violations were 23 | evident to us at the time of linking. Should any legal infringement become known to us, we will remove the respective 24 | link immediately.

Copyright
Our web pages and their contents are subject to German copyright law. Unless 25 | expressly permitted by law, every form of utilizing, reproducing or processing 26 | works subject to copyright protection on our web pages requires the prior consent of the respective owner of the rights. 27 | Individual reproductions of a work are only allowed for private use. 28 | The materials from these pages are copyrighted and any unauthorized use may violate copyright laws. 29 | 30 |

31 | Source: Übersetzungsbüro translate-24h.de

-------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Ashet Home Computer 2 | site_url: https://ashet.computer/ 3 | site_author: Felix "xq" Queißner 4 | site_description: The Ashet Home Computer is a self-made late 80ies style inspired home computer with a 16 bit cpu. 5 | repo_url: https://github.com/MasterQ32/spu-mark-ii/ 6 | edit_uri: '' 7 | docs_dir: documentation 8 | site_dir: website-out 9 | 10 | nav: 11 | - 'Live Demo': livedemo.md 12 | - 'Documentation': 13 | - 'Specifications': 14 | - 'SPU Mark II': specs/spu-mark-ii.md 15 | - 'Ashet': specs/ashet.md 16 | - 'Datasheet': 17 | - 'TinyUART': specs/uart.md 18 | - 'SimpleMMU': specs/mmu.md 19 | - 'IRQ Controller': specs/irq.md 20 | - 'BasicVGA': specs/vga.md 21 | - 'PS/2': specs/ps2.md 22 | - 'OverkillDMA': specs/dma.md 23 | - 'Ethernet': specs/eth.md 24 | - 'IDE Interface': specs/ide.md 25 | - 'Joystick Interface': specs/joystick.md 26 | - 'IEEE 1284 II Parallel Port': specs/parport.md 27 | - 'PCM Audio': specs/pcm.md 28 | - 'Real Time Clock': specs/rtc.md 29 | - 'Timer': specs/timer.md 30 | - 'Application Notes': 31 | - 'AN000 - Understanding the Instruction Set': 'app-notes/AN000 - Understanding the Instruction Set.md' 32 | - 'AN001 - The SPU Assembly Language': 'app-notes/AN001 - The SPU Assembly Language.md' 33 | - 'AN002 - Standard Calling Convention': 'app-notes/AN002 - Standard Calling Convention.md' 34 | - 'AN003 - Writing efficient code': 'app-notes/AN003 - Writing efficient code.md' 35 | - 'Manuals': 36 | - 'Assembler': manuals/assembler.md 37 | - 'Disassembler': manuals/disassembler.md 38 | - 'Ashet Emulator': manuals/ashet-emulator.md 39 | - 'Basic System Emulator': manuals/basic-emulator.md 40 | - 'Ashet OS': 41 | - 'Overview': os/index.md 42 | - 'Syscalls': os/syscalls.md 43 | theme: 44 | name: mkdocs 45 | nav_style: light -------------------------------------------------------------------------------- /research-chamber/.gitignore: -------------------------------------------------------------------------------- 1 | *.hex 2 | *.bin 3 | -------------------------------------------------------------------------------- /research-chamber/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | pub fn build(b: *std.build.Builder) void { 4 | const exe = b.addExecutable("async-lpc", "src/main.zig"); 5 | exe.addPackage(std.build.Pkg{ 6 | .name = "lpc1768", 7 | .path = "libs/lpc1768/lpc1768.zig", 8 | }); 9 | exe.setTarget(std.zig.CrossTarget{ 10 | .cpu_arch = .thumb, 11 | .cpu_model = .{ 12 | .explicit = &std.Target.arm.cpu.cortex_m3, 13 | }, 14 | .os_tag = .freestanding, 15 | .abi = .eabi, 16 | }); 17 | exe.strip = true; 18 | exe.setBuildMode(.ReleaseSmall); 19 | exe.install(); 20 | exe.setLinkerScriptPath("./src/linker.ld"); 21 | 22 | const create_hex = b.addSystemCommand(&[_][]const u8{ 23 | "arm-none-eabi-objcopy", 24 | "-R", 25 | "stack", 26 | "-R", 27 | ".data", 28 | "-R", 29 | ".bss", 30 | "-R", 31 | ".debug_abbrev", 32 | "-O", 33 | "ihex", 34 | // "zig-cache/bin/async-lpc", 35 | // "async-lpc.hex", 36 | }); 37 | create_hex.addArtifactArg(exe); 38 | create_hex.addArg("firmware.hex"); 39 | 40 | const hex_step = b.step("hex", "Creates a flashable ihex file"); 41 | hex_step.dependOn(&create_hex.step); 42 | 43 | const create_bin = b.addSystemCommand(&[_][]const u8{ 44 | "arm-none-eabi-objcopy", 45 | "-I", 46 | "ihex", 47 | "-O", 48 | "binary", 49 | "firmware.hex", 50 | "firmware.bin", 51 | }); 52 | create_bin.step.dependOn(&create_hex.step); 53 | 54 | const bin_step = b.step("bin", "Creates a flashable binary file"); 55 | bin_step.dependOn(&create_bin.step); 56 | 57 | const flash_step = b.step("flash", "Creates a hex file and flashes it."); 58 | if (b.option([]const u8, "flash-drive", "If given, the file is deployed via mtools/fat32")) |file_name| { 59 | const copy_flash = b.addSystemCommand(&[_][]const u8{ 60 | "mcopy", 61 | "-D", 62 | "o", // override the file without asking 63 | "firmware.bin", // from firmware.bin 64 | "::firmware.bin", // to D:\firmware.bin 65 | "-i", // MUST BE LAST 66 | }); 67 | copy_flash.addArg(file_name); 68 | 69 | copy_flash.step.dependOn(&create_bin.step); 70 | 71 | flash_step.dependOn(©_flash.step); 72 | } else { 73 | 74 | // This is 100% machine dependant 75 | const run_flash = b.addSystemCommand(&[_][]const u8{ 76 | "flash-magic", 77 | "COM(5, 115200)", 78 | "DEVICE(LPC1768, 0.000000, 0)", 79 | "HARDWARE(BOOTEXEC, 50, 100)", 80 | "ERASEUSED(Z:\\home\\felix\\projects\\lowlevel\\async-lpc\\async-lpc.hex, PROTECTISP)", 81 | "HEXFILE(Z:\\home\\felix\\projects\\lowlevel\\async-lpc\\async-lpc.hex, NOCHECKSUMS, NOFILL, PROTECTISP)", 82 | }); 83 | run_flash.step.dependOn(&create_hex.step); 84 | 85 | flash_step.dependOn(&run_flash.step); 86 | } 87 | 88 | const run_term = b.addSystemCommand(&[_][]const u8{ 89 | "picocom", 90 | "--baud", 91 | "19200", 92 | "--lower-rts", // Disable programmer 93 | "--lower-dtr", // Disable reset 94 | "/dev/ttyUSB0", 95 | }); 96 | 97 | const term_step = b.step("terminal", "Starts picocom on the correct port"); 98 | term_step.dependOn(&run_term.step); 99 | } 100 | -------------------------------------------------------------------------------- /research-chamber/src/boot.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const lpc1768 = @import("lpc1768"); 3 | 4 | const ISRHandler = fn () callconv(.C) void; 5 | 6 | const start_of_ram = 0x10000000; 7 | const stack_size = 0x2000; 8 | const initial_sp = start_of_ram + stack_size; 9 | 10 | var mutable_vector_table: @TypeOf(fixed_vector_table) = undefined; 11 | 12 | extern var __bss__start: c_void; 13 | extern var __bss__end: c_void; 14 | extern var __text__end: c_void; 15 | extern var __data__start: c_void; 16 | extern var __data__end: c_void; 17 | 18 | export fn _start() callconv(.C) noreturn { 19 | mutable_vector_table = fixed_vector_table; 20 | 21 | lpc1768.SCB.VTOR = @ptrToInt(&mutable_vector_table); 22 | lpc1768.SCB.SHP[7] = 1; // SVC has less priority than all fault handlers 23 | lpc1768.SCB.SHCSR = 0x00070000; // enable fault handler 24 | 25 | const bss = @ptrCast([*]u8, &__bss__start)[0 .. @ptrToInt(&__bss__end) - @ptrToInt(&__bss__end)]; 26 | 27 | const ro_data = @ptrCast([*]const u8, &__text__end)[0 .. @ptrToInt(&__data__end) - @ptrToInt(&__data__start)]; 28 | const rw_data = @ptrCast([*]u8, &__data__start)[0..ro_data.len]; 29 | 30 | // BSS Segment löschen 31 | std.mem.set(u8, bss, 0); 32 | 33 | // Datasegment aus Flash in RAM kopieren 34 | std.mem.copy(u8, rw_data, ro_data); 35 | 36 | @import("root").main() catch |err| { 37 | @panic(@errorName(err)); 38 | }; 39 | while (true) { 40 | lpc1768.__disable_irq(); 41 | lpc1768.__disable_fault_irq(); 42 | lpc1768.__WFE(); 43 | } 44 | } 45 | 46 | export fn _nmi() callconv(.C) void { 47 | @panic("nmi"); 48 | } 49 | 50 | export fn _hardFault() callconv(.C) void { 51 | @panic("hard fault"); 52 | } 53 | 54 | export fn _mpuFault() callconv(.C) void { 55 | @panic("mpu fault"); 56 | } 57 | 58 | export fn _busFault() callconv(.C) void { 59 | @panic("bus fault"); 60 | } 61 | 62 | export fn _usageFault() callconv(.C) void { 63 | @panic("usage fault"); 64 | } 65 | 66 | export fn _unhandledInterrupt() callconv(.C) void { 67 | @panic("Unhandled interrupt!"); 68 | } 69 | 70 | comptime { 71 | _ = fixed_vector_table; 72 | } 73 | 74 | const VectorTable = extern struct { 75 | initial_stack_pointer: u32 = initial_sp, 76 | 77 | reset: ISRHandler = _start, 78 | nmi: ISRHandler = _nmi, 79 | hard_fault: ISRHandler = _hardFault, 80 | mpu_fault: ISRHandler = _mpuFault, 81 | bus_fault: ISRHandler = _busFault, 82 | usage_fault: ISRHandler = _usageFault, 83 | 84 | checksum: u32 = undefined, 85 | 86 | reserved0: u32 = 0, 87 | reserved1: u32 = 0, 88 | reserved2: u32 = 0, 89 | 90 | svcall: ISRHandler = _unhandledInterrupt, 91 | debug_monitor: ISRHandler = _unhandledInterrupt, 92 | 93 | reserved3: u32 = 0, 94 | 95 | pendsv: ISRHandler = _unhandledInterrupt, 96 | systick: ISRHandler = _unhandledInterrupt, 97 | 98 | wdt: ISRHandler = _unhandledInterrupt, 99 | timer0: ISRHandler = _unhandledInterrupt, 100 | timer1: ISRHandler = _unhandledInterrupt, 101 | timer2: ISRHandler = _unhandledInterrupt, 102 | timer3: ISRHandler = _unhandledInterrupt, 103 | uart0: ISRHandler = _unhandledInterrupt, 104 | uart1: ISRHandler = _unhandledInterrupt, 105 | uart2: ISRHandler = _unhandledInterrupt, 106 | uart3: ISRHandler = _unhandledInterrupt, 107 | pwm1: ISRHandler = _unhandledInterrupt, 108 | i2c0: ISRHandler = _unhandledInterrupt, 109 | i2c1: ISRHandler = _unhandledInterrupt, 110 | i2c2: ISRHandler = _unhandledInterrupt, 111 | spi: ISRHandler = _unhandledInterrupt, 112 | ssp0: ISRHandler = _unhandledInterrupt, 113 | ssp1: ISRHandler = _unhandledInterrupt, 114 | pll0: ISRHandler = _unhandledInterrupt, 115 | rtc: ISRHandler = _unhandledInterrupt, 116 | eint0: ISRHandler = _unhandledInterrupt, 117 | eint1: ISRHandler = _unhandledInterrupt, 118 | eint2: ISRHandler = _unhandledInterrupt, 119 | eint3: ISRHandler = _unhandledInterrupt, 120 | adc: ISRHandler = _unhandledInterrupt, 121 | bod: ISRHandler = _unhandledInterrupt, 122 | usb: ISRHandler = _unhandledInterrupt, 123 | can: ISRHandler = _unhandledInterrupt, 124 | dma: ISRHandler = _unhandledInterrupt, 125 | i2s: ISRHandler = _unhandledInterrupt, 126 | enet: ISRHandler = _unhandledInterrupt, 127 | rit: ISRHandler = _unhandledInterrupt, 128 | mcpwm: ISRHandler = _unhandledInterrupt, 129 | qei: ISRHandler = _unhandledInterrupt, 130 | pll1: ISRHandler = _unhandledInterrupt, 131 | }; 132 | 133 | export const fixed_vector_table: VectorTable linksection(".isr_vector") = VectorTable{}; 134 | -------------------------------------------------------------------------------- /research-chamber/src/linker.ld: -------------------------------------------------------------------------------- 1 | /******************************************* 2 | Memory Definitions für LPC 1768 3 | *******************************************/ 4 | MEMORY 5 | { 6 | flash (RX) : ORIGIN = 0x00000000, LENGTH = 512k 7 | ram (RW) : ORIGIN = 0x10000000, LENGTH = 16K 8 | ahbram (RW) : ORIGIN = 0x2007C040, LENGTH = 32K-64-32 9 | } 10 | 11 | /* 12 | * IAP routine location. 1 makes the routine a thumb routine! 13 | */ 14 | IAP = 0x1FFF1FF1; 15 | 16 | /******************************************* 17 | Section Definitions 18 | *******************************************/ 19 | SECTIONS 20 | { 21 | . = 0; 22 | .text : 23 | { 24 | . = ALIGN(4); 25 | __code_start__ = .; 26 | 27 | KEEP(*( .isr_vector )); 28 | 29 | *(.text) 30 | *(.text.*) 31 | 32 | . = ALIGN(4); 33 | __code_end__ = .; 34 | 35 | *(.gnu.linkonce.t.*) 36 | *(.glue_7) 37 | *(.glue_7t) 38 | *(.gcc_except_table) 39 | *(.gnu.linkonce.r.*) 40 | 41 | } >flash 42 | 43 | . = ALIGN(16); 44 | .ARM.exidx : 45 | { 46 | . = ALIGN(4); 47 | __exidx_start = .; 48 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 49 | __exidx_end = .; 50 | . = ALIGN(4); 51 | } >flash 52 | 53 | . = ALIGN(16); 54 | .rodata : 55 | { 56 | . = ALIGN(4); 57 | *(.rodata) 58 | 59 | . = ALIGN(4); 60 | *(.rodata.*) 61 | 62 | PROVIDE(start_ctors = .); 63 | KEEP(*( .init_array )); 64 | KEEP(*(SORT_BY_INIT_PRIORITY( .init_array.* ))); 65 | PROVIDE(end_ctors = .); 66 | 67 | PROVIDE(start_dtors = .); 68 | KEEP(*( .fini_array )); 69 | KEEP(*(SORT_BY_INIT_PRIORITY( .fini_array.* ))); 70 | PROVIDE(end_dtors = .); 71 | . = ALIGN(4); 72 | } >flash 73 | 74 | . = ALIGN(4); 75 | _etext = . ; 76 | 77 | PROVIDE (__text__end = .); 78 | 79 | . = ALIGN(16); 80 | stack : 81 | { 82 | ASSERT((. == 0x10000000), "Error: Stack must be located at the start of the RAM!") 83 | . += 0x2000; 84 | } >ram 85 | 86 | . = ALIGN(16); 87 | .data : AT (_etext) 88 | { 89 | __data_start__ = . ; 90 | PROVIDE (__data__start = .) ; 91 | 92 | *(.data) 93 | *(.data.*) 94 | *(.gnu.linkonce.d*) 95 | SORT(CONSTRUCTORS) 96 | __data_end__ = . ; 97 | PROVIDE (__data__end = .); 98 | } >ram 99 | 100 | . = ALIGN(4); 101 | _edata = . ; 102 | 103 | . = ALIGN(16); 104 | .bss : 105 | { 106 | __bss_start__ = . ; 107 | PROVIDE (__bss__start = .); 108 | 109 | *(.bss) 110 | *(.bss.*) 111 | *(.gnu.linkonce.b*) 112 | . = ALIGN(4); 113 | __bss_end__ = . ; 114 | PROVIDE (__bss__end = .); 115 | } >ram 116 | 117 | _end = .; 118 | PROVIDE (end = .); 119 | 120 | /************** AHBRAM **************************/ 121 | ahb_ram : AT (ORIGIN(ahbram)) { 122 | *(.ahb) 123 | } >ahbram 124 | } 125 | 126 | -------------------------------------------------------------------------------- /resources/castle.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/resources/castle.bit -------------------------------------------------------------------------------- /resources/castle.pcx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/resources/castle.pcx -------------------------------------------------------------------------------- /resources/example.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/resources/example.bit -------------------------------------------------------------------------------- /resources/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/resources/example.png -------------------------------------------------------------------------------- /resources/keen.pcx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/resources/keen.pcx -------------------------------------------------------------------------------- /scratchpad/scratch.asm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | .dw 10 5 | .dw 10+10 6 | .dw 10*10 7 | .dw 10-5 8 | .dw 5+10*10 ; => 105 9 | .dw 5*10+10 ; => 60 10 | 11 | .equ twenty, 20 12 | .equ ten, 10 13 | 14 | .dw twenty + ten * 10 15 | .dw 1 << 8 16 | .dw 255 & (1<<4) 17 | 18 | -------------------------------------------------------------------------------- /soc/vhdl/.floorplanner.ini: -------------------------------------------------------------------------------- 1 | [General] 2 | showNCD=true 3 | showPgroups=true 4 | showCongestion=false 5 | showConnsSelect=true 6 | showConnsBetween=true 7 | showConnsOutside=true 8 | showLPF=true 9 | showREGIONs=true 10 | showUGROUPs=true 11 | showPARITIONs=true 12 | showLogicalConnections=false 13 | dontShowBBoxOverlapWarning=false 14 | sceneInViewRect="@Variant(\0\0\0\x14\xc0\xc3\x35\x8c\x91\xe\0\xb7@\xba\xa3\0[\xeau\fA\a_\x4\x9fj\xa3\0@\xf7\x15\x41;\xf5\xf2Z)" 15 | -------------------------------------------------------------------------------- /soc/vhdl/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | impl*/ 3 | *.xml 4 | .build_status 5 | .run_manager.ini 6 | .recovery 7 | *.dir/ 8 | *.log 9 | *.tcl 10 | *.ccl 11 | *.srp 12 | firstdesign 13 | *.o 14 | *.ghw 15 | testbench 16 | *.sort 17 | work-*.cf 18 | testbench_* 19 | debugging/ 20 | *.lst 21 | *.sty 22 | testbench_fifo 23 | testbench_spu*.mem 24 | -------------------------------------------------------------------------------- /soc/vhdl/.ncd_editor.ini: -------------------------------------------------------------------------------- 1 | [SysIOView] 2 | Type=100 3 | Name=100 4 | Pin=100 5 | Bank=100 6 | IO_TYPE=100 7 | PULLMODE=100 8 | DRIVE=100 9 | SLEWRATE=100 10 | OPENDRAIN=100 11 | SortColumns="1," 12 | CLAMP=100 13 | DIFFRESISTOR=100 14 | DIFFDRIVE=100 15 | BANK_VCCIO=100 16 | HYSTERESIS=100 17 | 18 | [PLLView] 19 | Type=100 20 | Name=100 21 | SortColumns="2," 22 | 23 | [MemoryTreeView] 24 | EBR%20Configuration=117 25 | Setting=58 26 | -------------------------------------------------------------------------------- /soc/vhdl/.setting.ini: -------------------------------------------------------------------------------- 1 | [General] 2 | AutoAssign=true 3 | PAR.auto_tasks=PARTrace 4 | Export.auto_tasks=Bitgen, Jedecgen 5 | Map.auto_tasks=MapTrace 6 | -------------------------------------------------------------------------------- /soc/vhdl/.spread_sheet.ini: -------------------------------------------------------------------------------- 1 | [General] 2 | COLUMN_POS_INFO_NAME_-1_0=Prioritize 3 | COLUMN_POS_INFO_NAME_-1_1=PIO Register 4 | -------------------------------------------------------------------------------- /soc/vhdl/.spreadsheet_view.ini: -------------------------------------------------------------------------------- 1 | [General] 2 | pin_sort_type=0 3 | pin_sort_ascending=true 4 | sig_sort_type=0 5 | sig_sort_ascending=true 6 | active_Sheet=Global Preferences 7 | 8 | [Port%20Assignments] 9 | Name="198,0" 10 | Group%20By="98,1" 11 | Pin="66,2" 12 | BANK="74,3" 13 | IO_TYPE="147,4" 14 | PULLMODE="110,5" 15 | DRIVE="77,9" 16 | SLEWRATE="107,6" 17 | OPENDRAIN="116,10" 18 | Outload%20%28pF%29="121,11" 19 | MaxSkew="99,14" 20 | Clock%20Load%20Only="143,13" 21 | sort_columns="Name,Ascending" 22 | BANK_VCC="106,7" 23 | VREF="70,8" 24 | CLAMP="82,12" 25 | DIFFRESISTOR="133,15" 26 | DIFFDRIVE="107,16" 27 | HYSTERESIS="118,17" 28 | SwitchingID="116,18" 29 | Ground%20plane%20PCB%20noise%20%28mV%29="235,19" 30 | Power%20plane%20PCB%20noise%20%28mV%29="227,20" 31 | SSO%20Allowance%28%25%29="158,21" 32 | 33 | [Pin%20Assignments] 34 | Pin="97,0" 35 | Pad%20Name="104,1" 36 | Dual%20Function="264,2" 37 | Polarity="88,3" 38 | BANK="0,4" 39 | IO_TYPE="147,5" 40 | Signal%20Name="185,6" 41 | Signal%20Type="115,7" 42 | sort_columns="Signal Name,Descending" 43 | BANK_VCC="106,8" 44 | 45 | [Clock%20Resource] 46 | Clock%20Type="100,ELLIPSIS" 47 | Clock%20Name="234,ELLIPSIS" 48 | Selection="100,ELLIPSIS" 49 | 50 | [Global%20Preferences] 51 | Preference%20Name="233,ELLIPSIS" 52 | Preference%20Value="226,ELLIPSIS" 53 | 54 | [Cell%20Mapping] 55 | Type="100,ELLIPSIS" 56 | Name="100,ELLIPSIS" 57 | Din\Dout="100,ELLIPSIS" 58 | PIO%20Register="100,ELLIPSIS" 59 | 60 | [Route%20Priority] 61 | Type="100,ELLIPSIS" 62 | Name="100,ELLIPSIS" 63 | Prioritize="100,ELLIPSIS" 64 | 65 | [Timing%20Preferences] 66 | Preference%20Name="139,ELLIPSIS" 67 | Preference%20Value="124,ELLIPSIS" 68 | Preference%20Unit="1189,ELLIPSIS" 69 | 70 | [Group] 71 | Group%20Type\Name="134,ELLIPSIS" 72 | Value="46,ELLIPSIS" 73 | 74 | [Misc%20Preferences] 75 | Preference%20Name="125,ELLIPSIS" 76 | Preference%20Value="124,ELLIPSIS" 77 | -------------------------------------------------------------------------------- /soc/vhdl/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #setup all the environment variable required by Diamond and related executable files 3 | #version 1.6 4 | 5 | ROOT_PATH="/usr/local/diamond/3.11_x64" 6 | 7 | FPGADIR="${ROOT_PATH}/bin/lin64" 8 | 9 | export "FOUNDRY=${ROOT_PATH}/ispfpga/bin/lin64/" 10 | 11 | export "PATH=${FOUNDRY}:${FPGADIR}:$PATH" 12 | LD_LIBRARY_PATH="${FOUNDRY}:${FPGADIR}:${LD_LIBRARY_PATH}" 13 | 14 | unset LSC_INI_PATH 15 | 16 | #setup LSC_DIAMOND 17 | export LSC_DIAMOND=true 18 | 19 | #fix RH7 incompatible Qt library issue 20 | export QT_PLUGIN_PATH= 21 | 22 | #set the output max line width 23 | export NEOCAD_MAXLINEWIDTH=32767 24 | 25 | #setup tcl library 26 | TCL_LIBRARY="${ROOT_PATH}/tcltk/lib/tcl8.5" 27 | export TCL_LIBRARY 28 | -------------------------------------------------------------------------------- /soc/vhdl/firmware.mem: -------------------------------------------------------------------------------- 1 | 0 : 4008 0004 0A28 F002 7F01 0A28 F010 8001 2 | 8 : 0A28 F012 8011 0A28 F014 8021 0A28 F016 3 | 10 : 8031 0A28 F018 8041 0A28 F01A 8051 0A28 4 | 18 : F01C 8061 0A28 F01E 8071 0A28 1004 7FD1 5 | 20 : 0A28 2000 0000 0A28 2002 0080 0A28 100E 6 | 28 : 8101 0A28 1008 7F21 1E08 8000 1A08 8000 7 | 30 : 0A28 4000 0048 0A28 4000 0065 0A28 4000 8 | 38 : 006C 0A28 4000 006C 0A28 4000 006F 0A28 9 | 40 : 4000 000D 0A28 4000 000A 0108 0080 0108 10 | 48 : 8000 0110 3910 2F78 0508 FFFF 2178 0508 11 | 50 : FFFE 0878 21B8 0001 400A 0092 0018 0018 12 | 58 : 0F08 2004 2338 0100 0A68 2004 0108 0000 13 | 60 : 21B8 0001 400A 00C0 4008 00B0 14 | 280 : 0000 0000 4008 0500 15 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/dist_boot_rom.ipx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/dist_boot_rom.jhd: -------------------------------------------------------------------------------- 1 | MODULE dist_boot_rom DEFIN dist_boot_rom.vhd 2 | SUBMODULE MUX41 3 | INSTANCE mux_0 4 | SUBMODULE MUX41 5 | INSTANCE mux_1 6 | SUBMODULE MUX41 7 | INSTANCE mux_2 8 | SUBMODULE MUX41 9 | INSTANCE mux_3 10 | SUBMODULE MUX41 11 | INSTANCE mux_4 12 | SUBMODULE MUX41 13 | INSTANCE mux_5 14 | SUBMODULE MUX41 15 | INSTANCE mux_6 16 | SUBMODULE MUX41 17 | INSTANCE mux_7 18 | SUBMODULE MUX41 19 | INSTANCE mux_8 20 | SUBMODULE MUX41 21 | INSTANCE mux_9 22 | SUBMODULE MUX41 23 | INSTANCE mux_10 24 | SUBMODULE MUX41 25 | INSTANCE mux_11 26 | SUBMODULE MUX41 27 | INSTANCE mux_12 28 | SUBMODULE MUX41 29 | INSTANCE mux_13 30 | SUBMODULE MUX41 31 | INSTANCE mux_14 32 | SUBMODULE MUX41 33 | INSTANCE mux_15 34 | SUBMODULE ROM256X1A 35 | INSTANCE mem_3_0 36 | SUBMODULE ROM256X1A 37 | INSTANCE mem_3_1 38 | SUBMODULE ROM256X1A 39 | INSTANCE mem_3_2 40 | SUBMODULE ROM256X1A 41 | INSTANCE mem_3_3 42 | SUBMODULE ROM256X1A 43 | INSTANCE mem_3_4 44 | SUBMODULE ROM256X1A 45 | INSTANCE mem_3_5 46 | SUBMODULE ROM256X1A 47 | INSTANCE mem_3_6 48 | SUBMODULE ROM256X1A 49 | INSTANCE mem_3_7 50 | SUBMODULE ROM256X1A 51 | INSTANCE mem_3_8 52 | SUBMODULE ROM256X1A 53 | INSTANCE mem_3_9 54 | SUBMODULE ROM256X1A 55 | INSTANCE mem_3_10 56 | SUBMODULE ROM256X1A 57 | INSTANCE mem_3_11 58 | SUBMODULE ROM256X1A 59 | INSTANCE mem_3_12 60 | SUBMODULE ROM256X1A 61 | INSTANCE mem_3_13 62 | SUBMODULE ROM256X1A 63 | INSTANCE mem_3_14 64 | SUBMODULE ROM256X1A 65 | INSTANCE mem_3_15 66 | SUBMODULE ROM256X1A 67 | INSTANCE mem_2_0 68 | SUBMODULE ROM256X1A 69 | INSTANCE mem_2_1 70 | SUBMODULE ROM256X1A 71 | INSTANCE mem_2_2 72 | SUBMODULE ROM256X1A 73 | INSTANCE mem_2_3 74 | SUBMODULE ROM256X1A 75 | INSTANCE mem_2_4 76 | SUBMODULE ROM256X1A 77 | INSTANCE mem_2_5 78 | SUBMODULE ROM256X1A 79 | INSTANCE mem_2_6 80 | SUBMODULE ROM256X1A 81 | INSTANCE mem_2_7 82 | SUBMODULE ROM256X1A 83 | INSTANCE mem_2_8 84 | SUBMODULE ROM256X1A 85 | INSTANCE mem_2_9 86 | SUBMODULE ROM256X1A 87 | INSTANCE mem_2_10 88 | SUBMODULE ROM256X1A 89 | INSTANCE mem_2_11 90 | SUBMODULE ROM256X1A 91 | INSTANCE mem_2_12 92 | SUBMODULE ROM256X1A 93 | INSTANCE mem_2_13 94 | SUBMODULE ROM256X1A 95 | INSTANCE mem_2_14 96 | SUBMODULE ROM256X1A 97 | INSTANCE mem_2_15 98 | SUBMODULE ROM256X1A 99 | INSTANCE mem_1_0 100 | SUBMODULE ROM256X1A 101 | INSTANCE mem_1_1 102 | SUBMODULE ROM256X1A 103 | INSTANCE mem_1_2 104 | SUBMODULE ROM256X1A 105 | INSTANCE mem_1_3 106 | SUBMODULE ROM256X1A 107 | INSTANCE mem_1_4 108 | SUBMODULE ROM256X1A 109 | INSTANCE mem_1_5 110 | SUBMODULE ROM256X1A 111 | INSTANCE mem_1_6 112 | SUBMODULE ROM256X1A 113 | INSTANCE mem_1_7 114 | SUBMODULE ROM256X1A 115 | INSTANCE mem_1_8 116 | SUBMODULE ROM256X1A 117 | INSTANCE mem_1_9 118 | SUBMODULE ROM256X1A 119 | INSTANCE mem_1_10 120 | SUBMODULE ROM256X1A 121 | INSTANCE mem_1_11 122 | SUBMODULE ROM256X1A 123 | INSTANCE mem_1_12 124 | SUBMODULE ROM256X1A 125 | INSTANCE mem_1_13 126 | SUBMODULE ROM256X1A 127 | INSTANCE mem_1_14 128 | SUBMODULE ROM256X1A 129 | INSTANCE mem_1_15 130 | SUBMODULE ROM256X1A 131 | INSTANCE mem_0_0 132 | SUBMODULE ROM256X1A 133 | INSTANCE mem_0_1 134 | SUBMODULE ROM256X1A 135 | INSTANCE mem_0_2 136 | SUBMODULE ROM256X1A 137 | INSTANCE mem_0_3 138 | SUBMODULE ROM256X1A 139 | INSTANCE mem_0_4 140 | SUBMODULE ROM256X1A 141 | INSTANCE mem_0_5 142 | SUBMODULE ROM256X1A 143 | INSTANCE mem_0_6 144 | SUBMODULE ROM256X1A 145 | INSTANCE mem_0_7 146 | SUBMODULE ROM256X1A 147 | INSTANCE mem_0_8 148 | SUBMODULE ROM256X1A 149 | INSTANCE mem_0_9 150 | SUBMODULE ROM256X1A 151 | INSTANCE mem_0_10 152 | SUBMODULE ROM256X1A 153 | INSTANCE mem_0_11 154 | SUBMODULE ROM256X1A 155 | INSTANCE mem_0_12 156 | SUBMODULE ROM256X1A 157 | INSTANCE mem_0_13 158 | SUBMODULE ROM256X1A 159 | INSTANCE mem_0_14 160 | SUBMODULE ROM256X1A 161 | INSTANCE mem_0_15 162 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/dist_boot_rom.lpc: -------------------------------------------------------------------------------- 1 | [Device] 2 | Family=machxo3lf 3 | PartType=LCMXO3LF-6900C 4 | PartName=LCMXO3LF-6900C-6BG256I 5 | SpeedGrade=6 6 | Package=CABGA256 7 | OperatingCondition=IND 8 | Status=S 9 | 10 | [IP] 11 | VendorName=Lattice Semiconductor Corporation 12 | CoreType=LPM 13 | CoreStatus=Demo 14 | CoreName=Distributed_ROM 15 | CoreRevision=2.8 16 | ModuleName=dist_boot_rom 17 | SourceFormat=VHDL 18 | ParameterFileVersion=1.0 19 | Date=05/12/2020 20 | Time=01:03:19 21 | 22 | [Parameters] 23 | Verilog=0 24 | VHDL=1 25 | EDIF=1 26 | Destination=Synplicity 27 | Expression=BusA(0 to 7) 28 | Order=Big Endian [MSB:LSB] 29 | IO=0 30 | Addresses=1024 31 | Data=16 32 | LUT=0 33 | MemFile=/home/felix/projects/lowlevel/spu-mark-2/soc/hw/firmware.mem 34 | MemFormat=orca 35 | 36 | [FilesGenerated] 37 | /home/felix/projects/lowlevel/spu-mark-2/soc/hw/firmware.mem=mem 38 | 39 | [Command] 40 | cmd_line= -w -n dist_boot_rom -lang vhdl -synth lse -bus_exp 7 -bb -arch xo3c00f -dram -type romblk -addr_width 10 -num_words 1024 -data_width 16 -outdata UNREGISTERED -memfile /home/felix/projects/lowlevel/spu-mark-2/soc/hw/firmware.mem -memformat orca 41 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/dist_boot_rom.naf: -------------------------------------------------------------------------------- 1 | Address[9] i 2 | Address[8] i 3 | Address[7] i 4 | Address[6] i 5 | Address[5] i 6 | Address[4] i 7 | Address[3] i 8 | Address[2] i 9 | Address[1] i 10 | Address[0] i 11 | Q[15] o 12 | Q[14] o 13 | Q[13] o 14 | Q[12] o 15 | Q[11] o 16 | Q[10] o 17 | Q[9] o 18 | Q[8] o 19 | Q[7] o 20 | Q[6] o 21 | Q[5] o 22 | Q[4] o 23 | Q[3] o 24 | Q[2] o 25 | Q[1] o 26 | Q[0] o 27 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/dist_boot_rom.sym: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/soc/vhdl/ip-cores/dist_boot_rom.sym -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/dist_boot_rom_tmpl.vhd: -------------------------------------------------------------------------------- 1 | -- VHDL module instantiation generated by SCUBA Diamond (64-bit) 3.11.2.446.3 2 | -- Module Version: 2.8 3 | -- Tue May 12 01:03:19 2020 4 | 5 | -- parameterized module component declaration 6 | component dist_boot_rom 7 | port (Address: in std_logic_vector(9 downto 0); 8 | Q: out std_logic_vector(15 downto 0)); 9 | end component; 10 | 11 | -- parameterized module component instance 12 | __ : dist_boot_rom 13 | port map (Address(9 downto 0)=>__, Q(15 downto 0)=>__); 14 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/embedded_function_block.ipx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/embedded_function_block.jhd: -------------------------------------------------------------------------------- 1 | MODULE embedded_function_block DEFIN embedded_function_block.vhd 2 | SUBMODULE EFB 3 | INSTANCE EFBInst_0 4 | SUBMODULE VLO 5 | INSTANCE scuba_vlo_inst 6 | SUBMODULE VHI 7 | INSTANCE scuba_vhi_inst 8 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/embedded_function_block.lpc: -------------------------------------------------------------------------------- 1 | [Device] 2 | Family=machxo3lf 3 | PartType=LCMXO3LF-6900C 4 | PartName=LCMXO3LF-6900C-6BG256I 5 | SpeedGrade=6 6 | Package=CABGA256 7 | OperatingCondition=IND 8 | Status=S 9 | 10 | [IP] 11 | VendorName=Lattice Semiconductor Corporation 12 | CoreType=LPM 13 | CoreStatus=Demo 14 | CoreName=EFB 15 | CoreRevision=1.2 16 | ModuleName=embedded_function_block 17 | SourceFormat=VHDL 18 | ParameterFileVersion=1.0 19 | Date=04/25/2020 20 | Time=13:30:31 21 | 22 | [Parameters] 23 | Verilog=0 24 | VHDL=1 25 | EDIF=1 26 | Destination=Synplicity 27 | Expression=BusA(0 to 7) 28 | Order=Big Endian [MSB:LSB] 29 | IO=0 30 | freq= 31 | i2c1=0 32 | i2c1config=0 33 | i2c1_addr=7-Bit Addressing 34 | i2c1_ce=0 35 | i2c1_freq=100 36 | i2c1_sa=10000 37 | i2c1_we=0 38 | i2c2=0 39 | i2c2_addr=7-Bit Addressing 40 | i2c2_ce=0 41 | i2c2_freq=100 42 | i2c2_sa=10000 43 | i2c2_we=0 44 | ufm_addr=7-Bit Addressing 45 | ufm_sa=10000 46 | pll=0 47 | pll_cnt=1 48 | spi=0 49 | spi_clkinv=0 50 | spi_cs=1 51 | spi_en=0 52 | spi_freq=1 53 | spi_lsb=0 54 | spi_mode=Slave 55 | spi_ib=0 56 | spi_ph=0 57 | spi_hs=0 58 | spi_rxo=0 59 | spi_rxr=0 60 | spi_txo=0 61 | spi_txr=0 62 | spi_we=0 63 | static_tc=Dynamic 64 | tc=0 65 | tc_clkinv=Positive 66 | tc_ctr=1 67 | tc_div=0 68 | tc_ipcap=0 69 | tc_mode=CTCM 70 | tc_ocr=32767 71 | tc_oflow=0 72 | tc_o=TOGGLE 73 | tc_opcomp=0 74 | tc_osc=0 75 | tc_sa_oflow=0 76 | tc_top=65535 77 | ufm=1 78 | ufm0=0 79 | ufm1=0 80 | ufm2=0 81 | ufm3=0 82 | ufm_cfg0=0 83 | ufm_cfg1=0 84 | wb_clk_freq=12 85 | ufm_usage=SHARED_EBR_TAG 86 | ufm_ebr=2045 87 | ufm_remain= 88 | mem_size=1 89 | ufm_start= 90 | ufm_init=0 91 | memfile= 92 | ufm_dt=hex 93 | ufm0_ebr= 94 | mem_size0=1 95 | ufm0_init=0 96 | memfile0= 97 | ufm0_dt=hex 98 | ufm1_ebr= 99 | mem_size1=1 100 | ufm1_init=0 101 | memfile1= 102 | ufm1_dt=hex 103 | ufm2_ebr= 104 | mem_size2=1 105 | ufm2_init=0 106 | memfile2= 107 | ufm2_dt=hex 108 | ufm3_ebr= 109 | mem_size3=1 110 | ufm3_init=0 111 | memfile3= 112 | ufm3_dt=hex 113 | ufm_cfg0_ebr= 114 | mem_size_cfg0=1 115 | ufm_cfg0_init=0 116 | memfile_cfg0= 117 | ufm_cfg0_dt=hex 118 | ufm_cfg1_ebr= 119 | mem_size_cfg1=1 120 | ufm_cfg1_init=0 121 | memfile_cfg1= 122 | ufm_cfg1_dt=hex 123 | wb=1 124 | boot_option=Internal 125 | efb_ufm=0 126 | boot_option_internal=Single Boot 127 | internal_ufm0=0 128 | internal_ufm1=0 129 | efb_ufm_boot= 130 | tamperdr=0 131 | t_pwd=0 132 | t_lockflash=0 133 | t_manmode=0 134 | t_jtagport=0 135 | t_sspiport=0 136 | t_sic2port=0 137 | t_wbport=0 138 | t_portlock=0 139 | 140 | [Command] 141 | cmd_line= -w -n embedded_function_block -lang vhdl -synth lse -bus_exp 7 -bb -type efb -arch xo3c00f -freq 12 -ufm -ufm_ebr 2045 -mem_size 1 -ufm_0 -wb -dev 6900 142 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/embedded_function_block.naf: -------------------------------------------------------------------------------- 1 | wb_clk_i i 2 | wb_rst_i i 3 | wb_cyc_i i 4 | wb_stb_i i 5 | wb_we_i i 6 | wb_adr_i[7] i 7 | wb_adr_i[6] i 8 | wb_adr_i[5] i 9 | wb_adr_i[4] i 10 | wb_adr_i[3] i 11 | wb_adr_i[2] i 12 | wb_adr_i[1] i 13 | wb_adr_i[0] i 14 | wb_dat_i[7] i 15 | wb_dat_i[6] i 16 | wb_dat_i[5] i 17 | wb_dat_i[4] i 18 | wb_dat_i[3] i 19 | wb_dat_i[2] i 20 | wb_dat_i[1] i 21 | wb_dat_i[0] i 22 | wb_dat_o[7] o 23 | wb_dat_o[6] o 24 | wb_dat_o[5] o 25 | wb_dat_o[4] o 26 | wb_dat_o[3] o 27 | wb_dat_o[2] o 28 | wb_dat_o[1] o 29 | wb_dat_o[0] o 30 | wb_ack_o o 31 | wbc_ufm_irq o 32 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/embedded_function_block.sym: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/soc/vhdl/ip-cores/embedded_function_block.sym -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/embedded_function_block_tmpl.vhd: -------------------------------------------------------------------------------- 1 | -- VHDL module instantiation generated by SCUBA Diamond (64-bit) 3.11.2.446.3 2 | -- Module Version: 1.2 3 | -- Sat Apr 25 13:30:31 2020 4 | 5 | -- parameterized module component declaration 6 | component embedded_function_block 7 | port (wb_clk_i: in std_logic; wb_rst_i: in std_logic; 8 | wb_cyc_i: in std_logic; wb_stb_i: in std_logic; 9 | wb_we_i: in std_logic; 10 | wb_adr_i: in std_logic_vector(7 downto 0); 11 | wb_dat_i: in std_logic_vector(7 downto 0); 12 | wb_dat_o: out std_logic_vector(7 downto 0); 13 | wb_ack_o: out std_logic; wbc_ufm_irq: out std_logic); 14 | end component; 15 | 16 | -- parameterized module component instance 17 | __ : embedded_function_block 18 | port map (wb_clk_i=>__, wb_rst_i=>__, wb_cyc_i=>__, wb_stb_i=>__, 19 | wb_we_i=>__, wb_adr_i(7 downto 0)=>__, wb_dat_i(7 downto 0)=>__, 20 | wb_dat_o(7 downto 0)=>__, wb_ack_o=>__, wbc_ufm_irq=>__); 21 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/fastram_ebr.ipx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/fastram_ebr.jhd: -------------------------------------------------------------------------------- 1 | MODULE fastram_ebr DEFIN fastram_ebr.vhd 2 | SUBMODULE MUX41 3 | INSTANCE mux_0 4 | SUBMODULE MUX41 5 | INSTANCE mux_1 6 | SUBMODULE MUX41 7 | INSTANCE mux_2 8 | SUBMODULE MUX41 9 | INSTANCE mux_3 10 | SUBMODULE MUX41 11 | INSTANCE mux_4 12 | SUBMODULE MUX41 13 | INSTANCE mux_5 14 | SUBMODULE MUX41 15 | INSTANCE mux_6 16 | SUBMODULE MUX41 17 | INSTANCE mux_7 18 | SUBMODULE MUX41 19 | INSTANCE mux_8 20 | SUBMODULE MUX41 21 | INSTANCE mux_9 22 | SUBMODULE MUX41 23 | INSTANCE mux_10 24 | SUBMODULE MUX41 25 | INSTANCE mux_11 26 | SUBMODULE MUX41 27 | INSTANCE mux_12 28 | SUBMODULE MUX41 29 | INSTANCE mux_13 30 | SUBMODULE MUX41 31 | INSTANCE mux_14 32 | SUBMODULE MUX41 33 | INSTANCE mux_15 34 | SUBMODULE FD1P3DX 35 | INSTANCE FF_0 36 | SUBMODULE VLO 37 | INSTANCE scuba_vlo_inst 38 | SUBMODULE FD1P3DX 39 | INSTANCE FF_1 40 | SUBMODULE DP8KC 41 | INSTANCE fastram_ebr_3_1_0 42 | SUBMODULE VHI 43 | INSTANCE scuba_vhi_inst 44 | SUBMODULE DP8KC 45 | INSTANCE fastram_ebr_3_0_1 46 | SUBMODULE DP8KC 47 | INSTANCE fastram_ebr_2_1_2 48 | SUBMODULE DP8KC 49 | INSTANCE fastram_ebr_2_0_3 50 | SUBMODULE DP8KC 51 | INSTANCE fastram_ebr_1_1_4 52 | SUBMODULE DP8KC 53 | INSTANCE fastram_ebr_1_0_5 54 | SUBMODULE DP8KC 55 | INSTANCE fastram_ebr_0_1_6 56 | SUBMODULE DP8KC 57 | INSTANCE fastram_ebr_0_0_7 58 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/fastram_ebr.lpc: -------------------------------------------------------------------------------- 1 | [Device] 2 | Family=machxo3lf 3 | PartType=LCMXO3LF-6900C 4 | PartName=LCMXO3LF-6900C-6BG256I 5 | SpeedGrade=6 6 | Package=CABGA256 7 | OperatingCondition=IND 8 | Status=S 9 | 10 | [IP] 11 | VendorName=Lattice Semiconductor Corporation 12 | CoreType=LPM 13 | CoreStatus=Demo 14 | CoreName=RAM_DQ 15 | CoreRevision=7.5 16 | ModuleName=fastram_ebr 17 | SourceFormat=VHDL 18 | ParameterFileVersion=1.0 19 | Date=04/25/2020 20 | Time=14:19:28 21 | 22 | [Parameters] 23 | Verilog=0 24 | VHDL=1 25 | EDIF=1 26 | Destination=Synplicity 27 | Expression=BusA(0 to 7) 28 | Order=Big Endian [MSB:LSB] 29 | IO=0 30 | Address=4096 31 | Data=16 32 | enByte=1 33 | ByteSize=8 34 | OutputEn=0 35 | ClockEn=0 36 | Optimization=Speed 37 | Reset=Sync 38 | Reset1=Sync 39 | Init=0 40 | MemFile= 41 | MemFormat=orca 42 | EnECC=0 43 | Pipeline=0 44 | Write=WriteThrough 45 | init_data=0 46 | no_init=0 47 | 48 | [FilesGenerated] 49 | =mem 50 | 51 | [Command] 52 | cmd_line= -w -n fastram_ebr -lang vhdl -synth lse -bus_exp 7 -bb -arch xo3c00f -type ramdq -device LCMXO3LF-6900C -addr_width 12 -data_width 16 -num_words 4096 -byte 8 -cascade -1 -mem_init0 -writemode WRITETHROUGH 53 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/fastram_ebr.naf: -------------------------------------------------------------------------------- 1 | Clock i 2 | ClockEn i 3 | Reset i 4 | ByteEn[1] i 5 | ByteEn[0] i 6 | WE i 7 | Address[11] i 8 | Address[10] i 9 | Address[9] i 10 | Address[8] i 11 | Address[7] i 12 | Address[6] i 13 | Address[5] i 14 | Address[4] i 15 | Address[3] i 16 | Address[2] i 17 | Address[1] i 18 | Address[0] i 19 | Data[15] i 20 | Data[14] i 21 | Data[13] i 22 | Data[12] i 23 | Data[11] i 24 | Data[10] i 25 | Data[9] i 26 | Data[8] i 27 | Data[7] i 28 | Data[6] i 29 | Data[5] i 30 | Data[4] i 31 | Data[3] i 32 | Data[2] i 33 | Data[1] i 34 | Data[0] i 35 | Q[15] o 36 | Q[14] o 37 | Q[13] o 38 | Q[12] o 39 | Q[11] o 40 | Q[10] o 41 | Q[9] o 42 | Q[8] o 43 | Q[7] o 44 | Q[6] o 45 | Q[5] o 46 | Q[4] o 47 | Q[3] o 48 | Q[2] o 49 | Q[1] o 50 | Q[0] o 51 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/fastram_ebr.sym: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/soc/vhdl/ip-cores/fastram_ebr.sym -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/fastram_ebr_tmpl.vhd: -------------------------------------------------------------------------------- 1 | -- VHDL module instantiation generated by SCUBA Diamond (64-bit) 3.11.2.446.3 2 | -- Module Version: 7.5 3 | -- Sat Apr 25 14:19:28 2020 4 | 5 | -- parameterized module component declaration 6 | component fastram_ebr 7 | port (Clock: in std_logic; ClockEn: in std_logic; 8 | Reset: in std_logic; ByteEn: in std_logic_vector(1 downto 0); 9 | WE: in std_logic; Address: in std_logic_vector(11 downto 0); 10 | Data: in std_logic_vector(15 downto 0); 11 | Q: out std_logic_vector(15 downto 0)); 12 | end component; 13 | 14 | -- parameterized module component instance 15 | __ : fastram_ebr 16 | port map (Clock=>__, ClockEn=>__, Reset=>__, ByteEn(1 downto 0)=>__, 17 | WE=>__, Address(11 downto 0)=>__, Data(15 downto 0)=>__, Q(15 downto 0)=>__); 18 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/hw_mult_16.ipx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/hw_mult_16.lpc: -------------------------------------------------------------------------------- 1 | [Device] 2 | Family=machxo3lf 3 | PartType=LCMXO3LF-6900C 4 | PartName=LCMXO3LF-6900C-6BG256I 5 | SpeedGrade=6 6 | Package=CABGA256 7 | OperatingCondition=IND 8 | Status=S 9 | 10 | [IP] 11 | VendorName=Lattice Semiconductor Corporation 12 | CoreType=LPM 13 | CoreStatus=Demo 14 | CoreName=Multiplier 15 | CoreRevision=4.9 16 | ModuleName=hw_mult_16 17 | SourceFormat=VHDL 18 | ParameterFileVersion=1.0 19 | Date=04/25/2020 20 | Time=12:46:37 21 | 22 | [Parameters] 23 | Verilog=0 24 | VHDL=1 25 | EDIF=1 26 | Destination=Synplicity 27 | Expression=BusA(0 to 7) 28 | Order=Big Endian [MSB:LSB] 29 | IO=0 30 | pmi_implemenntation=LUT 31 | pmi_const_coeff=No 32 | pmi_coeff_value=2 33 | pmi_ram_mult=No 34 | pmi_dataa_width=16 35 | pmi_datab_width=16 36 | pmi_datap_width=32 37 | pmi_signa=Signed 38 | pmi_signb=Signed 39 | pmi_additional_pipeline=0 40 | pmi_input_reg=Yes 41 | pmi_output_reg=Yes 42 | 43 | [Command] 44 | cmd_line= -w -n hw_mult_16 -lang vhdl -synth lse -bus_exp 7 -bb -arch xo3c00f -type dspmult -simple_portname -pfu_mult -widtha 16 -widthb 16 -widthp 32 -signed -PL_stages 0 -input_reg -output_reg -clk0 -ce0 -rst0 45 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/hw_mult_16.naf: -------------------------------------------------------------------------------- 1 | Clock i 2 | ClkEn i 3 | Aclr i 4 | DataA[15] i 5 | DataA[14] i 6 | DataA[13] i 7 | DataA[12] i 8 | DataA[11] i 9 | DataA[10] i 10 | DataA[9] i 11 | DataA[8] i 12 | DataA[7] i 13 | DataA[6] i 14 | DataA[5] i 15 | DataA[4] i 16 | DataA[3] i 17 | DataA[2] i 18 | DataA[1] i 19 | DataA[0] i 20 | DataB[15] i 21 | DataB[14] i 22 | DataB[13] i 23 | DataB[12] i 24 | DataB[11] i 25 | DataB[10] i 26 | DataB[9] i 27 | DataB[8] i 28 | DataB[7] i 29 | DataB[6] i 30 | DataB[5] i 31 | DataB[4] i 32 | DataB[3] i 33 | DataB[2] i 34 | DataB[1] i 35 | DataB[0] i 36 | Result[31] o 37 | Result[30] o 38 | Result[29] o 39 | Result[28] o 40 | Result[27] o 41 | Result[26] o 42 | Result[25] o 43 | Result[24] o 44 | Result[23] o 45 | Result[22] o 46 | Result[21] o 47 | Result[20] o 48 | Result[19] o 49 | Result[18] o 50 | Result[17] o 51 | Result[16] o 52 | Result[15] o 53 | Result[14] o 54 | Result[13] o 55 | Result[12] o 56 | Result[11] o 57 | Result[10] o 58 | Result[9] o 59 | Result[8] o 60 | Result[7] o 61 | Result[6] o 62 | Result[5] o 63 | Result[4] o 64 | Result[3] o 65 | Result[2] o 66 | Result[1] o 67 | Result[0] o 68 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/hw_mult_16.sym: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/soc/vhdl/ip-cores/hw_mult_16.sym -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/hw_mult_16_tmpl.vhd: -------------------------------------------------------------------------------- 1 | -- VHDL module instantiation generated by SCUBA Diamond (64-bit) 3.11.2.446.3 2 | -- Module Version: 4.9 3 | -- Sat Apr 25 12:46:37 2020 4 | 5 | -- parameterized module component declaration 6 | component hw_mult_16 7 | port (Clock: in std_logic; ClkEn: in std_logic; 8 | Aclr: in std_logic; DataA: in std_logic_vector(15 downto 0); 9 | DataB: in std_logic_vector(15 downto 0); 10 | Result: out std_logic_vector(31 downto 0)); 11 | end component; 12 | 13 | -- parameterized module component instance 14 | __ : hw_mult_16 15 | port map (Clock=>__, ClkEn=>__, Aclr=>__, DataA(15 downto 0)=>__, 16 | DataB(15 downto 0)=>__, Result(31 downto 0)=>__); 17 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/tb_boot_rom_tmpl.vhd: -------------------------------------------------------------------------------- 1 | -- VHDL testbench template generated by SCUBA Diamond (64-bit) 3.11.2.446.3 2 | library IEEE; 3 | use IEEE.std_logic_1164.all; 4 | use IEEE.std_logic_unsigned.all; 5 | 6 | use IEEE.math_real.all; 7 | 8 | use IEEE.numeric_std.all; 9 | 10 | entity tb is 11 | end entity tb; 12 | 13 | 14 | architecture test of tb is 15 | 16 | component boot_rom 17 | port (Address : in std_logic_vector(9 downto 0); 18 | OutClock: in std_logic; OutClockEn: in std_logic; 19 | Reset: in std_logic; Q : out std_logic_vector(15 downto 0) 20 | ); 21 | end component; 22 | 23 | signal Address : std_logic_vector(9 downto 0) := (others => '0'); 24 | signal OutClock: std_logic := '0'; 25 | signal OutClockEn: std_logic := '0'; 26 | signal Reset: std_logic := '0'; 27 | signal Q : std_logic_vector(15 downto 0); 28 | begin 29 | u1 : boot_rom 30 | port map (Address => Address, OutClock => OutClock, OutClockEn => OutClockEn, 31 | Reset => Reset, Q => Q 32 | ); 33 | 34 | process 35 | 36 | begin 37 | Address <= (others => '0') ; 38 | wait for 100 ns; 39 | wait until Reset = '0'; 40 | for i in 0 to 1027 loop 41 | wait until OutClock'event and OutClock = '1'; 42 | Address <= Address + '1' after 1 ns; 43 | end loop; 44 | wait; 45 | end process; 46 | 47 | OutClock <= not OutClock after 5.00 ns; 48 | 49 | process 50 | 51 | begin 52 | OutClockEn <= '0' ; 53 | wait for 100 ns; 54 | wait until Reset = '0'; 55 | OutClockEn <= '1' ; 56 | wait; 57 | end process; 58 | 59 | process 60 | 61 | begin 62 | Reset <= '1' ; 63 | wait for 100 ns; 64 | Reset <= '0' ; 65 | wait; 66 | end process; 67 | 68 | end architecture test; 69 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/tb_dist_boot_rom_tmpl.vhd: -------------------------------------------------------------------------------- 1 | -- VHDL testbench template generated by SCUBA Diamond (64-bit) 3.11.2.446.3 2 | library IEEE; 3 | use IEEE.std_logic_1164.all; 4 | use IEEE.std_logic_unsigned.all; 5 | 6 | use IEEE.math_real.all; 7 | 8 | use IEEE.numeric_std.all; 9 | 10 | entity tb is 11 | end entity tb; 12 | 13 | 14 | architecture test of tb is 15 | 16 | component dist_boot_rom 17 | port (Address : in std_logic_vector(9 downto 0); 18 | Q : out std_logic_vector(15 downto 0) 19 | ); 20 | end component; 21 | 22 | signal Address : std_logic_vector(9 downto 0) := (others => '0'); 23 | signal Q : std_logic_vector(15 downto 0); 24 | begin 25 | u1 : dist_boot_rom 26 | port map (Address => Address, Q => Q 27 | ); 28 | 29 | process 30 | 31 | begin 32 | Address <= (others => '0') ; 33 | wait for 100 ns; 34 | wait for 10 ns; 35 | for i in 0 to 1027 loop 36 | wait for 10 ns; 37 | Address <= Address + '1' ; 38 | end loop; 39 | wait; 40 | end process; 41 | 42 | end architecture test; 43 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/tb_fastram_ebr_tmpl.vhd: -------------------------------------------------------------------------------- 1 | -- VHDL testbench template generated by SCUBA Diamond (64-bit) 3.11.2.446.3 2 | library IEEE; 3 | use IEEE.std_logic_1164.all; 4 | use IEEE.std_logic_unsigned.all; 5 | 6 | use IEEE.math_real.all; 7 | 8 | use IEEE.numeric_std.all; 9 | 10 | entity tb is 11 | end entity tb; 12 | 13 | 14 | architecture test of tb is 15 | 16 | component fastram_ebr 17 | port (Clock: in std_logic; ClockEn: in std_logic; 18 | Reset: in std_logic; ByteEn : in std_logic_vector(1 downto 0); 19 | WE: in std_logic; Address : in std_logic_vector(11 downto 0); 20 | Data : in std_logic_vector(15 downto 0); 21 | Q : out std_logic_vector(15 downto 0) 22 | ); 23 | end component; 24 | 25 | signal Clock: std_logic := '0'; 26 | signal ClockEn: std_logic := '0'; 27 | signal Reset: std_logic := '0'; 28 | signal ByteEn : std_logic_vector(1 downto 0) := (others => '0'); 29 | signal WE: std_logic := '0'; 30 | signal Address : std_logic_vector(11 downto 0) := (others => '0'); 31 | signal Data : std_logic_vector(15 downto 0) := (others => '0'); 32 | signal Q : std_logic_vector(15 downto 0); 33 | begin 34 | u1 : fastram_ebr 35 | port map (Clock => Clock, ClockEn => ClockEn, Reset => Reset, 36 | ByteEn => ByteEn, WE => WE, Address => Address, Data => Data, 37 | Q => Q 38 | ); 39 | 40 | Clock <= not Clock after 5.00 ns; 41 | 42 | process 43 | 44 | begin 45 | ClockEn <= '0' ; 46 | wait for 100 ns; 47 | wait until Reset = '0'; 48 | ClockEn <= '1' ; 49 | wait; 50 | end process; 51 | 52 | process 53 | 54 | begin 55 | Reset <= '1' ; 56 | wait for 100 ns; 57 | Reset <= '0' ; 58 | wait; 59 | end process; 60 | 61 | process 62 | 63 | begin 64 | WE <= '0' ; 65 | wait until Reset = '0'; 66 | for i in 0 to 4099 loop 67 | wait until Clock'event and Clock = '1'; 68 | WE <= '1' after 1 ns; 69 | end loop; 70 | WE <= '0' ; 71 | wait; 72 | end process; 73 | 74 | process 75 | 76 | begin 77 | Address <= (others => '0') ; 78 | wait for 100 ns; 79 | wait until Reset = '0'; 80 | for i in 0 to 8198 loop 81 | wait until Clock'event and Clock = '1'; 82 | Address <= Address + '1' after 1 ns; 83 | end loop; 84 | wait; 85 | end process; 86 | 87 | process 88 | 89 | begin 90 | Data <= (others => '0') ; 91 | wait for 100 ns; 92 | wait until Reset = '0'; 93 | for i in 0 to 4099 loop 94 | wait until Clock'event and Clock = '1'; 95 | Data <= Data + '1' after 1 ns; 96 | end loop; 97 | wait; 98 | end process; 99 | 100 | end architecture test; 101 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/tb_hw_mult_16_tmpl.vhd: -------------------------------------------------------------------------------- 1 | -- VHDL testbench template generated by SCUBA Diamond (64-bit) 3.11.2.446.3 2 | library IEEE; 3 | use IEEE.std_logic_1164.all; 4 | use IEEE.std_logic_unsigned.all; 5 | 6 | use IEEE.math_real.all; 7 | 8 | use IEEE.numeric_std.all; 9 | 10 | entity tb is 11 | end entity tb; 12 | 13 | 14 | architecture test of tb is 15 | 16 | component hw_mult_16 17 | port (Clock: in std_logic; ClkEn: in std_logic; 18 | Aclr: in std_logic; DataA : in std_logic_vector(15 downto 0); 19 | DataB : in std_logic_vector(15 downto 0); 20 | Result : out std_logic_vector(31 downto 0) 21 | ); 22 | end component; 23 | 24 | signal Clock: std_logic := '0'; 25 | signal ClkEn: std_logic := '0'; 26 | signal Aclr: std_logic := '0'; 27 | signal DataA : std_logic_vector(15 downto 0) := (others => '0'); 28 | signal DataB : std_logic_vector(15 downto 0) := (others => '0'); 29 | signal Result : std_logic_vector(31 downto 0); 30 | begin 31 | u1 : hw_mult_16 32 | port map (Clock => Clock, ClkEn => ClkEn, Aclr => Aclr, DataA => DataA, 33 | DataB => DataB, Result => Result 34 | ); 35 | 36 | Clock <= not Clock after 5.00 ns; 37 | 38 | process 39 | 40 | begin 41 | ClkEn <= '1' ; 42 | wait; 43 | end process; 44 | 45 | process 46 | 47 | begin 48 | Aclr <= '1' ; 49 | wait for 100 ns; 50 | Aclr <= '0' ; 51 | wait; 52 | end process; 53 | 54 | process 55 | 56 | begin 57 | DataA <= (others => '0') ; 58 | for i in 0 to 200 loop 59 | wait until Clock'event and Clock = '1'; 60 | DataA <= DataA + '1' after 1 ns; 61 | end loop; 62 | wait; 63 | end process; 64 | 65 | process 66 | 67 | begin 68 | DataB <= (others => '0') ; 69 | for i in 0 to 200 loop 70 | wait until Clock'event and Clock = '1'; 71 | DataB <= DataB + '1' after 1 ns; 72 | end loop; 73 | wait; 74 | end process; 75 | 76 | end architecture test; 77 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/vga_pll.ipx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/vga_pll.jhd: -------------------------------------------------------------------------------- 1 | MODULE vga_pll DEFIN vga_pll.vhd 2 | SUBMODULE EHXPLLJ 3 | INSTANCE PLLInst_0 4 | SUBMODULE VLO 5 | INSTANCE scuba_vlo_inst 6 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/vga_pll.lpc: -------------------------------------------------------------------------------- 1 | [Device] 2 | Family=machxo3lf 3 | PartType=LCMXO3LF-6900C 4 | PartName=LCMXO3LF-6900C-6BG256I 5 | SpeedGrade=6 6 | Package=CABGA256 7 | OperatingCondition=IND 8 | Status=S 9 | 10 | [IP] 11 | VendorName=Lattice Semiconductor Corporation 12 | CoreType=LPM 13 | CoreStatus=Demo 14 | CoreName=PLL 15 | CoreRevision=5.8 16 | ModuleName=vga_pll 17 | SourceFormat=VHDL 18 | ParameterFileVersion=1.0 19 | Date=05/05/2020 20 | Time=22:16:29 21 | 22 | [Parameters] 23 | Verilog=0 24 | VHDL=1 25 | EDIF=1 26 | Destination=Synplicity 27 | Expression=None 28 | Order=None 29 | IO=0 30 | mode=Frequency 31 | CLKI=12 32 | CLKI_DIV=1 33 | BW=1.172 34 | VCO=528.000 35 | fb_mode=CLKOP 36 | CLKFB_DIV=4 37 | FRACN_ENABLE=0 38 | FRACN_DIV=0 39 | DynamicPhase=STATIC 40 | ClkEnable=0 41 | Standby=0 42 | Enable_sel=0 43 | PLLRst=0 44 | PLLMRst=0 45 | ClkOS2Rst=0 46 | ClkOS3Rst=0 47 | LockSig=1 48 | LockStk=0 49 | WBProt=0 50 | OPBypass=0 51 | OPUseDiv=0 52 | CLKOP_DIV=11 53 | FREQ_PIN_CLKOP=48 54 | OP_Tol=0.0 55 | CLKOP_AFREQ=48.000000 56 | CLKOP_PHASEADJ=0 57 | CLKOP_TRIM_POL=Rising 58 | CLKOP_TRIM_DELAY=0 59 | EnCLKOS=0 60 | OSBypass=0 61 | OSUseDiv=0 62 | CLKOS_DIV=1 63 | FREQ_PIN_CLKOS=100 64 | OS_Tol=0.0 65 | CLKOS_AFREQ= 66 | CLKOS_PHASEADJ=0 67 | CLKOS_TRIM_POL=Rising 68 | CLKOS_TRIM_DELAY=0 69 | EnCLKOS2=0 70 | OS2Bypass=0 71 | OS2UseDiv=0 72 | CLKOS2_DIV=1 73 | FREQ_PIN_CLKOS2=100 74 | OS2_Tol=0.0 75 | CLKOS2_AFREQ= 76 | CLKOS2_PHASEADJ=0 77 | EnCLKOS3=0 78 | OS3Bypass=0 79 | OS3UseDiv=0 80 | CLKOS3_DIV=1 81 | FREQ_PIN_CLKOS3=100 82 | OS3_Tol=0.0 83 | CLKOS3_AFREQ= 84 | CLKOS3_PHASEADJ=0 85 | 86 | [Command] 87 | cmd_line= -w -n vga_pll -lang vhdl -synth lse -arch xo3c00f -type pll -fin 12 -fclkop 48 -fclkop_tol 0.0 -trimp 0 -phasep 0 -trimp_r -phase_cntl STATIC -fb_mode 1 -lock 88 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/vga_pll.naf: -------------------------------------------------------------------------------- 1 | CLKI i 2 | CLKOP o 3 | LOCK o 4 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/vga_pll.sym: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/soc/vhdl/ip-cores/vga_pll.sym -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/vga_pll_tmpl.vhd: -------------------------------------------------------------------------------- 1 | -- VHDL module instantiation generated by SCUBA Diamond (64-bit) 3.11.2.446.3 2 | -- Module Version: 5.7 3 | -- Tue May 5 22:16:29 2020 4 | 5 | -- parameterized module component declaration 6 | component vga_pll 7 | port (CLKI: in std_logic; CLKOP: out std_logic; 8 | LOCK: out std_logic); 9 | end component; 10 | 11 | -- parameterized module component instance 12 | __ : vga_pll 13 | port map (CLKI=>__, CLKOP=>__, LOCK=>__); 14 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/videoram.ipx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/videoram.jhd: -------------------------------------------------------------------------------- 1 | MODULE videoram DEFIN videoram.vhd 2 | SUBMODULE MUX41 3 | INSTANCE mux_0 4 | SUBMODULE MUX41 5 | INSTANCE mux_1 6 | SUBMODULE MUX41 7 | INSTANCE mux_2 8 | SUBMODULE MUX41 9 | INSTANCE mux_3 10 | SUBMODULE MUX41 11 | INSTANCE mux_4 12 | SUBMODULE MUX41 13 | INSTANCE mux_5 14 | SUBMODULE MUX41 15 | INSTANCE mux_6 16 | SUBMODULE MUX41 17 | INSTANCE mux_7 18 | SUBMODULE FD1P3DX 19 | INSTANCE FF_0 20 | SUBMODULE VLO 21 | INSTANCE scuba_vlo_inst 22 | SUBMODULE FD1P3DX 23 | INSTANCE FF_1 24 | SUBMODULE FD1P3DX 25 | INSTANCE FF_2 26 | SUBMODULE FD1P3DX 27 | INSTANCE FF_3 28 | SUBMODULE DP8KC 29 | INSTANCE videoram_3_3_0 30 | SUBMODULE DP8KC 31 | INSTANCE videoram_3_2_1 32 | SUBMODULE DP8KC 33 | INSTANCE videoram_3_1_2 34 | SUBMODULE DP8KC 35 | INSTANCE videoram_3_0_3 36 | SUBMODULE DP8KC 37 | INSTANCE videoram_2_3_4 38 | SUBMODULE DP8KC 39 | INSTANCE videoram_2_2_5 40 | SUBMODULE DP8KC 41 | INSTANCE videoram_2_1_6 42 | SUBMODULE DP8KC 43 | INSTANCE videoram_2_0_7 44 | SUBMODULE DP8KC 45 | INSTANCE videoram_1_3_8 46 | SUBMODULE DP8KC 47 | INSTANCE videoram_1_2_9 48 | SUBMODULE DP8KC 49 | INSTANCE videoram_1_1_10 50 | SUBMODULE DP8KC 51 | INSTANCE videoram_1_0_11 52 | SUBMODULE DP8KC 53 | INSTANCE videoram_0_3_12 54 | SUBMODULE DP8KC 55 | INSTANCE videoram_0_2_13 56 | SUBMODULE DP8KC 57 | INSTANCE videoram_0_1_14 58 | SUBMODULE DP8KC 59 | INSTANCE videoram_0_0_15 60 | SUBMODULE VHI 61 | INSTANCE scuba_vhi_inst 62 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/videoram.lpc: -------------------------------------------------------------------------------- 1 | [Device] 2 | Family=machxo3lf 3 | PartType=LCMXO3LF-6900C 4 | PartName=LCMXO3LF-6900C-6BG256I 5 | SpeedGrade=6 6 | Package=CABGA256 7 | OperatingCondition=IND 8 | Status=S 9 | 10 | [IP] 11 | VendorName=Lattice Semiconductor Corporation 12 | CoreType=LPM 13 | CoreStatus=Demo 14 | CoreName=RAM_DP_TRUE 15 | CoreRevision=7.5 16 | ModuleName=videoram 17 | SourceFormat=VHDL 18 | ParameterFileVersion=1.0 19 | Date=05/04/2020 20 | Time=22:13:56 21 | 22 | [Parameters] 23 | Verilog=0 24 | VHDL=1 25 | EDIF=1 26 | Destination=Synplicity 27 | Expression=BusA(0 to 7) 28 | Order=Big Endian [MSB:LSB] 29 | IO=0 30 | RAddress=32768 31 | RData=4 32 | WAddress=32768 33 | WData=4 34 | ROutputEn=0 35 | RClockEn=0 36 | WOutputEn=0 37 | WClockEn=0 38 | enByte=0 39 | ByteSize=9 40 | Optimization=Speed 41 | Reset=Sync 42 | Reset1=Sync 43 | Init=0 44 | MemFile= 45 | MemFormat=bin 46 | EnECC=0 47 | Pipeline=0 48 | WriteA=WriteThrough 49 | WriteB=WriteThrough 50 | init_data=0 51 | no_init=0 52 | 53 | [FilesGenerated] 54 | =mem 55 | 56 | [Command] 57 | cmd_line= -w -n videoram -lang vhdl -synth lse -bus_exp 7 -bb -arch xo3c00f -type ramdp -device LCMXO3LF-6900C -aaddr_width 15 -widtha 4 -baddr_width 15 -widthb 4 -anum_words 32768 -bnum_words 32768 -cascade -1 -mem_init0 -writemodeA WRITETHROUGH -writemodeB WRITETHROUGH 58 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/videoram.naf: -------------------------------------------------------------------------------- 1 | DataInA[3] i 2 | DataInA[2] i 3 | DataInA[1] i 4 | DataInA[0] i 5 | DataInB[3] i 6 | DataInB[2] i 7 | DataInB[1] i 8 | DataInB[0] i 9 | AddressA[14] i 10 | AddressA[13] i 11 | AddressA[12] i 12 | AddressA[11] i 13 | AddressA[10] i 14 | AddressA[9] i 15 | AddressA[8] i 16 | AddressA[7] i 17 | AddressA[6] i 18 | AddressA[5] i 19 | AddressA[4] i 20 | AddressA[3] i 21 | AddressA[2] i 22 | AddressA[1] i 23 | AddressA[0] i 24 | AddressB[14] i 25 | AddressB[13] i 26 | AddressB[12] i 27 | AddressB[11] i 28 | AddressB[10] i 29 | AddressB[9] i 30 | AddressB[8] i 31 | AddressB[7] i 32 | AddressB[6] i 33 | AddressB[5] i 34 | AddressB[4] i 35 | AddressB[3] i 36 | AddressB[2] i 37 | AddressB[1] i 38 | AddressB[0] i 39 | ClockA i 40 | ClockB i 41 | ClockEnA i 42 | ClockEnB i 43 | WrA i 44 | WrB i 45 | ResetA i 46 | ResetB i 47 | QA[3] o 48 | QA[2] o 49 | QA[1] o 50 | QA[0] o 51 | QB[3] o 52 | QB[2] o 53 | QB[1] o 54 | QB[0] o 55 | -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/videoram.sym: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikskuh/spu-mark-ii/ec8e7e05f5c2cdfe4b4e98b369ce03df08885baa/soc/vhdl/ip-cores/videoram.sym -------------------------------------------------------------------------------- /soc/vhdl/ip-cores/videoram_tmpl.vhd: -------------------------------------------------------------------------------- 1 | -- VHDL module instantiation generated by SCUBA Diamond (64-bit) 3.11.2.446.3 2 | -- Module Version: 7.5 3 | -- Mon May 4 22:13:56 2020 4 | 5 | -- parameterized module component declaration 6 | component videoram 7 | port (DataInA: in std_logic_vector(3 downto 0); 8 | DataInB: in std_logic_vector(3 downto 0); 9 | AddressA: in std_logic_vector(14 downto 0); 10 | AddressB: in std_logic_vector(14 downto 0); 11 | ClockA: in std_logic; ClockB: in std_logic; 12 | ClockEnA: in std_logic; ClockEnB: in std_logic; 13 | WrA: in std_logic; WrB: in std_logic; ResetA: in std_logic; 14 | ResetB: in std_logic; QA: out std_logic_vector(3 downto 0); 15 | QB: out std_logic_vector(3 downto 0)); 16 | end component; 17 | 18 | -- parameterized module component instance 19 | __ : videoram 20 | port map (DataInA(3 downto 0)=>__, DataInB(3 downto 0)=>__, AddressA(14 downto 0)=>__, 21 | AddressB(14 downto 0)=>__, ClockA=>__, ClockB=>__, ClockEnA=>__, 22 | ClockEnB=>__, WrA=>__, WrB=>__, ResetA=>__, ResetB=>__, QA(3 downto 0)=>__, 23 | QB(3 downto 0)=>__); 24 | -------------------------------------------------------------------------------- /soc/vhdl/programmer-conf.xcf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | JTAG 7 | 8 | 9 | 1 10 | Lattice 11 | MachXO3LF 12 | LCMXO3LF-6900C 13 | 0x612bd043 14 | All 15 | LCMXO3LF-6900C 16 | 17 | 8 18 | 11111111 19 | 1 20 | 0 21 | 22 | /home/felix/projects/lowlevel/spu-mark-2/soc/hw/firstdesign/spumark2_firstdesign.bit 23 | 05/12/20 22:21:58 24 | SRAM Fast Program 25 | 36 | 37 | 38 | 39 | SEQUENTIAL 40 | ENTIRED CHAIN 41 | No Override 42 | TLR 43 | TLR 44 | 45 | 1 46 | 47 | 48 | USB2 49 | FTUSB-0 50 | LATTICE XO3LF STARTER KIT A Location 0000 51 | 52 | TRST ABSENT; 53 | ISPEN ABSENT; 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /soc/vhdl/simu/.gitignore: -------------------------------------------------------------------------------- 1 | obj/ 2 | -------------------------------------------------------------------------------- /soc/vhdl/simu/Makefile: -------------------------------------------------------------------------------- 1 | 2 | SOURCES=ip-cores/fastram_ebr.vhd $(addprefix ../src/,cpu_types.vhd mmu.vhd fastram.vhd vga.vhd debug-port-in.vhd debug-port-out.vhd sram-controller.vhd uart_sender.vhd uart_receiver.vhd register-ram.vhd fifo.vhd serial-port.vhd cpu.vhd builtin-rom.vhd rom.vhd soc.vhd root.vhd testbench_fifo.vhd testbench_spu.vhd testbench_vga.vhd) 3 | 4 | OBJS=$(addprefix obj/,$(notdir $(SOURCES:.vhd=.o))) 5 | 6 | TIME?=2500us 7 | 8 | all: testbench_spu.ghw testbench_fifo.ghw testbench_vga.ghw 9 | 10 | obj/testbench_spu: $(OBJS) 11 | cd obj; ghdl -e --std=08 testbench_spu 12 | 13 | obj/testbench_fifo: $(OBJS) 14 | cd obj; ghdl -e --std=08 testbench_fifo 15 | 16 | obj/testbench_vga: $(OBJS) 17 | cd obj; ghdl -e --std=08 testbench_vga 18 | 19 | obj/%.o: ../src/%.vhd 20 | cd obj; ghdl -a --std=08 ../$^ 21 | 22 | obj/%.o: ip-cores/%.vhd 23 | cd obj; ghdl -a --std=08 ../$^ 24 | 25 | %.vcd: % 26 | ghdl -r $< --vcd=$@ --stop-time=50us 27 | 28 | %.ghw: obj/% 29 | cd obj; ghdl -r $(notdir $<) --wave=../$@ --stop-time=$(TIME) 30 | 31 | clean: $(OBJS) 32 | rm $^ 33 | 34 | .PHONY: clean 35 | .SUFFIXES: -------------------------------------------------------------------------------- /soc/vhdl/simu/ip-cores/fastram_ebr.vhd: -------------------------------------------------------------------------------- 1 | 2 | library IEEE; 3 | USE IEEE.std_logic_1164.ALL; 4 | USE IEEE.numeric_std.ALL; 5 | 6 | entity fastram_ebr is 7 | port ( 8 | Clock: in std_logic; 9 | ClockEn: in std_logic; 10 | Reset: in std_logic; 11 | ByteEn: in std_logic_vector(1 downto 0); 12 | WE: in std_logic; 13 | Address: in std_logic_vector(11 downto 0); 14 | Data: in std_logic_vector(15 downto 0); 15 | Q: out std_logic_vector(15 downto 0)); 16 | end fastram_ebr; 17 | 18 | ARCHITECTURE rtl OF fastram_ebr IS 19 | 20 | TYPE RAM_Type IS ARRAY(0 to 4096) OF std_logic_vector(15 downto 0); 21 | 22 | SIGNAL backing_buffer : RAM_Type; 23 | begin 24 | 25 | p0 : PROCESS(Clock, Reset) 26 | BEGIN 27 | if rising_edge(Clock) then 28 | if ClockEn = '1' then 29 | if WE = '1' then 30 | case ByteEn is 31 | -- Only write to the portion of the register 32 | -- that is selected by BLS 33 | when "11" => backing_buffer(to_integer(unsigned(Address))) <= Data; 34 | when "01" => backing_buffer(to_integer(unsigned(Address)))(7 downto 0) <= Data(7 downto 0); 35 | when "10" => backing_buffer(to_integer(unsigned(Address)))(15 downto 8) <= Data(15 downto 8); 36 | when others => -- ignore 37 | end case; 38 | end if; 39 | -- We don't need to respect `bus_bls` here as 40 | -- we don't modify any data. 41 | Q <= backing_buffer(to_integer(unsigned(Address))); 42 | end if; 43 | end if; 44 | END PROCESS; 45 | 46 | end architecture; 47 | -------------------------------------------------------------------------------- /soc/vhdl/spumark2.ldf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /soc/vhdl/src/cpu_types.vhd: -------------------------------------------------------------------------------- 1 | 2 | 3 | package SPU_Mark_II_Types is 4 | TYPE RegisterName IS ( 5 | IR, 6 | FR, 7 | IP, 8 | SP, 9 | BP 10 | ); 11 | end package; -------------------------------------------------------------------------------- /soc/vhdl/src/debug-port-in.vhd: -------------------------------------------------------------------------------- 1 | -- Debug Port receiver 2 | 3 | LIBRARY IEEE; 4 | USE IEEE.std_logic_1164.ALL; 5 | USE IEEE.numeric_std.ALL; 6 | 7 | ENTITY DebugPortReceiver IS 8 | PORT ( 9 | clk : in std_logic; 10 | rst : in std_logic; 11 | dbg_clk : in std_logic; 12 | dbg_data : in std_logic; 13 | rcv_data : out std_logic_vector(7 downto 0); 14 | rcv : out std_logic 15 | ); 16 | END ENTITY DebugPortReceiver; 17 | 18 | ARCHITECTURE rtl OF DebugPortReceiver IS 19 | SIGNAL pos : unsigned(3 downto 0); 20 | SIGNAL counter : unsigned(13 downto 0); 21 | SIGNAL input_buffer : std_logic_vector(6 downto 0); 22 | SIGNAL state : bit; 23 | begin 24 | 25 | p0: process(rst, clk) 26 | begin 27 | if rst = '0' then 28 | state <= '0'; 29 | pos <= to_unsigned(0, pos'length); 30 | counter <= to_unsigned(0, counter'length); 31 | elsif rising_edge(clk) then 32 | rcv <= '0'; 33 | if state = '0' then 34 | if dbg_clk = '1' then 35 | if pos = 7 then 36 | counter <= to_unsigned(0, counter'length); 37 | pos <= to_unsigned(0, pos'length); 38 | rcv_data <= input_buffer(0) 39 | & input_buffer(1) 40 | & input_buffer(2) 41 | & input_buffer(3) 42 | & input_buffer(4) 43 | & input_buffer(5) 44 | & input_buffer(6) 45 | & dbg_data; 46 | rcv <= '1'; 47 | else 48 | input_buffer(to_integer(pos)) <= dbg_data; 49 | pos <= pos + 1; 50 | end if; 51 | state <= '1'; 52 | else 53 | if counter = 11_999 then 54 | counter <= to_unsigned(0, counter'length); 55 | pos <= to_unsigned(0, pos'length); 56 | else 57 | counter <= counter + 1; 58 | end if; 59 | end if; 60 | else 61 | if dbg_clk = '0' then 62 | state <= '0'; 63 | elsif counter /= 11_999 then 64 | counter <= counter + 1; 65 | end if; 66 | end if; 67 | end if; 68 | end process; 69 | 70 | end architecture; -------------------------------------------------------------------------------- /soc/vhdl/src/debug-port-out.vhd: -------------------------------------------------------------------------------- 1 | -- Debug Port receiver 2 | 3 | LIBRARY IEEE; 4 | USE IEEE.std_logic_1164.ALL; 5 | USE IEEE.numeric_std.ALL; 6 | USE ieee.math_real.log2; 7 | USE ieee.math_real.ceil; 8 | 9 | ENTITY DebugPortSender IS 10 | GENERIC ( 11 | freq_clk : natural; 12 | baud : natural := 9600 13 | ); 14 | PORT ( 15 | clk : in std_logic; 16 | rst : in std_logic; 17 | dbg_clk : out std_logic; 18 | dbg_data : out std_logic; 19 | txd_data : in std_logic_vector(7 downto 0); 20 | txd : in std_logic; 21 | complete : out std_logic 22 | ); 23 | END ENTITY DebugPortSender; 24 | 25 | ARCHITECTURE rtl OF DebugPortSender IS 26 | TYPE TState IS (Idle, TransmitHigh, TransmitLow ); 27 | 28 | CONSTANT limit : natural := (freq_clk / (2 * baud)) - 1; 29 | 30 | constant limit_width : integer := INTEGER(CEIL(LOG2(REAL(limit+1)))); 31 | 32 | SIGNAL state : TState ; 33 | SIGNAL pos : unsigned(3 downto 0); 34 | SIGNAL output_buffer : std_logic_vector(6 downto 0); 35 | SIGNAL divider : unsigned(limit_width downto 0); 36 | begin 37 | 38 | p0: process(rst, clk) 39 | begin 40 | if rst = '0' then 41 | state <= Idle; 42 | pos <= to_unsigned(0, pos'length); 43 | complete <= '0'; 44 | elsif rising_edge(clk) then 45 | case state is 46 | when Idle => 47 | complete <= '0'; 48 | if txd = '1' then 49 | state <= TransmitHigh; 50 | pos <= to_unsigned(7, pos'length); 51 | divider <= to_unsigned(0, divider'length); 52 | output_buffer <= txd_data(6 downto 0); 53 | dbg_clk <= '1'; 54 | dbg_data <= txd_data(7); 55 | end if; 56 | 57 | when TransmitHigh => 58 | if divider = limit then 59 | divider <= to_unsigned(0, divider'length); 60 | state <= TransmitLow; 61 | dbg_clk <= '0'; 62 | dbg_data <= '0'; 63 | else 64 | divider <= divider + 1; 65 | end if; 66 | 67 | when TransmitLow => 68 | if divider = limit then 69 | if pos = 0 then 70 | state <= Idle; 71 | complete <= '1'; 72 | dbg_clk <= '0'; 73 | dbg_data <= '0'; 74 | else 75 | state <= TransmitHigh; 76 | pos <= pos - 1; 77 | dbg_clk <= '1'; 78 | dbg_data <= output_buffer(to_integer(pos - 1)); 79 | end if; 80 | divider <= to_unsigned(0, divider'length); 81 | else 82 | divider <= divider + 1; 83 | end if; 84 | 85 | end case; 86 | 87 | end if; 88 | end process; 89 | 90 | end architecture; -------------------------------------------------------------------------------- /soc/vhdl/src/fastram.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY IEEE; 2 | USE IEEE.std_logic_1164.ALL; 3 | USE IEEE.numeric_std.ALL; 4 | 5 | ENTITY FastRAM IS 6 | PORT ( 7 | rst : in std_logic; -- asynchronous reset 8 | clk : in std_logic; -- system clock 9 | bus_data_out : out std_logic_vector(15 downto 0); 10 | bus_data_in : in std_logic_vector(15 downto 0); 11 | bus_address : in std_logic_vector(15 downto 1); 12 | bus_write : in std_logic; -- when '1' then bus write is requested, otherwise a read. 13 | bus_bls : in std_logic_vector(1 downto 0); -- selects the byte lanes for the memory operation 14 | bus_request : in std_logic; -- when set to '1', the bus operation is requested 15 | bus_acknowledge : out std_logic -- when set to '1', the bus operation is acknowledged 16 | ); 17 | END ENTITY FastRAM; 18 | 19 | ARCHITECTURE rtl OF FastRAM IS 20 | component fastram_ebr is 21 | port ( 22 | Clock: in std_logic; 23 | ClockEn: in std_logic; 24 | Reset: in std_logic; 25 | ByteEn: in std_logic_vector(1 downto 0); 26 | WE: in std_logic; 27 | Address: in std_logic_vector(11 downto 0); 28 | Data: in std_logic_vector(15 downto 0); 29 | Q: out std_logic_vector(15 downto 0) 30 | ); 31 | end component fastram_ebr; 32 | 33 | SIGNAL acknext : boolean; 34 | 35 | begin 36 | 37 | fastram_ebr0: FastRam_EBR 38 | PORT MAP( 39 | Clock => clk, 40 | ClockEn => bus_request, 41 | Reset => '0', -- reset for RAM doesn't do anything useful anyways 42 | WE => bus_write, 43 | ByteEn => bus_bls, 44 | Address => bus_address(12 downto 1), 45 | Data => bus_data_in, 46 | Q => bus_data_out 47 | ); 48 | 49 | p0 : PROCESS(clk, rst) 50 | BEGIN 51 | if rst = '0' then 52 | bus_acknowledge <= '0'; 53 | acknext <= False; 54 | else 55 | if rising_edge(clk) then 56 | acknext <= bus_request = '1'; 57 | bus_acknowledge <= '1' when acknext else '0'; 58 | end if; 59 | end if; 60 | END PROCESS; 61 | 62 | end architecture; -------------------------------------------------------------------------------- /soc/vhdl/src/fifo.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY IEEE; 2 | USE IEEE.std_logic_1164.ALL; 3 | USE IEEE.numeric_std.ALL; 4 | 5 | ENTITY FIFO IS 6 | GENERIC ( 7 | width : natural := 16; -- width in bits 8 | depth : natural := 8 -- number of elements in the fifo 9 | ); 10 | 11 | PORT ( 12 | rst : in std_logic; -- asynchronous reset 13 | clk : in std_logic; -- system clock 14 | input : in std_logic_vector(width - 1 downto 0); 15 | output : out std_logic_vector(width - 1 downto 0); 16 | insert : in std_logic; 17 | remove : in std_logic; 18 | empty : out std_logic; 19 | not_empty : out std_logic; 20 | full : out std_logic 21 | ); 22 | 23 | END ENTITY FIFO; 24 | 25 | ARCHITECTURE rtl OF FIFO IS 26 | 27 | SUBTYPE WORD_Type IS std_logic_vector(width - 1 downto 0); 28 | 29 | SUBTYPE INDEX_Type IS integer range 0 to depth - 1; 30 | 31 | TYPE Storage_Type IS ARRAY (0 to depth - 1) OF WORD_Type; 32 | 33 | signal storage : Storage_Type; 34 | signal head : INDEX_Type; 35 | signal tail : INDEX_Type; 36 | 37 | signal inserting : std_logic; 38 | signal removing : std_logic; 39 | 40 | -- Increment and wrap 41 | function incr(index : in index_type) return index_type is 42 | begin 43 | if index = index_type'high then 44 | return index_type'low; 45 | else 46 | return index + 1; 47 | end if; 48 | end function; 49 | 50 | begin 51 | 52 | p0 : process(clk, rst) is 53 | begin 54 | if rst = '0' then 55 | 56 | empty <= '1'; 57 | full <= '0'; 58 | head <= 0; 59 | tail <= 0; 60 | inserting <= '0'; 61 | removing <= '0'; 62 | else 63 | if rising_edge(clk) then 64 | output <= storage(tail); 65 | empty <= '1' when head = tail else '0'; 66 | full <= '1' when incr(head) = tail else '0'; 67 | not_empty <= '1' when head /= tail else '0'; 68 | 69 | if inserting = '1' then 70 | if insert = '0' then 71 | inserting <= '0'; 72 | end if; 73 | else 74 | if insert = '1' then 75 | if incr(head) /= tail then 76 | storage(head) <= input; 77 | head <= incr(head); 78 | end if; 79 | inserting <= '1'; 80 | end if; 81 | end if; 82 | 83 | if removing = '1' then 84 | if remove = '0' then 85 | removing <= '0'; 86 | end if; 87 | else 88 | if remove = '1' then 89 | if tail /= head then 90 | tail <= incr(tail); 91 | end if; 92 | removing <= '1'; 93 | end if; 94 | end if; 95 | end if; 96 | end if; 97 | end process; 98 | 99 | end architecture; -------------------------------------------------------------------------------- /soc/vhdl/src/register-ram.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY IEEE; 2 | USE IEEE.std_logic_1164.ALL; 3 | USE IEEE.numeric_std.ALL; 4 | 5 | ENTITY Register_RAM IS 6 | GENERIC ( 7 | address_width : natural := 8 -- number of address bits => 2**address_width => number of bytes 8 | ); 9 | 10 | PORT ( 11 | rst : in std_logic; -- asynchronous reset 12 | clk : in std_logic; -- system clock 13 | bus_data_out : out std_logic_vector(15 downto 0); 14 | bus_data_in : in std_logic_vector(15 downto 0); 15 | bus_address : in std_logic_vector(address_width-1 downto 1); 16 | bus_write : in std_logic; -- when '1' then bus write is requested, otherwise a read. 17 | bus_bls : in std_logic_vector(1 downto 0); -- selects the byte lanes for the memory operation 18 | bus_request : in std_logic; -- when set to '1', the bus operation is requested 19 | bus_acknowledge : out std_logic -- when set to '1', the bus operation is acknowledged 20 | ); 21 | 22 | END ENTITY Register_RAM; 23 | 24 | ARCHITECTURE rtl OF Register_RAM IS 25 | 26 | TYPE RAM_Type IS ARRAY(0 to 2**address_width) OF std_logic_vector(15 downto 0); 27 | 28 | SIGNAL data : RAM_Type; 29 | begin 30 | 31 | p0 : PROCESS(clk, rst) 32 | BEGIN 33 | if rst = '0' then 34 | bus_acknowledge <= '0'; 35 | else 36 | if rising_edge(clk) then 37 | if bus_request = '1' then 38 | bus_acknowledge <= '1'; 39 | if bus_write = '1' then 40 | case bus_bls is 41 | -- Only write to the portion of the register 42 | -- that is selected by BLS 43 | when "11" => data(to_integer(unsigned(bus_address))) <= bus_data_in; 44 | when "01" => data(to_integer(unsigned(bus_address)))(7 downto 0) <= bus_data_in(7 downto 0); 45 | when "10" => data(to_integer(unsigned(bus_address)))(15 downto 8) <= bus_data_in(15 downto 8); 46 | when others => -- ignore 47 | end case; 48 | end if; 49 | -- We don't need to respect `bus_bls` here as 50 | -- we don't modify any data. 51 | bus_data_out <= data(to_integer(unsigned(bus_address))); 52 | else 53 | bus_acknowledge <= '0'; 54 | end if; 55 | end if; 56 | end if; 57 | END PROCESS; 58 | 59 | end architecture; -------------------------------------------------------------------------------- /soc/vhdl/src/rom.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY IEEE; 2 | USE IEEE.std_logic_1164.ALL; 3 | USE IEEE.numeric_std.ALL; 4 | 5 | ENTITY ROM IS 6 | PORT ( 7 | rst : in std_logic; -- asynchronous reset 8 | clk : in std_logic; -- system clock 9 | bus_data_out : out std_logic_vector(15 downto 0); 10 | bus_data_in : in std_logic_vector(15 downto 0); 11 | bus_address : in std_logic_vector(15 downto 1); 12 | bus_write : in std_logic; -- when '1' then bus write is requested, otherwise a read. 13 | bus_bls : in std_logic_vector(1 downto 0); -- selects the byte lanes for the memory operation 14 | bus_request : in std_logic; -- when set to '1', the bus operation is requested 15 | bus_acknowledge : out std_logic -- when set to '1', the bus operation is acknowledged 16 | ); 17 | END ENTITY ROM; 18 | 19 | ARCHITECTURE rtl OF ROM IS 20 | component boot_rom 21 | port ( 22 | Address: in std_logic_vector(9 downto 0); 23 | OutClock: in std_logic; 24 | OutClockEn: in std_logic; 25 | Reset: in std_logic; 26 | Q: out std_logic_vector(15 downto 0) 27 | ); 28 | end component; 29 | 30 | component dist_boot_rom 31 | port ( 32 | Address: in std_logic_vector(9 downto 0); 33 | Q: out std_logic_vector(15 downto 0) 34 | ); 35 | end component; 36 | 37 | SIGNAL acknext : boolean; 38 | begin 39 | 40 | -- ebr_rom : boot_rom 41 | -- port map ( 42 | -- Address(9 downto 0) => bus_address(10 downto 1), 43 | -- OutClock => clk, 44 | -- OutClockEn => '1', 45 | -- Reset => not rst, 46 | -- Q(15 downto 0) => bus_data_out 47 | -- ); 48 | 49 | dist_rom : dist_boot_rom 50 | port map ( 51 | Address(9 downto 0) => bus_address(10 downto 1), 52 | Q(15 downto 0) => bus_data_out 53 | ); 54 | 55 | p0 : PROCESS(clk, rst) 56 | BEGIN 57 | if rst = '0' then 58 | bus_acknowledge <= '0'; 59 | acknext <= False; 60 | else 61 | if rising_edge(clk) then 62 | bus_acknowledge <= bus_request; 63 | -- acknext <= bus_request = '1'; 64 | -- bus_acknowledge <= '1' when acknext else '0'; 65 | end if; 66 | end if; 67 | END PROCESS; 68 | 69 | end architecture; -------------------------------------------------------------------------------- /soc/vhdl/src/root.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY IEEE; 2 | USE IEEE.std_logic_1164.ALL; 3 | USE IEEE.numeric_std.ALL; 4 | 5 | ENTITY root IS 6 | PORT ( 7 | leds : out std_logic_vector(7 downto 0); 8 | switches : in std_logic_vector(3 downto 0); 9 | extclk : in std_logic; 10 | extrst : in std_logic; 11 | uart0_rxd : in std_logic; 12 | uart0_txd : out std_logic; 13 | sram_addr : out std_logic_vector(18 downto 0); 14 | sram_data : inout std_logic_vector(7 downto 0); 15 | sram_we : out std_logic; 16 | sram_oe : out std_logic; 17 | sram_ce : out std_logic; 18 | dbg_miso_data : in std_logic; 19 | dbg_mosi_data : out std_logic; 20 | vga_r : out std_logic_vector(1 downto 0); 21 | vga_g : out std_logic_vector(1 downto 0); 22 | vga_b : out std_logic_vector(1 downto 0); 23 | vga_hs : out std_logic; 24 | vga_vs : out std_logic; 25 | logic_dbg : out std_logic_vector(7 downto 0) 26 | ); 27 | 28 | END ENTITY root; 29 | 30 | ARCHITECTURE rtl OF root IS 31 | COMPONENT SOC IS 32 | PORT ( 33 | leds : out std_logic_vector(7 downto 0); 34 | switches : in std_logic_vector(3 downto 0); 35 | extclk : in std_logic; 36 | extrst : in std_logic; 37 | uart0_rxd : in std_logic; 38 | uart0_txd : out std_logic; 39 | sram_addr : out std_logic_vector(18 downto 0); 40 | sram_data : inout std_logic_vector(7 downto 0); 41 | sram_we : out std_logic; 42 | sram_oe : out std_logic; 43 | sram_ce : out std_logic; 44 | vga_r : out std_logic_vector(1 downto 0); 45 | vga_g : out std_logic_vector(1 downto 0); 46 | vga_b : out std_logic_vector(1 downto 0); 47 | vga_hs : out std_logic; 48 | vga_vs : out std_logic; 49 | dbg_miso_data : in std_logic; 50 | dbg_mosi_data : out std_logic; 51 | logic_dbg : out std_logic_vector(7 downto 0) 52 | ); 53 | END COMPONENT SOC; 54 | 55 | component vga_pll 56 | port (CLKI: in std_logic; CLKOP: out std_logic; 57 | LOCK: out std_logic); 58 | end component; 59 | 60 | SIGNAL clk : std_logic; 61 | SIGNAL rst : std_logic; 62 | 63 | SIGNAL sysclk_raw : std_logic; 64 | SIGNAL sysclk_locked : std_logic; 65 | 66 | BEGIN 67 | 68 | rst <= extrst; 69 | clk <= sysclk_raw and sysclk_locked; 70 | 71 | sys_clk : vga_pll port map ( 72 | CLKI => extclk, 73 | CLKOP => sysclk_raw, 74 | LOCK => sysclk_locked 75 | ); 76 | 77 | -- leds(3 downto 0) <= not switches(3 downto 0); 78 | 79 | glue: SOC 80 | PORT MAP ( 81 | leds => leds, 82 | switches => switches, 83 | extclk => clk, 84 | extrst => rst, 85 | uart0_rxd => uart0_rxd, 86 | uart0_txd => uart0_txd, 87 | sram_addr => sram_addr, 88 | sram_data => sram_data, 89 | sram_we => sram_we, 90 | sram_oe => sram_oe, 91 | sram_ce => sram_ce, 92 | dbg_miso_data => dbg_miso_data, 93 | dbg_mosi_data => dbg_mosi_data, 94 | logic_dbg => logic_dbg, 95 | vga_r => vga_r, 96 | vga_g => vga_g, 97 | vga_b => vga_b, 98 | vga_hs => vga_hs, 99 | vga_vs => vga_vs 100 | ); 101 | 102 | END ARCHITECTURE rtl ; -------------------------------------------------------------------------------- /soc/vhdl/src/sram-controller.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY IEEE; 2 | USE IEEE.std_logic_1164.ALL; 3 | USE IEEE.numeric_std.ALL; 4 | 5 | ENTITY SRAM_Controller IS 6 | PORT ( 7 | rst : in std_logic; -- asynchronous reset 8 | clk : in std_logic; -- system clock 9 | -- sram interface 10 | sram_addr : out std_logic_vector(18 downto 0); 11 | sram_data : inout std_logic_vector(7 downto 0); 12 | sram_we : out std_logic; 13 | sram_oe : out std_logic; 14 | sram_ce : out std_logic; 15 | 16 | -- system bus 17 | bus_data_out : out std_logic_vector(15 downto 0); 18 | bus_data_in : in std_logic_vector(15 downto 0); 19 | bus_address : in std_logic_vector(18 downto 1); 20 | bus_write : in std_logic; -- when '1' then bus write is requested, otherwise a read. 21 | bus_bls : in std_logic_vector(1 downto 0); -- selects the byte lanes for the memory operation 22 | bus_request : in std_logic; -- when set to '1', the bus operation is requested 23 | bus_acknowledge : out std_logic -- when set to '1', the bus operation is acknowledged 24 | ); 25 | END ENTITY SRAM_Controller; 26 | 27 | ARCHITECTURE rtl OF SRAM_Controller IS 28 | 29 | TYPE SRAM_Mode_Type IS (OFF,READ,WRITE); 30 | 31 | TYPE SRAM_State_Type IS (Init, AccessLow, AccessHighDelay, AccessHigh, Done); 32 | 33 | SIGNAL sram_data_in : std_logic_vector(7 downto 0); 34 | SIGNAL sram_data_out : std_logic_vector(7 downto 0); 35 | SIGNAL sram_mode : SRAM_Mode_Type := off; 36 | SIGNAL state : SRAM_State_Type := Init; 37 | SIGNAL next_state : SRAM_State_Type := Init; 38 | SIGNAL delay : unsigned(3 downto 0); 39 | 40 | -- turbo-slow 41 | CONSTANT sram_delay : natural := 50; 42 | 43 | begin 44 | 45 | sram_data_in <= sram_data; 46 | sram_data <= sram_data_out when sram_mode = write else "ZZZZZZZZ"; 47 | 48 | sram_we <= '0' when sram_mode = write else '1'; 49 | sram_oe <= '0' when sram_mode = read else '1'; 50 | sram_ce <= '0'; -- when sram_mode /= off else '1'; 51 | 52 | p0 : PROCESS(clk, rst) is 53 | procedure goTo(st : SRAM_State_Type; cycCount: natural) is 54 | begin 55 | state <= st; 56 | delay <= to_unsigned(cycCount, delay'length); 57 | end procedure; 58 | BEGIN 59 | if rst = '0' then 60 | bus_acknowledge <= '0'; 61 | sram_mode <= off; 62 | state <= Init; 63 | sram_data_out <= (others => '0'); 64 | delay <= to_unsigned(0, delay'length); 65 | else 66 | if rising_edge(clk) then 67 | if bus_request = '1' then 68 | if delay /= 0 then 69 | delay <= delay - 1; 70 | else 71 | case state is 72 | when Init => 73 | if bus_write = '1' then 74 | sram_mode <= write; 75 | else 76 | sram_mode <= read; 77 | end if; 78 | if bus_bls(0) = '1' then 79 | goTo(AccessLow, sram_delay); 80 | sram_addr <= bus_address(18 downto 1) & "0"; 81 | sram_data_out <= bus_data_in(7 downto 0); 82 | bus_data_out(15 downto 8) <= "00000000"; 83 | else 84 | goTo(AccessHigh, sram_delay); 85 | sram_addr <= bus_address(18 downto 1) & "1"; 86 | sram_data_out <= bus_data_in(15 downto 8); 87 | bus_data_out(7 downto 0) <= "00000000"; 88 | end if; 89 | 90 | when AccessLow => 91 | sram_mode <= off; 92 | bus_data_out(7 downto 0) <= sram_data_in; 93 | if bus_bls(1) = '1' then 94 | goTo(AccessHighDelay, sram_delay); 95 | else 96 | bus_acknowledge <= '1'; 97 | goTo(state, 0); -- no delay required, we are finished anyways 98 | end if; 99 | 100 | when AccessHighDelay => 101 | if bus_write = '1' then 102 | sram_mode <= write; 103 | else 104 | sram_mode <= read; 105 | end if; 106 | sram_data_out <= bus_data_in(15 downto 8); 107 | sram_addr <= bus_address(18 downto 1) & "1"; 108 | goTo(AccessHigh, sram_delay); 109 | 110 | when AccessHigh => 111 | bus_data_out(15 downto 8) <= sram_data_in; 112 | bus_acknowledge <= '1'; 113 | goTo(Done, 0); -- no delay required, we are done 114 | sram_mode <= off; 115 | 116 | when Done => 117 | bus_acknowledge <= '1'; 118 | 119 | end case; 120 | end if; 121 | else 122 | sram_mode <= off; 123 | state <= Init; 124 | bus_acknowledge <= '0'; 125 | end if; 126 | end if; 127 | end if; 128 | END PROCESS; 129 | 130 | end architecture; -------------------------------------------------------------------------------- /soc/vhdl/src/uart_receiver.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY IEEE; 2 | USE IEEE.std_logic_1164.ALL; 3 | USE IEEE.numeric_std.ALL; 4 | 5 | ENTITY UART_Receiver IS 6 | GENERIC ( 7 | clkfreq : natural; -- frequency of 'clk' in Hz 8 | baudrate : natural -- basic symbol rate of the UART ("bit / sec") 9 | ); 10 | PORT ( 11 | rst : in std_logic; -- asynchronous reset 12 | clk : in std_logic; -- the clock for the uart operation. 13 | rxd : in std_logic; -- uses logic levels, non-inverted 14 | bsy : out std_logic; -- is '1' when receiving a byte and '0' when not. 15 | data : out unsigned(7 downto 0); -- the data to send. must be valid in the first clock cycle where send='1' 16 | recv : out std_logic -- when '1', data transmission is complete. this bit is only set for 1 clk cycle 17 | ); 18 | 19 | END ENTITY UART_Receiver; 20 | 21 | ARCHITECTURE rtl OF UART_Receiver IS 22 | TYPE FSM_State IS (IDLE, START, BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, STOP ); 23 | CONSTANT clk_limit : natural := (clkfreq / baudrate) - 1; 24 | 25 | SIGNAL clkdiv : unsigned(31 downto 0); 26 | SIGNAL state : FSM_State; 27 | SIGNAL data_buffer : unsigned(7 downto 0); 28 | BEGIN 29 | 30 | P0: PROCESS (clk, rst) 31 | BEGIN 32 | if rst = '0' then 33 | clkdiv <= to_unsigned(0, clkdiv'length); 34 | state <= IDLE; 35 | recv <= '0'; 36 | bsy <= '0'; 37 | else 38 | if rising_edge(clk) then 39 | if state = IDLE then 40 | -- prepare for first bit reception 41 | clkdiv <= to_unsigned(clk_limit / 2, clkdiv'length); 42 | 43 | recv <= '0'; 44 | 45 | if rxd = '0' then 46 | state <= START; 47 | bsy <= '1'; 48 | else 49 | bsy <= '0'; 50 | end if; 51 | else 52 | -- this path here is clocked with `baud` Hz instead of the base frequency 53 | if clkdiv = 0 then 54 | clkdiv <= to_unsigned(clk_limit, clkdiv'length); 55 | 56 | CASE state IS 57 | WHEN IDLE => 58 | -- transfer individual bits 59 | WHEN START => 60 | if rxd = '0' then 61 | -- start bit confirmed, let's go! 62 | state <= BIT0; 63 | else 64 | -- this was a glitch, not a start bit 65 | state <= IDLE; 66 | end if; 67 | 68 | WHEN BIT0 => data_buffer(0) <= rxd; state <= BIT1; 69 | WHEN BIT1 => data_buffer(1) <= rxd; state <= BIT2; 70 | WHEN BIT2 => data_buffer(2) <= rxd; state <= BIT3; 71 | WHEN BIT3 => data_buffer(3) <= rxd; state <= BIT4; 72 | WHEN BIT4 => data_buffer(4) <= rxd; state <= BIT5; 73 | WHEN BIT5 => data_buffer(5) <= rxd; state <= BIT6; 74 | WHEN BIT6 => data_buffer(6) <= rxd; state <= BIT7; 75 | WHEN BIT7 => data_buffer(7) <= rxd; state <= STOP; 76 | 77 | WHEN STOP => 78 | -- when we received a valid stop bit, send data, 79 | -- else: discard 80 | if rxd = '1' then 81 | recv <= '1'; 82 | data <= data_buffer; 83 | state <= IDLE; 84 | end if; 85 | END CASE; 86 | 87 | else 88 | clkdiv <= clkdiv - 1; 89 | end if; 90 | end if; 91 | end if; 92 | end if; 93 | END PROCESS P0; 94 | 95 | END ARCHITECTURE rtl ; -------------------------------------------------------------------------------- /specification/README.md: -------------------------------------------------------------------------------- 1 | # System Specification 2 | 3 | This folder contains lua files that either contain datasets that specify system components or transform those components into other formats -------------------------------------------------------------------------------- /specification/devices/irq.lua: -------------------------------------------------------------------------------- 1 | local Datasheet = require "Datasheet" 2 | local Peripherial = require "Peripherial" 3 | 4 | 5 | return Datasheet { 6 | id = "irq", 7 | name = "IRQ Controller", 8 | 9 | registers = Peripherial.RegisterSet { 10 | Peripherial.Register("IRQ0", 0, 2, "RO", "Active IRQs 0…15") [[ 11 | When read, all IRQs between 0 and 15 that were triggered since the last acknowledge are 12 | displayed as `1`. All non-triggered IRQs are `0`. 13 | ]], 14 | Peripherial.Register("IRQ1", 2, 2, "RO", "Active IRQs 16…31") [[ 15 | When read, all IRQs between 16 and 31 that were triggered since the last acknowledge are 16 | displayed as `1`. All non-triggered IRQs are `0`. 17 | ]], 18 | Peripherial.Register("ACK0", 0, 2, "WO", "Acknowledge IRQs 0…15") [[ 19 | When writing to this register, all bits that are `1` in this register will be acknowledged and reset. 20 | ]], 21 | Peripherial.Register("ACK1", 2, 2, "WO", "Acknowledge IRQs 16…31") [[ 22 | When writing to this register, all bits that are `1` in this register will be acknowledged and reset. 23 | ]], 24 | Peripherial.Register("MASK0", 4, 2, "RW", "Mask IRQs 0…15") [[ 25 | When a bit is 1, the corresponding interrupt is masked and will not be able to get active. On controller reset, all interrupts are masked. 26 | ]], 27 | Peripherial.Register("MASK1", 6, 2, "RW", "Mask IRQs 16…31") [[ 28 | When a bit is 1, the corresponding interrupt is masked and will not be able to get active. On controller reset, all interrupts are masked. 29 | ]], 30 | }, 31 | 32 | Datasheet.Chapter("Overview") [[ 33 | - Dispatch multiple IRQ lanes into a single lane 34 | - Acknowledge of IRQs 35 | - Masking of IRQs 36 | - up to 32 IRQs 37 | ]], 38 | 39 | Datasheet.Chapter("Function") [[ 40 | The IRQ controller manages up to 32 different IRQ sources that work with level-driven IRQs. 41 | If a source IRQ lane is *low*, the IRQ is assumed to be active. A IRQ becomes inactive when the 42 | source lane will go to *high*. 43 | 44 | When an IRQ becomes active, a corresponding bit is set in the `IRQ0` or `IRQ1` register and the output IRQ lane is pulled to *low*. 45 | The output IRQ lane is *low* until all bits in the `IRQ0` and `IRQ1` registers are `0`. 46 | 47 | To acknowledge that an IRQ was handled, write a `1` bit into `IRQ0` or `IRQ1` to tell the controller that this interrupt was handled. 48 | If the IRQ was previously active, it is now disabled. 49 | 50 | Masking interrupts is supported by writing a `1` bit to `MASK0` or `MASK1`. Interrupts will only become active when the IRQ lane is *low* and the corresponding bit in `MASK0` or `MASK1` is `0`. When the controller is reset, all interrupts are masked. 51 | ]], 52 | 53 | Datasheet.ImplementChapter("Registers", Peripherial.RegisterChapter) 54 | } -------------------------------------------------------------------------------- /specification/devices/uart.lua: -------------------------------------------------------------------------------- 1 | local Datasheet = require "Datasheet" 2 | local Peripherial = require "Peripherial" 3 | 4 | return Datasheet { 5 | id = "uart", 6 | name = "TinyUART", 7 | brief = "A 16C550 compatible UART component.", 8 | 9 | registers = Peripherial.RegisterSet { 10 | Peripherial.Register("RBR", 0, 1, "RO", "(DLAB=0) Receiver buffer"), 11 | Peripherial.Register("THR", 0, 1, "WO", "(DLAB=0) Transmitter holding register"), 12 | Peripherial.Register("IER", 1, 1, "RW", "(DLAB=0) Interrupt enable register"), 13 | Peripherial.Register("DLL", 0, 1, "RW", "(DLAB=1) Divisor latch (LSB)"), 14 | Peripherial.Register("DLM", 1, 1, "RW", "(DLAB=1) Divisor latch (MSB)"), 15 | Peripherial.Register("IIR", 2, 1, "RO", "Interrupt identification register"), 16 | Peripherial.Register("FCR", 2, 1, "WO", "FIFO control register"), 17 | Peripherial.Register("LCR", 3, 1, "RW", "Line control register"), 18 | Peripherial.Register("MCR", 4, 1, "RW", "Modem control register"), 19 | Peripherial.Register("LSR", 5, 1, "RO", "Line status register"), 20 | Peripherial.Register("MSR", 6, 1, "RO", "Modem status register"), 21 | Peripherial.Register("SCR", 7, 1, "RW", "Scratch register"), 22 | }, 23 | 24 | Datasheet.Chapter("Features") [[ 25 | The TinyUART is a 16C550 compatible UART implementation that provides a fully featured UART interface including flow- and modem control. 26 | ]], 27 | 28 | Datasheet.ImplementChapter("Registers", Peripherial.RegisterChapter), 29 | } -------------------------------------------------------------------------------- /specification/gen-gpio-pins.lua: -------------------------------------------------------------------------------- 1 | local device_map = require "specification/device_map" 2 | 3 | local devices = {} 4 | local tot_gpio = 0 5 | 6 | for i,v in ipairs(device_map) do 7 | for n=1,v.count do 8 | local dev = { 9 | name = v.name, 10 | gpio = v.gpio, 11 | } 12 | if v.count > 1 then 13 | dev.index = n 14 | dev.name = dev.name .. (" (%d)"):format(n) 15 | end 16 | devices[#devices+1] = dev 17 | 18 | if #dev.gpio > 0 then 19 | print(dev.name .. " => " .. tostring(#dev.gpio)) 20 | end 21 | 22 | tot_gpio = tot_gpio + #dev.gpio 23 | 24 | end 25 | end 26 | 27 | print("total gpio count:", tot_gpio) -------------------------------------------------------------------------------- /specification/gen-register-space.lua: -------------------------------------------------------------------------------- 1 | local device_map = require "specification/device_map" 2 | 3 | local page_start = 0x7FE000 4 | local off = 0 5 | local align = 16 6 | 7 | local devices = {} 8 | 9 | for i,v in ipairs(device_map) do 10 | for n=1,v.count do 11 | -- align forward 12 | local a = v.align or align 13 | off = a * math.ceil(off / a) 14 | 15 | local dev = { 16 | offset = off, 17 | name = v.name, 18 | proto = v, 19 | size = 2 * v.reg16 + v.reg8, 20 | } 21 | if v.count > 1 then 22 | dev.index = n 23 | dev.name = dev.name .. (" (%d)"):format(n) 24 | end 25 | devices[#devices+1] = dev 26 | 27 | off = off + 2 * v.reg16 28 | off = off + v.reg8 29 | end 30 | end 31 | 32 | io.write("\n") 33 | 34 | io.write("# Register Space\n\n") 35 | 36 | io.write("## Device Overview\n\n") 37 | 38 | for i,v in ipairs(device_map) do 39 | io.write("**[", v.name, "](",v.url, "):**\n\n") 40 | 41 | if v.count > 1 then 42 | io.write(("- %d Devices\n"):format(v.count)) 43 | else 44 | io.write("- 1 Device\n") 45 | end 46 | 47 | if v.reg16 > 0 then 48 | io.write(("- %d Registers @ 16 Bit\n"):format(v.reg16)) 49 | end 50 | if v.reg8 > 0 then 51 | io.write(("- %d Registers @ 8 Bit\n"):format(v.reg8)) 52 | end 53 | 54 | io.write("\n") 55 | end 56 | 57 | io.write("## Device Mapping\n\n") 58 | 59 | -- io.write(("- Page Offset (Physical): `0x%06X`\n\n"):format(page_start)) 60 | 61 | io.write("| Address | Offset | Count | Peripherial |\n") 62 | io.write("|------------|--------|--------|-------------------------------------|\n") 63 | 64 | for i,v in ipairs(devices) do 65 | io.write(("| `0x%06X` | %6d | %6d | %-35s |\n"):format(page_start+v.offset,v.offset,v.size,("[%s](%s)"):format( v.name,v.proto.url))) 66 | end 67 | 68 | io.write(("| `0x%06X` | %6d | | %-35s |\n"):format(page_start+off,off,"*end of peripherials*")) -------------------------------------------------------------------------------- /specification/modules/Database.lua: -------------------------------------------------------------------------------- 1 | require "lfs" 2 | 3 | local Datasheet = require "Datasheet" 4 | 5 | local function load(root_path) 6 | local datasheets = {} 7 | 8 | for path in lfs.dir(root_path.."/devices") do 9 | if path:match(".lua$") then 10 | local full_path = root_path.."/devices/" .. path 11 | local ds = dofile(full_path) or error(path .. " does not return a datasheet!") 12 | ds.id = ds.id or path:gsub(".lua$", "") 13 | ds.full_path = full_path 14 | table.insert(datasheets, ds) 15 | if datasheets[ds.id] then 16 | error("A datasheet with the id " .. ds.id .. " already exists!") 17 | end 18 | datasheets[ds.id] = ds 19 | end 20 | end 21 | 22 | return { 23 | datasheets = datasheets, 24 | } 25 | end 26 | 27 | return load -------------------------------------------------------------------------------- /specification/modules/Datasheet.lua: -------------------------------------------------------------------------------- 1 | local Datasheet = {} 2 | 3 | local function join(sep, table) 4 | local s = "" 5 | for i=1,#table do 6 | if i > 1 then 7 | s = s .. sep 8 | end 9 | s = s .. tostring(table[i]) 10 | end 11 | return s 12 | end 13 | 14 | local function createAnchorString(str) 15 | return str:gsub("[%W]", "-"):lower() 16 | end 17 | 18 | local function flattenString(string) 19 | local indent 20 | return string:gsub("[^\n]+", function(line) 21 | if indent == nil then 22 | indent = line:match("%s+") 23 | end 24 | return line:sub(#indent + 1) 25 | end) 26 | end 27 | 28 | function Datasheet.Chapter(title) 29 | return function (contents) 30 | return { 31 | title = tostring(title) or error("requires title"), 32 | contents = flattenString(tostring(contents) or error("requires contents!")), 33 | } 34 | end 35 | end 36 | 37 | function Datasheet.ImplementChapter(title, implementor) 38 | return { 39 | title = tostring(title) or error("requires title"), 40 | implementor = implementor or error("requires implementor"), 41 | } 42 | end 43 | 44 | 45 | function Datasheet.renderMarkdown(datasheet, emitter) 46 | assert(datasheet, "requires datasheet") 47 | assert(emitter, "requires emitter") 48 | 49 | function emit(...) 50 | emitter(join("", table.pack(...))) 51 | end 52 | 53 | function emitln(...) 54 | emit(...) 55 | emit("\n") 56 | end 57 | 58 | if datasheet.full_path then 59 | emitln("") 60 | end 61 | 62 | emitln("# ", datasheet.name) 63 | emitln() 64 | if datasheet.brief then 65 | emitln(datasheet.brief) 66 | emitln() 67 | end 68 | 69 | if #datasheet > 0 then 70 | 71 | for i=1,#datasheet do 72 | local chapter = datasheet[i] 73 | 74 | emitln("- [", chapter.title, "](#", createAnchorString(chapter.title), ")") 75 | end 76 | emitln() 77 | end 78 | 79 | for i=1,#datasheet do 80 | local chapter = datasheet[i] 81 | emitln("## ", chapter.title) 82 | emitln() 83 | if chapter.contents then 84 | emitln(chapter.contents) 85 | elseif chapter.implementor then 86 | emitln(chapter.implementor(datasheet, chapter)) 87 | end 88 | 89 | end 90 | 91 | end 92 | 93 | 94 | local mt = { } 95 | function mt.__call(self, datasheet) 96 | assert(datasheet, "Datasheet requires at least one argument!") 97 | local function hasField(n) 98 | assert(datasheet[n], "Datasheet requires field " .. n ) 99 | end 100 | 101 | hasField "id" 102 | hasField "name" 103 | 104 | return datasheet 105 | end 106 | 107 | setmetatable(Datasheet, mt) 108 | 109 | return Datasheet -------------------------------------------------------------------------------- /specification/modules/Peripherial.lua: -------------------------------------------------------------------------------- 1 | local Peripherial = {} 2 | 3 | function Peripherial.Register(name, offset, size, access, desc) 4 | local reg = { 5 | name = name or error("requires name!"), 6 | offset = tonumber(offset) or error("requires offset!"), 7 | size = tonumber(size) or error("requires size!"), 8 | access = tostring(access) or error("requires access"), 9 | desc = desc or "Missing description", 10 | } 11 | if reg.size ~= 1 and reg.size ~= 2 then 12 | error("size must be 1 or 2") 13 | end 14 | if reg.access ~= "RO" and reg.access ~= "WO" and reg.access ~= "RW" then 15 | error ("access must be RO, WO or RW") 16 | end 17 | 18 | return function(details) 19 | if details ~= nil then 20 | reg.details = tostring(details) 21 | end 22 | return reg 23 | end 24 | end 25 | 26 | function Peripherial.RegisterSet(set) 27 | for i=1,#set do 28 | local reg = set[i] 29 | 30 | if type(reg) == "function" then 31 | reg = reg(nil) -- no details given 32 | end 33 | 34 | set[i] = reg 35 | end 36 | return set 37 | end 38 | 39 | local function flattenString(string) 40 | local indent 41 | return string:gsub("[^\n]+", function(line) 42 | if indent == nil then 43 | indent = line:match("%s+") 44 | end 45 | return line:sub(#indent + 1) 46 | end) 47 | end 48 | 49 | function Peripherial.RegisterChapter(datasheet, chapter) 50 | 51 | local str = "" 52 | 53 | str = str .. "| Offset | Name | Size | Access | Description |" .. "\n" 54 | str = str .. "|---------|-------|------|--------|--------------------------------------------|" .. "\n" 55 | 56 | for i=1,#datasheet.registers do 57 | local reg = datasheet.registers[i] 58 | 59 | local access = ({ 60 | RO = "R", 61 | WO = "W", 62 | RW = "R/W", 63 | })[reg.access] 64 | 65 | str = str .. ("| `0x%03X` | %-5s | %4d | %-6s | %-42s |\n"):format( 66 | reg.offset, 67 | reg.name, 68 | reg.size, 69 | access, 70 | reg.desc 71 | ) 72 | 73 | end 74 | 75 | for i=1,#datasheet.registers do 76 | local reg = datasheet.registers[i] 77 | if reg.details and #reg.details > 0 then 78 | str = str .. "\n" 79 | str = str .. "### " .. reg.desc .. "\n\n" 80 | str = str .. flattenString(reg.details) 81 | end 82 | end 83 | 84 | return str 85 | end 86 | 87 | return Peripherial -------------------------------------------------------------------------------- /specification/render-documents.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua5.3 2 | 3 | local root_path = arg[0]:gsub("/[^/]+", "") 4 | package.path = root_path .. "/modules/?.lua;" .. package.path 5 | 6 | 7 | local Datasheet = require "Datasheet" 8 | 9 | local loadDB = require "Database" 10 | 11 | local db = loadDB(root_path) 12 | 13 | for i=1,#db.datasheets do 14 | local ds = db.datasheets[i] 15 | 16 | local output_path = root_path .. "/../documentation/specs/" .. ds.id .. ".md" 17 | 18 | print("Rendering "..output_path) 19 | 20 | local f = io.open(output_path, "wb") 21 | 22 | Datasheet.renderMarkdown( 23 | ds, 24 | function(text) 25 | f:write(text) 26 | end 27 | ) 28 | f:close() 29 | 30 | end 31 | -------------------------------------------------------------------------------- /tasks/README.md: -------------------------------------------------------------------------------- 1 | # Common Tasks 2 | 3 | This folder contains scripts that solve a common development task that is not worth integrating in the build script -------------------------------------------------------------------------------- /tasks/build-website.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | clear 4 | zig build install firmware wasm 5 | mkdocs build 6 | cp zig-out/lib/emulator.wasm website-out/livedemo/emulator.wasm 7 | cp -r website/* website-out/livedemo/ 8 | -------------------------------------------------------------------------------- /tasks/run-basic-emulator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | clear 5 | zig build 6 | ./zig-out/bin/assembler --format ihex --output /tmp/firmware.hex apps/web-firmware/main.asm 7 | ./zig-out/bin/assembler --format ihex --output /tmp/demo.hex apps/web-firmware/demo.asm 8 | 9 | clear 10 | 11 | echo "demo application:" 12 | cat /tmp/demo.hex 13 | 14 | echo "" # empty line 15 | 16 | ./zig-out/bin/emulator /tmp/firmware.hex "$@" 17 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | This folder contains several files related to testing the toolchain 2 | 3 | - `include.inc` is for testing `.include` and `.incbin` in the assembler -------------------------------------------------------------------------------- /test/include.inc: -------------------------------------------------------------------------------- 1 | .ascii "include" -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | ## ISA Changes 2 | - Refine interrupt handling 3 | - Add instruction `cpuctrl` (reset, halt, soft-interrupt, cpuid, ...) 4 | - Swap input0, input1 for STORE{8,16} instructions. Improves overall assembler quality 5 | 6 | ## SOC Changes 7 | - Design and calculate GPU 8 | x Add basic VGA module (only "background color") 9 | x 640x480 VGA resolution 10 | x 256×128 pixel output 11 | - 65536-Color RGB (RGB565) 12 | - Use 4 bit dual port frame buffer RAM 13 | - Finalize blitter design (see vchip.md) 14 | - Finalize sprite design (see vga.md) 15 | - Make bus mastering configurable 16 | 17 | - FIX: EBR ROM is zero all the time :( 18 | - ADD: Read CPU registers via CMD 19 | - ADD: Write CPU registers via CMD 20 | 21 | ## Tooling Changes 22 | - Rewrite assembler with support for new features: 23 | - rewrite expression parser to recursive-decent 24 | - allow expression evaluation 25 | - Implement function evaluation 26 | - improve error reporting 27 | - Refine function call syntax `#bswap()` to have simpler parsing 28 | - Support new debug features 29 | - break 30 | - inspect/write registers 31 | - restart 32 | - Add feature: Load ihex with offset / banking (16 MB memory space vs. 64k) 33 | 34 | ## Documentation Change 35 | - Write about common patterns in AN000 36 | 37 | ## Website 38 | - Improve *Try it!* 39 | - Add assembler 40 | - Add controls 41 | - Add hex view 42 | 43 | 44 | To overcome the 64k memory limitation own to 16 bit cpus is overcome by a paging... 45 | 46 | The SPU Mark II uses the little endian encoding, so the less significant byte is at the lower address, the more significant byte at the higher address. 47 | bit, not byte 48 | least significant bit, most significant bit 49 | 50 | ist der MSB bei LOAD8 undefined? 51 | -------------------------------------------------------------------------------- /tools/bit-loader/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const pcx = @import("pcx.zig"); 3 | const argsParser = @import("args"); 4 | 5 | pub fn main() !u8 { 6 | const cli_args = argsParser.parseForCurrentProcess(struct { 7 | help: bool = false, 8 | output: ?[]const u8 = null, 9 | 10 | pub const shorthands = .{ 11 | .h = "help", 12 | .o = "output", 13 | }; 14 | }, std.heap.page_allocator, .print) catch return 1; 15 | defer cli_args.deinit(); 16 | 17 | if (cli_args.options.help or cli_args.positionals.len != 1) { 18 | try std.io.getStdOut().writer().writeAll( 19 | \\bit-converter --help [--output file] pcx-file 20 | \\Converts a PCX file into a bit-bang sequence for the 21 | \\ 22 | \\-h, --help Displays this help text. 23 | \\-o, --output Defines the name of the output file. If not given, 24 | \\ the bit-converter will write the bit sequence to stdout. 25 | \\ 26 | ); 27 | return if (cli_args.options.help) @as(u8, 0) else @as(u8, 1); 28 | } 29 | 30 | var file = try std.fs.cwd().openFile(cli_args.positionals[0], .{ .read = true, .write = false }); 31 | defer file.close(); 32 | 33 | var img = try pcx.load(std.heap.page_allocator, &file); 34 | defer img.deinit(); 35 | 36 | if (img != .bpp8) { 37 | try std.io.getStdErr().writer().print("The provided file is not a file with 8 bit per pixel, but uses the format {}!\n", .{ 38 | @as(pcx.Format, img), 39 | }); 40 | return 1; 41 | } 42 | 43 | var out = if (cli_args.options.output) |outfile| 44 | try std.fs.cwd().createFile(outfile, .{ .truncate = true }) 45 | else 46 | std.io.getStdOut(); 47 | 48 | defer if (cli_args.options.output) |_| 49 | out.close(); 50 | 51 | var ostream = out.writer(); 52 | 53 | var y: usize = 0; 54 | while (y < 128) : (y += 1) { 55 | var x: usize = 0; 56 | while (x < 256) : (x += 1) { 57 | try ostream.writeIntLittle(u8, 'B'); 58 | try ostream.writeIntLittle(u24, 0x810000 | @intCast(u24, y << 8) | @intCast(u24, x)); 59 | try ostream.writeIntLittle(u8, img.bpp8.pixels[y * img.bpp8.width + x]); 60 | } 61 | } 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /tools/common/spu-2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define SPU_VERSION_MAJOR 2 6 | #define SPU_VERSION_MINOR 1 7 | 8 | typedef uint16_t word_t; 9 | typedef uint8_t byte_t; 10 | 11 | #define INSTR_ENCODE(ex, i0, i1, fl, ou, cm) 0 | ((ex & 07) << 0) | ((i0 & 03) << 3) | ((i1 & 03) << 5) | ((fl & 01) << 7) | ((ou & 03) << 8) | ((cm & 63) << 10) 12 | 13 | #define INSTR_GETEXEC(iword) (((iword) >> 0) & 07) 14 | #define INSTR_GETI0(iword) (((iword) >> 3) & 03) 15 | #define INSTR_GETI1(iword) (((iword) >> 5) & 03) 16 | #define INSTR_GETFLAG(iword) (((iword) >> 7) & 01) 17 | #define INSTR_GETOUT(iword) (((iword) >> 8) & 03) 18 | #define INSTR_GETCMD(iword) (((iword) >> 10) & 63) 19 | 20 | // Misuse the INSTR_ENCODE macro to create the bit masks :) 21 | #define INSTR_MASK_EXEC INSTR_ENCODE(0xFFFF, 0, 0, 0, 0, 0) 22 | #define INSTR_MASK_INPUT0 INSTR_ENCODE(0, 0xFFFF, 0, 0, 0, 0) 23 | #define INSTR_MASK_INPUT1 INSTR_ENCODE(0, 0, 0xFFFF, 0, 0, 0) 24 | #define INSTR_MASK_FLAG INSTR_ENCODE(0, 0, 0, 0xFFFF, 0, 0) 25 | #define INSTR_MASK_OUTPUT INSTR_ENCODE(0, 0, 0, 0, 0xFFFF, 0) 26 | #define INSTR_MASK_CMD INSTR_ENCODE(0, 0, 0, 0, 0, 0xFFFF) 27 | 28 | #define INPUT_ZERO 0 29 | #define INPUT_ARG 1 30 | #define INPUT_PEEK 2 31 | #define INPUT_POP 3 32 | 33 | #define EXEC_ALWAYS 0 34 | #define EXEC_ZERO 1 35 | #define EXEC_NONZERO 2 36 | #define EXEC_GREATER 3 37 | #define EXEC_LESS 4 38 | #define EXEC_GEQUAL 5 39 | #define EXEC_LEQUAL 6 40 | #define EXEC_OVERFLOW 7 41 | 42 | #define OUTPUT_DISCARD 0 43 | #define OUTPUT_PUSH 1 44 | #define OUTPUT_JUMP 2 45 | #define OUTPUT_RJUMP 3 46 | 47 | #define CMD_COPY 0 48 | #define CMD_IPGET 1 49 | #define CMD_GET 2 50 | #define CMD_SET 3 51 | #define CMD_STOR8 4 52 | #define CMD_STOR16 5 53 | #define CMD_LOAD8 6 54 | #define CMD_LOAD16 7 55 | // UNDEFINED 8 56 | // UNDEFINED 9 57 | #define CMD_FRGET 10 58 | #define CMD_FRSET 11 59 | #define CMD_BPGET 12 60 | #define CMD_BPSET 13 61 | #define CMD_SPGET 14 62 | #define CMD_SPSET 15 63 | #define CMD_ADD 16 64 | #define CMD_SUB 17 65 | #define CMD_MUL 18 66 | #define CMD_DIV 19 67 | #define CMD_MOD 20 68 | #define CMD_AND 21 69 | #define CMD_OR 22 70 | #define CMD_XOR 23 71 | #define CMD_NOT 24 72 | #define CMD_SIGNEXT 25 73 | #define CMD_ROL 26 74 | #define CMD_ROR 27 75 | #define CMD_BSWAP 28 76 | #define CMD_ASR 29 77 | #define CMD_LSL 30 78 | #define CMD_LSR 31 79 | -------------------------------------------------------------------------------- /tools/common/vt100.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define VT_CLS "\033[2J" 4 | #define VT_HOME "\033[H" 5 | #define VT_SETPOS(x,y) "\033[" #x ";" #y "H" 6 | 7 | #define VT_RESET "\033c" 8 | #define VT_ENABLE_LINEWRAP "\033[7j" 9 | #define VT_DISABLE_LINEWRAP "\033[7l" 10 | 11 | #define VT_CUR_UP "\033[A" 12 | #define VT_CUR_DOWN "\033[B" 13 | #define VT_CUR_LEFT "\033[D" 14 | #define VT_CUR_RIGHT "\033[C" 15 | #define VT_CUR_SAVE "\033[s" 16 | #define VT_CUR_RESTORE "\033[u" -------------------------------------------------------------------------------- /tools/disassembler/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const argsParser = @import("args"); 3 | const ihex = @import("ihex"); 4 | 5 | const spu = @import("spu-mk2"); 6 | 7 | const FileFormat = enum { ihex, binary }; 8 | const DisasmError = error{EndOfStream} || std.os.WriteError || std.io.FixedBufferStream([]const u8).ReadError; 9 | 10 | fn processRecord(out: *const std.io.Writer(std.fs.File, std.os.WriteError, std.fs.File.write), base: u32, data: []const u8) DisasmError!void { 11 | const in = std.io.fixedBufferStream(data).reader(); 12 | 13 | var offset = base; 14 | 15 | while (true) { 16 | try out.print("{X:0>4} ", .{offset}); 17 | offset += 2; 18 | 19 | if (in.readIntLittle(u16)) |instr_int| { 20 | const instr = @bitCast(spu.Instruction, instr_int); 21 | 22 | try out.print("{}", .{instr}); 23 | 24 | if (instr.input0 == .immediate) { 25 | offset += 2; 26 | const val = in.readIntLittle(u16) catch |err| switch (err) { 27 | error.EndOfStream => { 28 | try out.writeAll(" | ????\n"); 29 | return; 30 | }, 31 | else => return err, 32 | }; 33 | try out.print(" | {X:0>4}", .{val}); 34 | } 35 | 36 | if (instr.input1 == .immediate) { 37 | offset += 2; 38 | const val = in.readIntLittle(u16) catch |err| switch (err) { 39 | error.EndOfStream => { 40 | try out.writeAll(" | ????\n"); 41 | return; 42 | }, 43 | else => return err, 44 | }; 45 | try out.print(" | {X:0>4}", .{val}); 46 | } 47 | 48 | try out.writeAll("\n"); 49 | } else |err| { 50 | switch (err) { 51 | error.EndOfStream => break, 52 | else => return err, 53 | } 54 | } 55 | } 56 | } 57 | 58 | pub fn main() !u8 { 59 | const cli_args = argsParser.parseForCurrentProcess(struct { 60 | help: bool = false, 61 | format: ?FileFormat = null, 62 | offset: ?u16 = null, 63 | 64 | pub const shorthands = .{ 65 | .h = "help", 66 | .f = "format", 67 | }; 68 | }, std.heap.page_allocator, .print) catch return 1; 69 | defer cli_args.deinit(); 70 | 71 | const out = std.io.getStdOut().writer(); 72 | 73 | if (cli_args.options.help or cli_args.positionals.len == 0) { 74 | try out.writeAll( 75 | \\disassembler --help [--format ihex|binary] [--offset XXXX] fileA fileB 76 | \\Disassembles code for the SPU Mark II platform. 77 | \\ 78 | \\-h, --help Displays this help text. 79 | \\-f, --format Selects the input format (binary or ihex). 80 | \\ If not given, the file extension will be used 81 | \\ to guess the format. 82 | \\--offset XXXX Defines the disassembly offset for binary files. 83 | \\ 84 | ); 85 | return if (cli_args.options.help) @as(u8, 0) else @as(u8, 1); 86 | } 87 | 88 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); 89 | defer arena.deinit(); 90 | 91 | const hexParseMode = ihex.ParseMode{ .pedantic = true }; 92 | for (cli_args.positionals) |path| { 93 | var file = try std.fs.cwd().openFile(path, .{ .read = true, .write = false }); 94 | defer file.close(); 95 | if (std.mem.endsWith(u8, path, ".hex")) { 96 | // Emulator will always start at address 0x0000 or CLI given entry point. 97 | _ = try ihex.parseData(file.reader(), hexParseMode, &out, DisasmError, processRecord); 98 | } else { 99 | const buffer = try file.reader().readAllAlloc(arena.allocator(), 65536); 100 | defer arena.allocator().free(buffer); 101 | 102 | try processRecord(&out, cli_args.options.offset orelse 0x0000, buffer); 103 | } 104 | } 105 | 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /tools/emulator/shared.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const spu = @import("spu-mk2"); 3 | 4 | const SerialEmulator = @import("root").SerialEmulator; 5 | 6 | pub const WasmDemoMachine = struct { 7 | const Self = @This(); 8 | 9 | memory: [65536]u8 = undefined, // lower half is ROM, upper half is RAM 10 | 11 | pub const LoaderError = error{InvalidAddress}; 12 | pub fn loadHexRecord(self: *Self, base: u32, data: []const u8) LoaderError!void { 13 | // std.debug.warn("load {}+{}: {X}\n", .{ base, data.len, data }); 14 | for (data) |byte, offset| { 15 | const address = base + offset; 16 | switch (address) { 17 | 0x0000...0xFFFF => |a| self.memory[a] = byte, 18 | else => return error.InvalidAddress, 19 | } 20 | } 21 | } 22 | 23 | pub fn read8(self: *Self, address: u16) !u8 { 24 | return switch (address) { 25 | 0x7FFE...0x7FFF => return error.BusError, 26 | else => self.memory[address], 27 | }; 28 | } 29 | 30 | pub fn write8(self: *Self, address: u16, value: u8) !void { 31 | switch (address) { 32 | 0x0000...0x7FFD => return error.BusError, 33 | 0x7FFE...0x7FFF => return error.BusError, 34 | 0x8000...0xFFFF => self.memory[address] = value, 35 | } 36 | } 37 | 38 | pub fn read16(self: *Self, address: u16) !u16 { 39 | return switch (address) { 40 | 0x7FFE...0x7FFF => try SerialEmulator.read(), 41 | else => std.mem.readIntLittle(u16, self.memory[address..][0..2]), 42 | }; 43 | } 44 | 45 | pub fn write16(self: *Self, address: u16, value: u16) !void { 46 | return switch (address) { 47 | 0x0000...0x7FFD => return error.BusError, 48 | 0x7FFE...0x7FFF => try SerialEmulator.write(value), 49 | 0x8000...0xFFFF => std.mem.writeIntLittle(u16, self.memory[address..][0..2], value), 50 | }; 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /tools/emulator/web-main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | const spu = @import("spu-mk2"); 4 | const common = @import("shared.zig"); 5 | 6 | var emulator: spu.SpuMk2(common.WasmDemoMachine) = undefined; 7 | 8 | const bootrom = @embedFile("../../zig-out/firmware/wasm.bin"); 9 | 10 | pub fn dumpState(emu: *spu.SpuMk2) !void { 11 | _ = emu; 12 | } 13 | 14 | pub fn dumpTrace(emu: *spu.SpuMk2, ip: u16, instruction: spu.Instruction, input0: u16, input1: u16, output: u16) !void { 15 | _ = emu; 16 | _ = ip; 17 | _ = instruction; 18 | _ = input0; 19 | _ = input1; 20 | _ = output; 21 | } 22 | 23 | export fn init() void { 24 | // serialWrite("a", 1); 25 | emulator = spu.SpuMk2(common.WasmDemoMachine).init(.{}); 26 | // serialWrite("b", 1); 27 | std.mem.copy(u8, &emulator.memory.memory, bootrom[0..std.math.min(emulator.memory.memory.len, bootrom.len)]); 28 | // serialWrite("c", 1); 29 | } 30 | 31 | export fn run(steps: u32) u32 { 32 | emulator.runBatch(steps) catch |err| { 33 | // halting is similar to debugging 34 | if (err != error.CpuHalted) 35 | emulator.reset(); 36 | switch (err) { 37 | error.BadInstruction => return 1, 38 | error.UnalignedAccess => return 2, 39 | error.BusError => return 3, 40 | error.DebugBreak => return 4, 41 | error.CpuHalted => return 5, 42 | } 43 | }; 44 | return 0; 45 | } 46 | 47 | export fn resetCpu() void { 48 | emulator.triggerInterrupt(.reset); 49 | } 50 | 51 | export fn invokeNmi() void { 52 | emulator.triggerInterrupt(.nmi); 53 | } 54 | 55 | export fn getMemoryPtr() [*]u8 { 56 | return &emulator.memory.memory; 57 | } 58 | 59 | extern fn invokeJsPanic() noreturn; 60 | 61 | extern fn serialRead(data: [*]u8, len: u32) u32; 62 | 63 | extern fn serialWrite(data: [*]const u8, len: u32) void; 64 | 65 | pub const SerialEmulator = struct { 66 | pub fn read() !u16 { 67 | var value: [1]u8 = undefined; 68 | if (serialRead(&value, 1) == 1) { 69 | return @as(u16, value[0]); 70 | } else { 71 | return 0xFFFF; 72 | } 73 | } 74 | 75 | pub fn write(value: u16) !void { 76 | serialWrite(&[_]u8{@truncate(u8, value)}, 1); 77 | } 78 | }; 79 | 80 | pub fn panic(message: []const u8, stackTrace: ?*std.builtin.StackTrace) noreturn { 81 | serialWrite(message.ptr, message.len); 82 | _ = stackTrace; 83 | invokeJsPanic(); 84 | } 85 | 86 | pub fn log(level: anytype, comptime fmt: []const u8, args: anytype) void { 87 | _ = level; 88 | _ = fmt; 89 | _ = args; 90 | // 91 | } 92 | -------------------------------------------------------------------------------- /tools/hex2bin/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const argsParser = @import("args"); 3 | const ihex = @import("ihex"); 4 | 5 | extern fn configure_serial(fd: c_int) u8; 6 | 7 | extern fn flush_serial(fd: c_int) void; 8 | 9 | pub fn main() anyerror!u8 { 10 | const cli_args = argsParser.parseForCurrentProcess(struct { 11 | // This declares long options for double hyphen 12 | output: ?[]const u8 = null, 13 | help: bool = false, 14 | size: ?usize = null, 15 | 16 | // This declares short-hand options for single hyphen 17 | pub const shorthands = .{ 18 | .o = "output", 19 | .h = "help", 20 | .s = "size", 21 | }; 22 | }, std.heap.page_allocator, .print) catch return 1; 23 | defer cli_args.deinit(); 24 | 25 | const stdout = std.io.getStdOut().writer(); 26 | // const stdin = std.io.getStdOut().reader(); 27 | 28 | if (cli_args.options.help or cli_args.positionals.len == 0 or cli_args.options.output == null) { 29 | try stdout.writeAll( 30 | \\ hex2bin [-h] [-o outfile] infile.hex [infile.hex …] 31 | \\ -h, --help Outputs this help text 32 | \\ -o, --output Defines the name of the output file, required 33 | \\ -s, --size If given, the file will have this size in bytes, 34 | \\ otherwise the size will be determined automatically. 35 | \\ 36 | \\ Combines one or more intel hex files into a binary file. 37 | \\ The output file will have all bytes set to zero for all bytes 38 | \\ not contained in the hex files. 39 | \\ 40 | ); 41 | return if (cli_args.options.help) @as(u8, 0) else 1; // when we explicitly call help, we succeed 42 | } 43 | 44 | const outfile = try std.fs.cwd().createFile(cli_args.options.output.?, .{ .truncate = true, .read = true }); 45 | defer outfile.close(); 46 | 47 | const HexParser = struct { 48 | const Self = @This(); 49 | const Error = error{InvalidHexFile} || std.os.WriteError || std.os.SeekError; 50 | 51 | file: *const std.fs.File, 52 | 53 | fn load(p: *const Self, base: u32, data: []const u8) Error!void { 54 | try p.file.seekTo(base); 55 | try p.file.writeAll(data); 56 | } 57 | }; 58 | 59 | const parseMode = ihex.ParseMode{ 60 | .pedantic = true, 61 | }; 62 | 63 | const parser = HexParser{ 64 | .file = &outfile, 65 | }; 66 | 67 | for (cli_args.positionals) |file_name| { 68 | var infile = try std.fs.cwd().openFile(file_name, .{ .read = true, .write = false }); 69 | defer infile.close(); 70 | 71 | _ = try ihex.parseData(infile.reader(), parseMode, &parser, HexParser.Error, HexParser.load); 72 | } 73 | 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /tools/vscode-ext/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": false, 4 | "commonjs": true, 5 | "es6": true, 6 | "node": true, 7 | "mocha": true 8 | }, 9 | "parserOptions": { 10 | "ecmaVersion": 2018, 11 | "ecmaFeatures": { 12 | "jsx": true 13 | }, 14 | "sourceType": "module" 15 | }, 16 | "rules": { 17 | "no-const-assign": "warn", 18 | "no-this-before-super": "warn", 19 | "no-undef": "warn", 20 | "no-unreachable": "warn", 21 | "no-unused-vars": "warn", 22 | "constructor-super": "warn", 23 | "valid-typeof": "warn" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tools/vscode-ext/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /tools/vscode-ext/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | test/** 4 | .gitignore 5 | .yarnrc 6 | vsc-extension-quickstart.md 7 | **/jsconfig.json 8 | **/*.map 9 | **/.eslintrc.json 10 | -------------------------------------------------------------------------------- /tools/vscode-ext/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "spu-mark-ii" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | - Initial release -------------------------------------------------------------------------------- /tools/vscode-ext/README.md: -------------------------------------------------------------------------------- 1 | # spu-mark-ii README 2 | 3 | This is the README for your extension "spu-mark-ii". After writing up a brief description, we recommend including the following sections. 4 | 5 | ## Features 6 | 7 | Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file. 8 | 9 | For example if there is an image subfolder under your extension project workspace: 10 | 11 | \!\[feature X\]\(images/feature-x.png\) 12 | 13 | > Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow. 14 | 15 | ## Requirements 16 | 17 | If you have any requirements or dependencies, add a section describing those and how to install and configure them. 18 | 19 | ## Extension Settings 20 | 21 | Include if your extension adds any VS Code settings through the `contributes.configuration` extension point. 22 | 23 | For example: 24 | 25 | This extension contributes the following settings: 26 | 27 | * `myExtension.enable`: enable/disable this extension 28 | * `myExtension.thing`: set to `blah` to do something 29 | 30 | ## Known Issues 31 | 32 | Calling out known issues can help limit users opening duplicate issues against your extension. 33 | 34 | ## Release Notes 35 | 36 | Users appreciate release notes as you update your extension. 37 | 38 | ### 1.0.0 39 | 40 | Initial release of ... 41 | 42 | ### 1.0.1 43 | 44 | Fixed issue #. 45 | 46 | ### 1.1.0 47 | 48 | Added features X, Y, and Z. 49 | 50 | ----------------------------------------------------------------------------------------------------------- 51 | 52 | ## Working with Markdown 53 | 54 | **Note:** You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts: 55 | 56 | * Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux) 57 | * Toggle preview (`Shift+CMD+V` on macOS or `Shift+Ctrl+V` on Windows and Linux) 58 | * Press `Ctrl+Space` (Windows, Linux) or `Cmd+Space` (macOS) to see a list of Markdown snippets 59 | 60 | ### For more information 61 | 62 | * [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown) 63 | * [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/) 64 | 65 | **Enjoy!** 66 | -------------------------------------------------------------------------------- /tools/vscode-ext/language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": ";" 4 | }, 5 | // symbols used as brackets 6 | "brackets": [ 7 | [ 8 | "[", 9 | "]" 10 | ], 11 | [ 12 | "(", 13 | ")" 14 | ] 15 | ], 16 | // symbols that are auto closed when typing 17 | "autoClosingPairs": [ 18 | [ 19 | "[", 20 | "]" 21 | ], 22 | [ 23 | "(", 24 | ")" 25 | ], 26 | [ 27 | "\"", 28 | "\"" 29 | ], 30 | [ 31 | "'", 32 | "'" 33 | ] 34 | ], 35 | // symbols that can be used to surround a selection 36 | "surroundingPairs": [ 37 | [ 38 | "[", 39 | "]" 40 | ], 41 | [ 42 | "(", 43 | ")" 44 | ], 45 | [ 46 | "\"", 47 | "\"" 48 | ], 49 | [ 50 | "'", 51 | "'" 52 | ] 53 | ] 54 | } -------------------------------------------------------------------------------- /tools/vscode-ext/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spu-mark-ii", 3 | "displayName": "SPU Mark II", 4 | "description": "Provides syntax highlighting and utilities to work with the SPU Mark II.", 5 | "version": "0.0.1", 6 | "engines": { 7 | "vscode": "^1.58.0" 8 | }, 9 | "categories": [ 10 | "Programming Languages" 11 | ], 12 | "activationEvents": [ 13 | "onCommand:spumk2.helloWorld", 14 | "onLanguage:spumk2.asm" 15 | ], 16 | "main": "src/extension.js", 17 | "contributes": { 18 | "languages": [{ 19 | "id": "spumk2.asm", 20 | "aliases": [ 21 | "SPU Mark II Assembler", 22 | "asm" 23 | ], 24 | "extensions": [ 25 | ".asm", 26 | ".inc" 27 | ], 28 | "configuration": "./language-configuration.json" 29 | }], 30 | "grammars": [{ 31 | "language": "spumk2.asm", 32 | "scopeName": "source.asm", 33 | "path": "./syntaxes/asm.tmLanguage.json" 34 | }], 35 | "commands": [{ 36 | "command": "spumk2.helloWorld", 37 | "title": "Hello World" 38 | }] 39 | }, 40 | "scripts": { 41 | "lint": "eslint .", 42 | "pretest": "npm run lint", 43 | "test": "node ./test/runTest.js" 44 | }, 45 | "devDependencies": { 46 | "@types/glob": "^7.1.3", 47 | "@types/mocha": "^8.2.2", 48 | "@types/node": "14.x", 49 | "@types/vscode": "^1.58.0", 50 | "esbuild": "^0.12.15", 51 | "eslint": "^7.27.0", 52 | "glob": "^7.1.7", 53 | "mocha": "^10.1.0", 54 | "typescript": "^4.3.2", 55 | "vscode-test": "^1.5.2" 56 | } 57 | } -------------------------------------------------------------------------------- /tools/vscode-ext/render-mnemonics.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | const mnemonics = @import("../assembler/mnemonics.zig"); 4 | 5 | pub fn main() !void { 6 | const stdout = std.io.getStdOut().writer(); 7 | 8 | var items = mnemonics.mnemonics; 9 | 10 | std.sort.sort(mnemonics.Mnemonic, &items, {}, lt); 11 | 12 | try stdout.writeAll("module.exports = [\n"); 13 | for (items) |m| { 14 | try stdout.print(" {{ name: '{s}', desc: \"{}\", argc: {}, input0: '{s}', input1: '{s}', output: '{s}', command: '{s}', flags: {}, condition: '{s}' }},\n", .{ 15 | m.name, 16 | std.zig.fmtEscapes(m.info), 17 | m.argc, 18 | @tagName(m.instruction.input0), 19 | @tagName(m.instruction.input1), 20 | @tagName(m.instruction.output), 21 | @tagName(m.instruction.command), 22 | m.instruction.modify_flags, 23 | @tagName(m.instruction.condition), 24 | }); 25 | } 26 | try stdout.writeAll("];\n"); 27 | } 28 | 29 | fn lt(_: void, a: mnemonics.Mnemonic, b: mnemonics.Mnemonic) bool { 30 | if (std.mem.lessThan(u8, a.name, b.name)) 31 | return true; 32 | if (a.argc < b.argc) 33 | return true; 34 | return false; 35 | } 36 | -------------------------------------------------------------------------------- /tools/vscode-ext/syntaxes/asm.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", 3 | "name": "SPU Mark II Assembler", 4 | "patterns": [{ 5 | "include": "#assembler" 6 | }, 7 | { 8 | "include": "#strings" 9 | }, 10 | { 11 | "include": "#comments" 12 | }, 13 | { 14 | "include": "#numbers" 15 | } 16 | ], 17 | "repository": { 18 | "comments": { 19 | "patterns": [{ 20 | 21 | "name": "comment.line", 22 | "match": ";.*" 23 | }] 24 | 25 | }, 26 | "assembler": { 27 | "patterns": [{ 28 | "name": "variable.name.asm", 29 | "match": "^(\\w[\\w\\.]+):" 30 | }, 31 | { 32 | "name": "storage.asm", 33 | "match": "^\\.(\\w+)\\b" 34 | }, 35 | { 36 | "name": "keyword.asm", 37 | "match": "\\[\\w+\\:\\w+\\]" 38 | }, 39 | { 40 | "match": "^\\s*(\\[\\w+\\:\\w+\\]\\s*)*(\\w+)", 41 | "captures": { 42 | "1": { 43 | "name": "keyword.asm" 44 | }, 45 | "2": { 46 | "name": "keyword.control.asm" 47 | } 48 | } 49 | }, 50 | { 51 | "name": "string.quoted.single.asm", 52 | "match": "'(\\\\.|[^\\\\])'" 53 | } 54 | ] 55 | }, 56 | "strings": { 57 | "name": "string.quoted.double.asm", 58 | "begin": "\"", 59 | "end": "\"", 60 | "patterns": [{ 61 | "name": "constant.character.escape.asm", 62 | "match": "\\\\." 63 | }] 64 | }, 65 | "numbers": { 66 | "patterns": [{ 67 | "name": "constant.numeric.hex.asm", 68 | "match": "\\b0x[A-Za-z0-9]+" 69 | }, 70 | { 71 | "name": "constant.numeric.dec.asm", 72 | "match": "\\b[0-9]+" 73 | } 74 | ] 75 | } 76 | }, 77 | "scopeName": "source.asm" 78 | } -------------------------------------------------------------------------------- /tools/vscode-ext/update-mnemonics-js.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | zig run render-mnemonics.zig \ 3 | --main-pkg-path .. \ 4 | --pkg-begin spu-mk2 ../common/spu-mk2.zig --pkg-end \ 5 | > src/mnemonics.js 6 | -------------------------------------------------------------------------------- /tools/vscode-ext/vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension. 7 | * `syntaxes/asm.tmLanguage.json` - this is the Text mate grammar file that is used for tokenization. 8 | * `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets. 9 | 10 | ## Get up and running straight away 11 | 12 | * Make sure the language configuration settings in `language-configuration.json` are accurate. 13 | * Press `F5` to open a new window with your extension loaded. 14 | * Create a new file with a file name suffix matching your language. 15 | * Verify that syntax highlighting works and that the language configuration settings are working. 16 | 17 | ## Make changes 18 | 19 | * You can relaunch the extension from the debug toolbar after making changes to the files listed above. 20 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 21 | 22 | ## Add more language features 23 | 24 | * To add features such as intellisense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs 25 | 26 | ## Install your extension 27 | 28 | * To start using your extension with Visual Studio Code copy it into the `/.vscode/extensions` folder and restart Code. 29 | * To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension. 30 | -------------------------------------------------------------------------------- /website/zip.py: -------------------------------------------------------------------------------- 1 | import zipfile as zf, sys 2 | 3 | z = zf.ZipFile(sys.argv[1], "a") 4 | z.write(sys.argv[2], sys.argv[3]) 5 | z.close() 6 | # myfile.zip source/dir/file.txt dir/in/zip/file.txt 7 | # This will open myfile.zip and add source/dir/file.txt from the file system as dir/in/zip/file.txt in the zip file. 8 | 9 | --------------------------------------------------------------------------------