diff --git a/docs/README.md b/docs/README.md index 174cee13..b43cce87 100644 --- a/docs/README.md +++ b/docs/README.md @@ -39,7 +39,13 @@ * [`stdlib` module](stdlib/stdlib.md) -* [Other cross-platform modules](stdlib/other.md) +* [`string` module](stdlib/string.md) + +* [Modules for reading input devices](stdlib/input.md) + +* [Other cross-platform modules (`err`, `stdio`, `random`)](stdlib/other.md) + +* [Definitions available on only some platforms](stdlib/frequent.md) * [C64-only modules](stdlib/c64.md) diff --git a/docs/index.md b/docs/index.md index 37e42dea..b43cce87 100644 --- a/docs/index.md +++ b/docs/index.md @@ -43,7 +43,7 @@ * [Modules for reading input devices](stdlib/input.md) -* [Other cross-platform modules (`err`, `stdio`)](stdlib/other.md) +* [Other cross-platform modules (`err`, `stdio`, `random`)](stdlib/other.md) * [Definitions available on only some platforms](stdlib/frequent.md) diff --git a/docs/stdlib/other.md b/docs/stdlib/other.md index 2186335a..91803e30 100644 --- a/docs/stdlib/other.md +++ b/docs/stdlib/other.md @@ -14,6 +14,10 @@ Prints a string of length `len` located at address `str`. Prints a null-terminated string located at address `str`. If the string is longer than 255 bytes, then the behaviour is undefined (might even crash). +#### `void ensure_mixedcase()` + +On targets that have separate all-caps and mixed-case modes (like most Commodore machines), switches to the mixed-case mode. + ## err @@ -24,3 +28,29 @@ Standard error codes. All codes other than `err_ok` suggest that the last operat #### `error_number errno` The result of the last operation. + + +## random + +A simple and reasonably fast random number generator. Not suitable for cryptographic or simulation uses. + +#### `word rand_seed` + +Random number generator state. + +#### `byte rand()` + +Get a random byte (0–255) and update the state of the generator. + +#### `void init_rand_seed()` + +Initializes the random number generator state. +This may take a long time, even several frames, depending on the target. + +Current implementation: + +* On C64, spends two frames reading noise data from the SID chip. + +* On Z80, reads the refresh register. + +* On all other targets, sets the seed to 1. diff --git a/examples/crossplatform/fire.mfk b/examples/crossplatform/fire.mfk index 617b02a4..b80e4a62 100644 --- a/examples/crossplatform/fire.mfk +++ b/examples/crossplatform/fire.mfk @@ -1,4 +1,6 @@ +import random + array reverse_palette[256] align(256) #if CBM @@ -119,53 +121,3 @@ void fire() { p += COLUMN_COUNT } } - -word rand_seed - -#if CPU_6502 -asm byte rand() { - ldx #8 - lda rand_seed+0 -__rand_loop: - asl - rol rand_seed+1 - bcc __no_eor - eor #$2D -__no_eor: - dex - bne __rand_loop - sta rand_seed+0 - ? rts -} -#elseif CPU_Z80 -inline asm byte rand() { - ld b,8 - ld hl,(rand_seed) -__rand_loop: - add hl,hl - jp nc, __no_eor - ld a,l - xor $2D - ld l,a -__no_eor: - djnz __rand_loop - ld (rand_seed),hl - ? ret -} -#endif - -#if CBM_64 -inline void init_rand_seed() { - poke($D40E, $ff) - poke($D40F, $ff) - poke($D412, $80) - while vic_raster != $70 {} - rand_seed.hi = peek($D41B) - while vic_raster != $40 {} - rand_seed.lo = peek($D41B) -} -#else -inline void init_rand_seed() { - rand_seed = 1 -} -#endif \ No newline at end of file diff --git a/examples/crossplatform/hello_world.mfk b/examples/crossplatform/hello_world.mfk index 9e8c610f..c4deec52 100644 --- a/examples/crossplatform/hello_world.mfk +++ b/examples/crossplatform/hello_world.mfk @@ -3,9 +3,10 @@ import stdio -array hello_world = "hello world" +array hello_world = "Hello world" void main() { + ensure_mixedcase() #if CBM_64 || CBM_264 set_bg_color(green) @@ -16,7 +17,7 @@ void main() { putstr(hello_world, hello_world.length) new_line() - putstrz("hello world again"z) + putstrz("Hello world again"z) #if not(CPM) while(true){} diff --git a/include/random.mfk b/include/random.mfk new file mode 100644 index 00000000..e305203c --- /dev/null +++ b/include/random.mfk @@ -0,0 +1,10 @@ + +word rand_seed + +#if ARCH_6502 +import random_6502 +#elseif ARCH_I80 +import random_i80 +#else +#warn Unsupported architecture +#endif diff --git a/include/random_6502.mfk b/include/random_6502.mfk new file mode 100644 index 00000000..e2d77034 --- /dev/null +++ b/include/random_6502.mfk @@ -0,0 +1,43 @@ + +import random + +#if not(ARCH_6502) +#warn random_6502 module should be only used on 6502-compatible targets +#endif + +asm byte rand() { + ? ldx #8 + ? lda rand_seed+0 +__rand_loop: + asl + ? rol rand_seed+1 + bcc __no_eor + eor #$2D +__no_eor: + dex + bne __rand_loop + ? sta rand_seed+0 + ? rts +} + + +#if CBM_64 + +void init_rand_seed() { + poke($D40E, $ff) + poke($D40F, $ff) + poke($D412, $80) + while vic_raster != $70 {} + rand_seed.hi = peek($D41B) + while vic_raster != $40 {} + rand_seed.lo = peek($D41B) +} + +#else + +inline void init_rand_seed() { + // TODO: find a better source of randomness + rand_seed = 1 +} + +#endif \ No newline at end of file diff --git a/include/random_i80.mfk b/include/random_i80.mfk new file mode 100644 index 00000000..e999c2d9 --- /dev/null +++ b/include/random_i80.mfk @@ -0,0 +1,47 @@ + +import random + +#if not(ARCH_I80) +#warn stdlib_i80 module should be only used on Intel 8080-like targets +#endif + +#pragma zilog_syntax + +asm byte rand() { + ld b,8 + ld hl,(rand_seed) +__rand_loop: + add hl,hl + ? jp nc, __no_eor + ld a,l + xor $2D + ld l,a +__no_eor: +#if CPUFEATURE_Z80 + djnz __rand_loop +#else + dec b + ? jp nz, __rand_loop +#endif + ld (rand_seed),hl + ? ret +} + +#if CPUFEATURE_Z80 + +inline asm void init_rand_seed() { + ld a,r + ld (rand_seed), a + ld a,r + ld (rand_seed+1), a + ? ret +} + +#else + +inline void init_rand_seed() { + // TODO: find a better source of randomness + rand_seed = 1 +} + +#endif \ No newline at end of file diff --git a/include/stdio.mfk b/include/stdio.mfk index 362d3a29..ce5639c7 100644 --- a/include/stdio.mfk +++ b/include/stdio.mfk @@ -59,3 +59,18 @@ void putword(word w) { putchar('0') } } + +#if CBM_PET +inline asm void ensure_mixedcase() { + ? lda #14 + ! sta 59468 + ? rts +} +#elseif CBM +inline void ensure_mixedcase() { + putchar(14) +} +#else +inline void ensure_mixedcase() { +} +#endif