Skip to content

Commit

Permalink
added Min64x4 prime numbers example
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelkamprath committed Apr 26, 2024
1 parent 2eb5702 commit 2c9304a
Show file tree
Hide file tree
Showing 5 changed files with 260 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Changes that are planned but not implemented yet:
* Disallowed operands
* missing `:` after labels
* unknown labels
* Add named label scopes. This would allow a label to be defined in a specific scope that can be shared across files.
* Create a "align if needed" preprocessor directive paid that generates an `.align` directive is the bytecode in between the paid isn't naturally on the same page and can fit on the same page if aligned. An error would be benerated if the block of code can't fit on the same page regardless of alignment.

## [Unreleased]
* Added support for The Minimal 64x4 Home Computer with an example and updated assembler functionality to support it.
Expand Down
99 changes: 99 additions & 0 deletions examples/slu4-minimal-64x4/slu4-minimal-64x4.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2700,6 +2700,23 @@ macros:
- "phs"
- "ldi BYTE3(@ARG(0))"
- "phs"
phs4a:
# push 4 bytes of an absolute address to the stack
# stack is arranged as big-endian, address is little-endian
- operands:
count: 1
operand_sets:
list:
- absolute_address
instructions:
- "ldb @ARG(0)+0"
- "phs"
- "ldb @ARG(0)+1"
- "phs"
- "ldb @ARG(0)+2"
- "phs"
- "ldb @ARG(0)+3"
- "phs"
phsptr:
# push an immediate absolute address to the stack per MinOS calling convention
- operands:
Expand All @@ -2724,6 +2741,39 @@ macros:
- "phs"
- "lds @ARG(0)+0+1"
- "phs"
phs4s:
# push 4 bytes at (current) stack offset to the stack
- operands:
count: 1
operand_sets:
list:
- offset
instructions:
- "lds @ARG(0)+3+0"
- "phs"
- "lds @ARG(0)+2+1"
- "phs"
- "lds @ARG(0)+1+2"
- "phs"
- "lds @ARG(0)+0+3"
- "phs"
phsq:
# push a zero page long to the stack
# stack is arranged as big-endian, long in zero-page is little-endian
- operands:
count: 1
operand_sets:
list:
- zero_page
instructions:
- "ldz @ARG(0)+0"
- "phs"
- "ldz @ARG(0)+1"
- "phs"
- "ldz @ARG(0)+2"
- "phs"
- "ldz @ARG(0)+3"
- "phs"
pls2:
# pull 2 bytes from the stack
- operands:
Expand Down Expand Up @@ -2803,6 +2853,42 @@ macros:
- "sts @ARG(1)+2"
- "ldz @ARG(0)+0"
- "sts @ARG(1)+3"
mls4:
# move a long (4 bytes) from abs address to stack starting at passed offset
# stack is arranged as big-endian, long at abs address is little-endian
- operands:
count: 2
operand_sets:
list:
- absolute_address
- offset
instructions:
- "ldb @ARG(0)+3"
- "sts @ARG(1)+0"
- "ldb @ARG(0)+2"
- "sts @ARG(1)+1"
- "ldb @ARG(0)+1"
- "sts @ARG(1)+2"
- "ldb @ARG(0)+0"
- "sts @ARG(1)+3"
ms4l:
# move a long (4 bytes) from stack starting at passed offset to abs address
# stack is arranged as big-endian, long at abs address is little-endian
- operands:
count: 2
operand_sets:
list:
- offset
- absolute_address
instructions:
- "lds @ARG(0)+3"
- "stb @ARG(1)+0"
- "lds @ARG(0)+2"
- "stb @ARG(1)+1"
- "lds @ARG(0)+1"
- "stb @ARG(1)+2"
- "lds @ARG(0)+0"
- "stb @ARG(1)+3"
aqq:
# add two zero-page longs. result in second zero page operand
- operands:
Expand Down Expand Up @@ -2844,3 +2930,16 @@ macros:
instructions:
- "mvv @ARG(0)+0,@ARG(1)+0"
- "mvv @ARG(0)+2,@ARG(1)+2"
mll:
# move long from abs address to abs address
- operands:
count: 2
operand_sets:
list:
- absolute_address
- absolute_address
instructions:
- "mbb @ARG(0)+0,@ARG(1)+0"
- "mbb @ARG(0)+1,@ARG(1)+1"
- "mbb @ARG(0)+2,@ARG(1)+2"
- "mbb @ARG(0)+3,@ARG(1)+3"
9 changes: 6 additions & 3 deletions examples/slu4-minimal-64x4/software/mathlib32.min64x4
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
; Math Library 32-bit
; This library provides 32-bit math functions for unsigned and signed integers.
;
#require "slu4-min64x4-asm >= 1.1.0"
; Zero Page Usage
.memzone ZERO_PAGE_APPS
Expand Down Expand Up @@ -118,9 +121,9 @@ _multiply:
; take twos complement of 8-byte results
noq _working_mem8+0
noq _working_mem8+4
inw _working_mem8+0 fcc .copy_results ; if only INQ set the flags :-(
inw _working_mem8+2 fcc .copy_results
inw _working_mem8+4 fcc .copy_results
inw _working_mem8+0 bcc .copy_results ; if only INQ set the flags :-(
inw _working_mem8+2 bcc .copy_results
inw _working_mem8+4 bcc .copy_results
inw _working_mem8+6
.copy_results:
; the entire working memory is the 64-bit results
Expand Down
129 changes: 129 additions & 0 deletions examples/slu4-minimal-64x4/software/primes.min64x4
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
; Prime Number Calculator
; This program calculates prime numbers using the algorithm documented here:
; https://en.wikipedia.org/wiki/Primality_test
;
#require "slu4-min64x4-asm >= 1.1.0"

.memzone ZERO_PAGE_APPS
#mute
_n_value: .zero 4


#unmute

.org 0 "USER_APPS"
start:
; init N-value to 1
clq _n_value
miz 1,_n_value+0
.n_loop:
phsi 0
phsq _n_value
jps is_prime32
pls4
pls cpi 1 beq .print_is_prime
jpa .increment_n
.print_is_prime:
phsq _n_value jps print_uint32 pls4
phsptr is_prime_str jps _PrintPtr pls2
; jps _WaitInput
.increment_n:
inq _n_value
jpa .n_loop

is_prime_str: .cstr " is prime!\n"
is_not_prime_str: .cstr " is not prime\n"

; is_prime32
; determines wither the passed uint32 is a prime
;
; Arguments
; sp+3 : the value to determine if prime (4 bytes)
; sp+7 : a place holder for return boolean
;
; returns
; sp+7 : 0 or 1 depending on whether N is prime
is_prime32:
; first check for 2 or 3
lds 3 cpi 0 bne .modulo_two ; check top byte of N for 0
lds 4 cpi 0 bne .modulo_two ; check top byte of N for 0
lds 5 cpi 0 bne .modulo_two ; check top byte of N for 0
lds 6 cpi 3 beq .is_prime ; check N==3
cpi 2 beq .is_prime ; check N==2
cpi 1 beq .is_not_prime ; check N==1
cpi 0 beq .is_not_prime ; check N==0
.modulo_two:
lds 6 lr1 bcc .is_not_prime ; see if N's least signficant bit is even or odd
.modulo_three:
phs4i 3 ; place divisor on stack
phs4s (3+4) ; place dividend on stack (from stack)
jps divide32
pls4
; check if remainder is 0
phs4i 0 jps compare_uint32ss pls4
pls4
beq .is_not_prime
.loop_init:
; set i-value (long) to 5
cll .current_i_val ; clear all of I
mib 5, .current_i_val+0 ; copy 5 in to LSB
.loop:
phs4a .current_i_val
phs4a .current_i_val
jps multiply_uint32
; high 4 bytes of result should be 0 since we are only doing 32 bit N
lds 1 cpi 0 bne .iteration_loop_done
lds 2 cpi 0 bne .iteration_loop_done
lds 3 cpi 0 bne .iteration_loop_done
lds 4 cpi 0 bne .iteration_loop_done
pls4
ms4l 1,.isquared
pls4
phs4a .isquared phs4s 3+4 jps compare_uint32ss pls4 pls4
; if I*I > N, we are done
bgt .loop_done_is_prime
.n_gte_i_squared:
; now check various modulos.
; check N % I == 0
phs4a .current_i_val ; I
phs4s (3+4) ; N
jps divide32
pls4 ; quotient
phs4i 0
jps compare_uint32ss
pls4
pls4
beq .loop_done_is_not_prime
; check N % (I+2) == 0
mll .current_i_val,.temp_val
ail 2, .temp_val
phs4a .temp_val
phs4s (3+4)
jps divide32
pls4 ; quotient
phs4i 0
jps compare_uint32ss
pls4 ; zero
pls4 ; remainder
beq .loop_done_is_not_prime
; add 6 to I and loop
ail 6, .current_i_val
jpa .loop
.iteration_loop_done:
; get rid of I*I stack
pls4
pls4
.loop_done_is_prime:
.is_prime:
ldi 1 sts 7
rts
.loop_done_is_not_prime:
.is_not_prime:
ldi 0 sts 7
rts
.current_i_val: .4byte 0
.temp_val: .4byte 0
.isquared: .4byte 0

#include "mathlib32.min64x4"
#include "stringlib.min64x4"
25 changes: 24 additions & 1 deletion examples/slu4-minimal-64x4/software/stringlib.min64x4
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
; String Library
; various routines for manipulating strings
;
#require "slu4-min64x4-asm >= 1.1.0"
; Zero Page Usage
.memzone ZERO_PAGE_APPS
Expand All @@ -23,6 +26,7 @@ _working_mem5: .zero 5
;
; TODO - check to see if there is enough rroom in teh stack to do this operation.
;
.align
cstr_reverse:
lds 3+0 stz _tmp_Ptr1+1
lds 3+1 stz _tmp_Ptr1+0
Expand Down Expand Up @@ -118,7 +122,6 @@ uint32_to_decimal_cstr:
inv _tmp_Ptr1
jpa .outer_loop
.last_digit:
jps _Print "last digit!\n"
; get character of remainder
ldz _working_mem5+0 adi $30
; store character in buffer
Expand Down Expand Up @@ -158,6 +161,26 @@ uint32_to_decimal_cstr:
jpa _Prompt


; print_uint32
; prints the passed unsigned 4 byte integer in decimal format
;
; Arguments:
; sp + 3 : 32-bit value to print (4 bytes) big endian
;
BUFFER_SIZE = 32
print_uint32:
phsi BUFFER_SIZE
phsptr .buffer
phs4s (3+3)
jps uint32_to_decimal_cstr
pls4
pls2
pls
phs2i .buffer jps _PrintPtr pls2
rts
.buffer: .zero BUFFER_SIZE


_print_working_memory:
jps _Print "working mem = "
ldz _working_mem5+4 jas _PrintHex
Expand Down

0 comments on commit 2c9304a

Please sign in to comment.