Skip to content

Commit

Permalink
Added Minimal 64 Home Computer support (#27)
Browse files Browse the repository at this point in the history
* first version of minimal 64 configuration

* fixed bug when instruction configured for 0 operands

* allow predefined contants fot start with _

* added minimal 64 os constants

* corrected os function calling convention

* finalized minimal 64 release

* documentation update

* added prime numbers example

* added random maze example

* bumped version

* typos
  • Loading branch information
michaelkamprath committed Jul 12, 2023
1 parent 4da0062 commit add2003
Show file tree
Hide file tree
Showing 19 changed files with 2,342 additions and 23 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@ Changes that are planned but not implemented yet:
* unknown labels

## [Unreleased]

## [0.4.1]
* added `.asciiz` as an equivalent data directive to `.cstr`
* Updated Github workflow to add Python 3.11 to the test matrix.
* Remove usage of deprecated aspects of Python `importlib` library so that the code will work with Python 3.11 without deprecation warnings.
* Fixed [reported bug](https://github.com/michaelkamprath/bespokeasm/issues/25) where indirect indexed register operands were not parsed properly.
* Fixed bug that did not sanely handle an instructions operand configuration indicating 0 operands
* Allow predefined constants to labels starting with `_`, which also indicates file scope for code defined labels
* Added MThe Minimal 64 Home Computer example

## [0.4.0]
* Added ability to create preprocessor macros/symbols with `#define` directive. Thes macros can then be used in code. Also added the ability to define preprocessor symbols on the command line and in the instruction set configuration file.
Expand Down Expand Up @@ -137,7 +142,8 @@ First tracked released
* Enabled the `reverse_argument_order` instruction option be applied to a specific operand configuration. This slightly changed the configuration file format.
* Added ability for instructions with operands to have a single "empty operand" variant, e.g., `pop`

[Unreleased]: https://github.com/michaelkamprath/bespokeasm/compare/v0.4.0...HEAD
[Unreleased]: https://github.com/michaelkamprath/bespokeasm/compare/v0.4.1...HEAD
[0.4.1]: https://github.com/michaelkamprath/bespokeasm/compare/v0.4.0...v0.4.1
[0.4.0]: https://github.com/michaelkamprath/bespokeasm/compare/v0.3.3...v0.4.0
[0.3.3]: https://github.com/michaelkamprath/bespokeasm/compare/v0.3.2...v0.3.3
[0.3.2]: https://github.com/michaelkamprath/bespokeasm/compare/v0.3.1...v0.3.2
Expand Down
66 changes: 66 additions & 0 deletions examples/slu4-minimal-64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Minimal 64 Home Computer
*Current as of v1.2.x of the Minimal 64 Home Computer*

The Minimal 64 Home Computer (Minimal 64) is TTL CPU designed by Carsten Herting (slu4). Carsten has made his [Minimal 64 design open and available to others](https://github.com/slu4coder/The-Minimal-64-Home-Computer/) to build. The Minimal 64 is is well documented, and even has [a YouTube video series](https://www.youtube.com/watch?v=3zGTsi4AYLw&list=PLYlQj5cfIcBVrKpKJ-Sj68nkw6IRb9KOp) dedicated to it.

As part of his effort to demonstrate the "minimal effort" needed to make a working computer, Carsten has already implemented a simple yet solid assembler for the Minimal 64 Home Computer. So the question might be asked, "Why port the Minimal 64 to BespokeASM?" Simply put, to have a more robust assembler for the Minimal 64. For example, the instruction set for the Minimal 64 is simple (no overly complex instructions), and so actions like pushing a value on the stack takes at least two instructions to complete. In scenarios like this, BespokeASM's instruction macros can simplify the code needed to accomplish common tasks.

So the goal of this port to **BespokeASM** is to first support the basic instruction set of the Minimal 64 in its original form, but then build on that with richer features such as instruction macros to make assembly coding for the Minimal CPU more productive.

## Minimal 64 Assembly
The **BespokeASM** instruction set configration file `slu4-minimal-64.yaml` is available in this directory. Assuming that **BespookeASM** is [properly installed in the current python environment](https://github.com/michaelkamprath/bespokeasm/wiki/Installation-and-Usage#installation), to compile Minimal 64 assembly into a Intel Hex representation that the Minimal 64 OS's `receive` instruction can take, use the following command:

```sh
bespokeasm compile -n -p -t intel_hex -c /path/to/slu4-minimal-64.yaml /path/to/my-code.min64
```

The arguments to the command above are:

* `-n` - Indicates that no binary image should be generated.
* `-p` - indicates that a textual representation of the assembled code should be emitted.
* `-t intel_hex` - Specifies the format of the textual rerpesentation of the compiled code, in this case being Intel Hex. If you ommit this option, the default textual representation of an human-readable listing will be used.
* `-c /path/to/slu4-minimal-64.yaml` - The file path to the **BespokeASM** instruction set configuration for the Minimal 64.
* `/path/to/my-code.min64` - The file path to the Minimal 64 assembly code to be compiled. Here by convention the assembly code has a file extension of `.min64`. While **BespokeASM** can work with any file extension for the code, the convention is used so that code editors know what file type they are editing and thus are able to support syntax highlighting specific to the Minimal 64 assembly syntax. See **BespokeASM**'s documentation on syntax highlighting support for more information.

### Instruction Set
Carsten Herting thoroughly documents [the instruction set for the Minimal 64 in his user guide](https://docs.google.com/document/d/1e4hL9Z7BLIoUlErWgJOngnSMYLXjfnsZB9BtlwhTC6U/edit?usp=sharing). All of the documented instructions in their original syntax are implemented in in this **BespokeASM** port. However, **BespokeASM** will be case insensitive when matching instruction mnemonics.

### Instruction Macros
The following instruction macros have been added in the ISA confutation file for the Minimal 64. All macros that interact with the stack maintain byte order according to Min64 OS calling convention, which pushes the LSB of the value first despite the system otherwise using little endian byte ordering. Not that this means multibyte values on the stack cannot be used directly art their stack memory address and must be "pulled" from the stack to another memory location where they can be represented in little endian byte ordering.

| Macros Instruction | Operand 1 | Operand 2 | Description |
|:-:|:-:|:-:|:--|
| `spinit` | - | - | Init the stack popint to a value of `0xFFFE`. |
| `phsi` | 1 byte | - | Pushes a 1 byte immediate value onto the stack. |
| `phs2i` | 2 bytes | - | Pushes a 2 byte immediate value onto the stack. |
| `phs4i` | 4 bytes | - | Pushes a 4 byte immediate value onto the stack. |
| `phsa` | absolute address | - | Push onto stack 1 byte found at absolute address |
| `phs2a` | absolute address | - | Push onto stack 2 bytes found at absolute address |
| `phs4a` | absolute address | - | Push onto stack 4 bytes found at absolute address |
| `phss` | stack offset | - | Push onto stack 1 byte value currently found at indicated stack offset |
| `phs2s` | stack offset | - | Push onto stack 2 byte value currently found at indicated stack offset |
| `phs4s` | stack offset | - | Push onto stack 4 byte value currently found at indicated stack offset |
| `pls2` | - | - | Pull 2 bytes from stack. Last byte pulled will be in A register. |
| `pls4` | - | - | Pull 4 bytes from stack. Last byte pulled will be in A register. |
| `cpy2as` | absolute address | stack offset | Copy 2 bytes of data sourced from indicated stack offset to memory starting at indicated absolute address. Convert from stack big endian ordering to RAM little endian ordering. |
| `cpy2sa` | stack offset | absolute address | Copy 2 bytes of data sourced from absolute address to stack at indicated offset. Convert from RAM little endian to stack big endian ordering ordering. |
| `cpy4as` | absolute address | stack offset | Copy 4 bytes of data sourced from indicated stack offset to memory starting at indicated absolute address. Convert from stack big endian ordering to RAM little endian ordering. |
| `cpy4sa` | stack offset | absolute address | Copy 4 bytes of data sourced from absolute address to stack at indicated offset. Convert from RAM little endian to stack big endian ordering ordering. |
| `cpy4ai` | absolute address | immediate | Copy 4 bytes of immediate value to memory starting at indicated absolute address. Preserves endian ordering. |
| `cpy4si` | stack offset | immediate | Copy 4 bytes of immediate value to stack at indicated offset. Convert from RAM little endian to stack big endian ordering ordering. |
| `cpy4ss` | stack offset | stack offset | Copy 4 bytes of data from stack starting at indicated offset (2nd operand) to another location in stack starting at indicated offset (1rst operand). Byte ordering is preserved. |

The operand descriptions use the definitions provided by documentation for Minimal 64. You should assume the accumulator (register `A`) is not preserved across any of these macros.

### Assembly Syntax
**BespokeASM**'s syntax is close to the syntax that Carsten used for the Minimal CPU's assembly language. However, there are some differences:

* **BespokeASM** used a different syntax for some directives, notably the `.org` directive, which has the `#org` syntax in the Minimal CPU assembly. **BespokeASM** also has [a richer set of directives available](https://github.com/michaelkamprath/bespokeasm/wiki/Assembly-Language-Syntax#directives).
* The Minimal CPU's assembler has no data type directives. Instead, the assembler directly converts numeric values and strings to byte code exactly where it sits in the code. In **BespokeASM** one must declare a data type using [a data directive](https://github.com/michaelkamprath/bespokeasm/wiki/Assembly-Language-Syntax#data) when defining data in the byte code.
* The Minimal CPU assembler emits byte code in the order it was in the original assembly code, while **BespokeASM** emits byte code in address order. For the most part, these two orderings can be pretty much the same, however, differences will show up if multiple `.org` directives are use or multiple additional source files are included.
* The Minimal CPU uses a `<` and `>` to do byte slicing of constant values, with `<` meaning least significant byte and `>` meaning most significant byte (and it assumes a 2 byte value). **BespokeASM** using `BYTE0(..)` and `BYTE1(..)` [to accomplish the same goals](https://github.com/michaelkamprath/bespokeasm/wiki/Assembly-Language-Syntax#numeric-expressions) (respectively).

There are several other features that **BespokeASM** provides over the Minimal 64 assembly syntax, such as richer math expressions for constant values and [several preprocessor directives](https://github.com/michaelkamprath/bespokeasm/wiki/Assembly-Language-Syntax#preprocessor), but the differences listed above are the ones that require code written for the Minimal 64 assembler to be altered to be assembled with **BespokeASM**.

### Predefined Compiler Constants
The Minimal 64 operating system provided call vectors for a suite of API functions and system subroutines that are made available to user written programs. These API function labels are documented in the "API Functions" section of the Minimal 64 user guide. All documented API functions are implemented as predefined constants in this **BepsokeASM** port.
64 changes: 64 additions & 0 deletions examples/slu4-minimal-64/bubbles.min64
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
; ---------------------------------------
; VGA demo drawing 16 x 16 bubble sprites
; by C. Herting (slu4) 2022
;
; ported to BespokeASM syntax by Michael Kamprath
; ---------------------------------------
#require "slu4-min64-asm >= 1.2.0"
.org 0x8000

start: LDI 0xfe STA 0xffff
JPS _Clear ; clear VGA

rloop: JPS _Random ANI 1 STA table+0
redox: JPS _Random CPI 192 BCS redox
LSL ORB table+0 LDI 0 ROL STA table+1
redoy: JPS _Random CPI 224 BCS redoy
STA table+2

drawit: LDA table+0 PHS
LDA table+1 PHS
LDA table+2 PHS
JPS DrawSprite PLS PLS PLS

JPA rloop

ptr: .2byte 0xffff

; ------------------------------------------------
; Draws a 16x16 pixel sprite at the given position
; push: x_lsb, x_msb, y
; pull: #, #, #
; modifies: X
; ------------------------------------------------
DrawSprite: LDS 3 LL6 STA addr+0 ; use ypos
LDS 3 RL7 ANI 63 ADI 0xc3 STA addr+1
LDS 4 DEC LDS 5 ; add xpos
RL6 ANI 63 ADI 12 ORB addr+0 ; preprare target address
LDS 5 ANI 7 STA shift ; calc bit pos
LDI LSB(data) STA dptr+0 LDI BYTE1(data) STA dptr+1 ; data is hard-coded
lineloop: LDR dptr STA buffer+0 INW dptr
LDR dptr STA buffer+1 CLB buffer+2
LXA shift DEX BCC shiftdone ; shift that buffer to pixel position
shiftloop: LLW buffer+0 RLB buffer+2 DEX BCS shiftloop
shiftdone: NEB mask BEQ clearit
LDA buffer+0 ORR addr STR addr INW addr ; store line buffer to VRAM addr
LDA buffer+1 ORR addr STR addr INW addr
LDA buffer+2 ORR addr STR addr
JPA common
clearit: LDA buffer+0 NOT ANR addr STR addr INW addr ; store line buffer to VRAM addr
LDA buffer+1 NOT ANR addr STR addr INW addr
LDA buffer+2 NOT ANR addr STR addr
common: LDI 62 ADW addr ; ... and move to the next line
INW dptr LDA dptr+0 CPI LSB(data+32) BNE lineloop ; haben wir alle sprite daten verarbeitet?
RTS

shift: .byte 0xff
dptr: .2byte 0xffff
addr: .2byte 0xffff
mask: .byte 0x01
data: .byte 0xe0,0x07,0x98,0x1a,0x04,0x34,0x02,0x68,0x62,0x50,0x11,0xa0,0x09,0xd0,0x09,0xa0
.byte 0x01,0xd0,0x03,0xa8,0x05,0xd4,0x0a,0x6a,0x56,0x55,0xac,0x2a,0x58,0x1d,0xe0,0x07
buffer: .byte 0xff, 0xff, 0xff

table: ; position data for sprite entities
22 changes: 22 additions & 0 deletions examples/slu4-minimal-64/hello-world.min64
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
; Hello World
; for the Minimal 64 Home Computer
;
; This simple program simply displays a string to the screen
; and then returns to the OS prompt.
;
#require "slu4-min64-asm >= 1.2.0"
.org 0x8000
init:
; init the stack vector
spinit

start:
phs2i message_str
jps _Print
pls2

end:
jpa _Prompt

message_str:
.cstr "Hello World!\n"
Loading

0 comments on commit add2003

Please sign in to comment.