Library improvements

This commit is contained in:
Karol Stasiak 2018-12-17 17:18:29 +01:00
parent 7616c246ee
commit 585407e9bb
38 changed files with 554 additions and 70 deletions

View File

@ -3,8 +3,8 @@
# Target platforms
Currently, Millfork supports creating disk- or tape-based programs
for Commodore, Apple, BBC and Atari 8-bit computers, NEC PC-88, ZX Spectrum 48k,
and cartridge-based programs for Famicom/NES and Atari 2600,
for Commodore, Apple, BBC and Atari 8-bit computers, NEC PC-88, ZX Spectrum 48k, CP/M,
and cartridge-based programs for Commodore 64, VIC-20, Famicom/NES and Atari 2600,
but it may be expanded to support other 6502-based and Z80-based platforms in the future.
To add a custom platform yourself, see [the custom platform adding guide](./custom-platform.md).
@ -15,6 +15,10 @@ The following platforms are currently supported:
* `c64` Commodore 64
* `c64_crt8k` Commodore 64, 8K ROM cartridge
* `c64_crt16k` Commodore 64, 16K ROM cartridge
* `c64_scpu` Commodore 64 with SuperCPU in emulation mode
* `c64_scpu16` Commodore 64 with SuperCPU in native, 16-bit mode (very buggy)
@ -33,6 +37,8 @@ Read [the LUnix programming guide](./lunix-programming-guide.md) for more info.
* `vic20_8k` Commodore VIC-20 with 8K or 16K memory expansion
* `vic20_a000` Commodore VIC-20, 8K ROM cartridge at $A000
* `c128` Commodore 128 in its native mode
* `pet` Commodore PET
@ -55,7 +61,7 @@ Read [the BBC Micro programming guide](./bbcmicro-programming-guide.md) for more
The compiler only emits raw binaries, not disk images.
Read [the Apple 2 programming guide](./apple2-programming-guide.md) for more info.
* `pc88` NEC PC-88 (no ROM routines are mapped yet)
* `pc88` NEC PC-88
* `zxspectrum` Sinclair ZX Spectrum 48k

View File

@ -39,8 +39,12 @@
* [`stdlib` module](stdlib/stdlib.md)
* [Modules for reading input devices](stdlib/input.md)
* [Other cross-platform modules](stdlib/other.md)
* [Definitions available on only some platforms](stdlib/frequent.md)
* [C64-only modules](stdlib/c64.md)
* [NES-only modules](stdlib/nes.md)

View File

@ -8,16 +8,53 @@ The `c64_kernal` module is imported automatically on the C64 target.
TODO
## `c64_basic` module
## c64_basic module
TODO
## `c1531_mouse` module
## c64_hardware
TODO
## c1531_mouse
The `c1531_mouse` module implements a Commodore 1531 proportional mouse driver compatible with the `mouse` module.
#### `void c1531_mouse ()`
#### `void c1531_mouse()`
Updates the state of the mouse.
## c1531_mouse_default
Defines the `c1531` module as the default module for reading mouse input.
#### `alias read_mouse = c1531_mouse`
## c64_joy
The `c64_joy` module implements a joystick driver compatible with the `joy` module.
#### `void read_joy2()`
Reads the joystick from the port 2.
#### `void read_joy1()`
Reads the joystick from the port 1.
#### `void read_also_joy2()`
Reads the joystick from the port 2 and adds its readouts to the current readouts.
#### `void read_also_joy1()`
Reads the joystick from the port 1 and adds its readouts to the current readouts.
## c64_joy2_default
Defines the joystick in port 2 as the default joystick.
#### `alias read_joy = read_joy2`

42
docs/stdlib/frequent.md Normal file
View File

@ -0,0 +1,42 @@
[< back to index](../index.md)
Definitions on the following list are frequently provided by the default automatically-imported modules.
However, as they are not the part of the standard library, they might not be available on all targets:
#### `void putchar(byte char)`
Prints a single character.
Available for: all computer targets.
#### `void new_line()`
Moves the cursor to the next line.
Available for: all computer targets.
#### `void bell()`
Beeps.
Available for: Apple 2, ZX Spectrum.
#### `void set_bg_color(byte color)`
Sets the screen background color.
Available for: C64, VIC-20, C64, C264 series.
#### `void set_border(byte color)`
Sets the screen border color.
Available for: VIC-20, C64, C264 series, ZX Spectrum.
#### `const byte black, white, red, green, blue, cyan, purple, yellow`
Various colour constants.
Available for: VIC-20, C64, C264 series, ZX Spectrum.

66
docs/stdlib/input.md Normal file
View File

@ -0,0 +1,66 @@
[< back to index](../index.md)
## joy
The module contains global variables representing the state of the one-button joystick.
If the program is not using any joystick driver, the state of these variables is undefined.
#### `sbyte input_dx`
Horizontal joystick movement. 1 if right, -1 if left, 0 if neither.
#### `sbyte input_dy`
Vertical joystick movement. 1 if right, -1 if left, 0 if neither.
#### `byte input_btn`
1 if main button pressed, 0 id not pressed.
#### `void reset_joy()`
Resets the state variables.
For platforms with more than one button, this resets only the main button state.
## null_joy_default
This module set the default joystick to no joystick.
#### `alias read_joy`
## mouse
The `mouse` module automatically imports the `x_coord` module.
The module contains global variables representing the state of the mouse.
If the program is not using any mouse driver, the state of these variables is undefined.
#### `x_coord mouse_x`
Mouse X position.
#### `byte mouse_y`
Mouse Y position.
#### `byte mouse_lbm`
1 if the left mouse button is being pressed, 0 otherwise
#### `byte mouse_rbm`
1 if the right mouse button is being pressed, 0 otherwise
## `x_coord` module
#### `alias x_coord`
The type for representing horizontal screen coordinates.
It's `byte` if the screen is 256 pixels wide or less,
or `word` if the screen is more that 256 pixels wide.
## null_mouse_default
This module set the default joystick to no joystick.
#### `void read_mouse()`

View File

@ -2,13 +2,13 @@
# NES/Famicom-oriented modules
## `nes_hardware` module
## nes_hardware
The `nes_hardware` module is imported automatically on NES targets.
TODO
## `nes_mmc4` module
## nes_mmc4
The `nes_mmc4` module is imported automatically on the NES MMC4 target.
and contains routines related to MMC4 bankswitching.
@ -37,4 +37,51 @@ Switches nametable mirroring to vertical.
#### `void set_horizontal_mirroring()`
Switches nametable mirroring to horizontal.
Switches nametable mirroring to horizontal.
## nes_joy
Provides an interface for reading joypads that is compatible with the `joy` module.
#### `alias input_a = input_btn`
1 if A button pressed, 0 id not pressed.
#### `byte input_b`
1 if B button pressed, 0 id not pressed.
#### `byte input_select`
1 if Select button pressed, 0 id not pressed.
#### `byte input_start`
1 if Start button pressed, 0 id not pressed.
#### `void read_joy1()`
Reads the joypad from the port 1.
#### `void read_joy2()`
Reads the joypad from the port 2.
#### `void read_also_joy1()`
Reads the joypad from the port 1 and adds its readouts to the current readouts.
#### `void read_also_joy2()`
Reads the joypad from the port 2 and adds its readouts to the current readouts.
#### `void nes_reset_joy()`
Resets the state variables.
Unlike `reset_joy`, this resets all the NES button states.
## nes_joy1_default
Defines the joystick in port 1 as the default joystick.
#### `alias read_joy = read_joy1`

View File

@ -1,6 +1,6 @@
[< back to index](../index.md)
## `stdio` module
## stdio
The `stdio` module automatically imports the `string` module.
It requires an implementation of `void putchar(byte a)` and therefore works only on targets with console output.
@ -14,40 +14,9 @@ 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).
## `string` module
## string
#### `byte strzlen(pointer str)`
Calculates the length of a null-terminated string.
If the string is longer than 255 bytes, then the behaviour is undefined (might even crash).
## `mouse` module
The `mouse` module automatically imports the `x_coord` module.
The module contains global variables representing the state of the mouse.
If the program is not using any mouse driver, the state of these variables is undefined.
#### `x_coord mouse_x`
Mouse X position.
#### `byte mouse_y`
Mouse Y position.
#### `byte mouse_lbm`
1 if the left mouse button is being pressed, 0 otherwise
#### `byte mouse_rbm`
1 if the right mouse button is being pressed, 0 otherwise
## `x_coord` module
#### `alias x_coord`
The type for representing horizontal screen coordinates.
It's `byte` if the screen is 256 pixels wide or less,
or `word` if the screen is more that 256 pixels wide.

View File

@ -1,6 +1,6 @@
[< back to index](../index.md)
## `stdlib` module
## stdlib
The `stdlib` module is automatically imported on most targets.
@ -30,4 +30,4 @@ Returns an ASCII representation of the lower nibble of the given byte.
#### `macro asm void panic()`
Crashes the program.
Crashes the program.

View File

@ -2,9 +2,11 @@
## Cross-platform examples
* [Hello world](hello_world/hello_world.mfk) (C64/C16/PET/VIC-20/Atari/Apple II/BBC Micro) simple text output
* [Hello world](hello_world/hello_world.mfk) (C64/C16/PET/VIC-20/Atari/Apple II/BBC Micro/PC-88) simple text output
* [Text encodings](c64/text_encodings.mfk) (C64/ZX Spectrum) examples of text encoding features
* [Text encodings](c64/text_encodings.mfk) (C64/ZX Spectrum) examples of text encoding features
* [Bell](apple2/bell.mfk) (Apple II/ZX Spectrum) a program that goes \*ding!\*
## Commodore 64 examples
@ -30,10 +32,6 @@
* [MMC4 example](nes/nestest_mmc4.mfk) the same thing as above, but uses a MMC4 mapper just to test bankswitching
## Apple II examples
* [Bell](apple2/bell.mfk) a program that goes \*ding!\*
## Atari 2600 examples
* [Colors](vcs/colors.mfk) simple static rasterbars

View File

@ -5,9 +5,21 @@ import stdio
array hello_world = "hello world"
void main(){
void main() {
#if CBM_64 || CBM_264
set_bg_color(green)
#endif
#if CBM_64 || CBM_264 || ZX_SPECTRUM
set_border(red)
#endif
putstr(hello_world, hello_world.length)
putchar(13)
new_line()
putstrz("hello world again"z)
#if not(CPM)
while(true){}
#endif
}

View File

@ -1,6 +1,8 @@
// Based upon the example code from NES 101 tutorial by Michael Martin
// compile with -t nes_small
import nes_joy1_default
void main() {
init_graphics()
init_input()
@ -99,17 +101,14 @@ void update_sprite() {
}
void react_to_input() {
strobe_joypad()
if read_joypad1() & 1 != 0 { // A button
read_joy()
if input_a != 0 { // A button
reverse_dx()
}
read_joypad1() // B button
read_joypad1() // Select button
read_joypad1() // Start button
if read_joypad1() & 1 != 0 { // Up button
if input_dy < 0 { // Up button
if oam_buffer[0] > 7 { oam_buffer[0] -= 1}
}
if read_joypad1() & 1 != 0 { // Down button
if input_dy > 0 { // Down button
if oam_buffer[0] < 223 { oam_buffer[0] += 1}
}
}

View File

@ -4,11 +4,15 @@
#endif
asm void putchar(byte a) {
tax
? tax
lda $347
pha
lda $346
pha
txa
? txa
rts
}
}
inline void new_line() {
putchar($9b)
}

View File

@ -9,3 +9,4 @@ array hires_page_2 [$2000] @$4000
asm void bell() @$FBE4 extern
asm void putchar(byte a) @$FDED extern
asm void new_line() @$FC62 extern

View File

@ -6,3 +6,7 @@
// OSASCI. Write a character (to screen) from A plus LF if (A)=&0D
// Input: A = Byte to write.
asm void putchar(byte a) @$FFE3 extern
inline void new_line() {
putchar(13)
}

View File

@ -6,4 +6,8 @@
// CHROUT. Write byte to default output. (If not screen, must call OPEN and CHKOUT beforehands.)
// Input: A = Byte to write.
asm void putchar(byte a) @$FFD2 extern
asm void putchar(byte a) @$FFD2 extern
inline void new_line() {
putchar(13)
}

View File

@ -0,0 +1,3 @@
import c1541
alias read_mouse = c1531_mouse

View File

@ -5,4 +5,8 @@
// CHROUT. Write byte to default output. (If not screen, must call OPEN and CHKOUT beforehands.)
// Input: A = Byte to write.
asm void putchar(byte a) @$FFD2 extern
asm void putchar(byte a) @$FFD2 extern
inline void new_line() {
putchar(13)
}

View File

@ -2,6 +2,35 @@
#warn c264_ted module should be only used on C264-compatible targets
#endif
byte ted_cursor_hi @$FF0C
byte ted_cursor_lo @$FF0D
byte ted_color0 @$FF15
byte ted_color1 @$FF16
byte ted_color2 @$FF17
byte ted_color3 @$FF18
byte ted_border @$FF19
byte ted_raster_y @$FF1D
byte ted_raster_x @$FF1E
alias ted_bg_color = ted_color0
macro void set_bg_color(byte color) {
ted_color0 = color
}
macro void set_border(byte color) {
ted_border = color
}
inline void set_ted_cursor(word position) {
ted_cursor_hi = position.hi
ted_cursor_lo = position.lo
}
inline word get_ted_cursor() {
return ted_cursor_hi:position.lo
}
const byte black = 0
const byte white = $71
const byte red = $22

38
include/c64_joy.mfk Normal file
View File

@ -0,0 +1,38 @@
// standard joystick driver for Commodore 64
#if not(CBM_64)
#warn c64_joy module should be only used on C64-compatible targets
#endif
import joy
import c64_cia
inline void read_joy2 () {
reset_joy()
read_also_joy2()
}
inline void read_joy1 () {
reset_joy()
read_also_joy1()
}
void read_also_joy2() {
poke($dc02, 0)
byte value
value = peek($dc00)
if value & 1 == 0 { input_dy -= 1 }
if value & 2 == 0 { input_dy += 1 }
if value & 4 == 0 { input_dx -= 1 }
if value & 8 == 0 { input_dx += 1 }
if value & 16 == 0 { input_btn += 1 }
}
void read_also_joy1() {
poke($dc03, 0)
byte value
value = peek($dc01)
if value & 1 == 0 { input_dy -= 1 }
if value & 2 == 0 { input_dy += 1 }
if value & 4 == 0 { input_dx -= 1 }
if value & 8 == 0 { input_dx += 1 }
if value & 16 == 0 { input_btn += 1 }
}

View File

@ -0,0 +1,5 @@
// set C64 joystick in port 2 as the default
import c64_joy
alias read_joy = read_joy2

View File

@ -4,6 +4,10 @@
// Input: A = Byte to write.
asm void putchar(byte a) @$FFD2 extern
inline void new_line() {
putchar(13)
}
// OPEN. Open file. (Must call SETLFS and SETNAM beforehands.)
asm void open() @$FFC0 extern

View File

@ -131,6 +131,14 @@ macro void vic_bitmap_2000() {
vic_mem |= 8
}
macro void set_bg_color(byte color) {
vic_bg_color0 = color
}
macro void set_border(byte color) {
vic_border = color
}
// x, y < 8
// default: x=0, y=3
void vic_set_scroll(byte x, byte y) {

View File

@ -8,10 +8,15 @@ inline asm void exit() {
}
inline asm void putchar (byte e) {
? mvi c, 2
call 5
call 5
? ret
}
inline void new_line() {
putchar(13)
putchar(10)
}
inline asm byte getchar() {
? mvi c, 1
call 5

16
include/joy.mfk Normal file
View File

@ -0,0 +1,16 @@
// Generic module for joystick/gamepad support
// Horizontal movement: -1 for left, 1 for right
sbyte input_dx
// Vertical movement: -1 for up, 1 for down
sbyte input_dy
// Main button: 1 pressed, 0 not pressed
byte input_btn
void reset_joy() {
input_dx = 0
input_dy = 0
input_btn = 0
}

10
include/loader_a000.mfk Normal file
View File

@ -0,0 +1,10 @@
segment(prgrom)
array __vectors @$A000 = [
main.addr.lo,
main.addr.hi,
main.addr.lo,
main.addr.hi
]
segment(prgrom)
array __boot_signature @$A004 = [$41, $30, $C3, $C2, $CD]

47
include/nes_joy.mfk Normal file
View File

@ -0,0 +1,47 @@
// standard joystick driver for NES
import joy
import nes_hardware
alias input_a = input_btn
byte input_b
byte input_select
byte input_start
macro void read_joy1() {
nes_reset_joy()
read_also_joy2()
}
macro void read_joy2() {
nes_reset_joy()
read_also_joy1()
}
void nes_reset_joy() {
input_b = 0
input_select = 0
input_start = 0
reset_joy()
}
inline void read_also_joy1() {
strobe_joypad()
__parse_nes_joypad(read_joypad1())
}
inline void read_also_joy2() {
strobe_joypad()
__parse_nes_joypad(read_joypad2())
}
void __parse_nes_joypad(byte b) {
if read_joypad1() & 1 != 0 { input_a += 1 }
if read_joypad1() & 1 != 0 { input_b += 1 }
if read_joypad1() & 1 != 0 { input_select += 1 }
if read_joypad1() & 1 != 0 { input_start += 1 }
if read_joypad1() & 1 != 0 { input_dy -= 1 }
if read_joypad1() & 1 != 0 { input_dy += 1 }
if read_joypad1() & 1 != 0 { input_dx -= 1 }
if read_joypad1() & 1 != 0 { input_dx += 1 }
}

View File

@ -0,0 +1,5 @@
// set NES joypad in port 1 as the default
import nes_joy
alias read_joy = read_joy1

View File

@ -0,0 +1,5 @@
// set no joystick as the default
import joy
alias read_joy = reset_joy

View File

@ -0,0 +1,10 @@
// set no mouse as the default
import mouse
void read_mouse() {
mouse_x = 0
mouse_y = 0
mouse_lbm = 0
mouse_rbm = 0
}

View File

@ -3,7 +3,7 @@
[compilation]
arch=z80
encoding=jisx
modules=default_panic,stdlib
modules=default_panic,stdlib,pc88
[allocation]
; TODO: find a more optimal start address

11
include/pc88.mfk Normal file
View File

@ -0,0 +1,11 @@
#if not(NEC_PC_88)
#warn pc88 module should be only used on PC-88 targets
#endif
asm void putchar(byte a) @$3e0d extern
inline void new_line() {
putchar(13)
putchar(10)
}

View File

@ -2,7 +2,7 @@
arch=nmos
encoding=petscii
screen_encoding=petscr
modules=loader_1001,vic20_kernal,default_panic,stdlib
modules=loader_1001,vic20_kernal,vic20_hardware,default_panic,stdlib
[allocation]

View File

@ -2,7 +2,7 @@
arch=nmos
encoding=petscii
screen_encoding=petscr
modules=loader_0401,vic20_kernal,default_panic,stdlib
modules=loader_0401,vic20_kernal,vic20_hardware,default_panic,stdlib
[allocation]

View File

@ -2,7 +2,7 @@
arch=nmos
encoding=petscii
screen_encoding=petscr
modules=loader_1201,vic20_kernal,default_panic,stdlib
modules=loader_1201,vic20_kernal,vic20_hardware,,default_panic,stdlib
[allocation]

34
include/vic20_a000.ini Normal file
View File

@ -0,0 +1,34 @@
; VIC-20
; 8K ROM cartridge at $A000
[compilation]
arch=nmos
encoding=petscii
screen_encoding=petscr
modules=vic20_kernal,default_panic,stdlib,vic20_hardware,loader_a000
ro_arrays=true
[allocation]
zp_pointers=$C1,$C3,$FB,$FD,$39,$3B,$3D,$43,$4B
segments=default,prgrom
default_code_segment=prgrom
segment_default_start=$1000
segment_default_end=$1fff
segment_prgrom_start=$a000
segment_prgrom_end=$bfff
[define]
CBM=1
CBM_VIC=1
WIDESCREEN=0
KEYBOARD=1
JOYSTICKS=1
HAS_BITMAP_MODE=1
[output]
style=single
format=$00,$a0,prgrom:$a000:$bfff
extension=crt

View File

@ -0,0 +1,42 @@
#if not(CBM_VIC)
#warn vic20_hardware module should be only used on VIC-20-compatible targets
#endif
volatile byte vic_raster @$9004
byte vic_freq1 @$900a
byte vic_freq2 @$900b
byte vic_freq3 @$900c
byte vic_volume @$9003
byte vic_colors @$900f
macro void set_volume(byte volume) {
vic_volume &= $f0
vic_volume |= volume & $f
}
macro void set_bg_color(byte color) {
vic_colors &= $f
vic_colors |= color << 4
}
macro void set_border(byte color) {
vic_colors &= $f8
vic_colors |= color & 7
}
const byte black = 0
const byte white = 1
const byte red = 2
const byte cyan = 3
const byte purple = 4
const byte green = 5
const byte blue = 6
const byte yellow = 7
const byte orange = 8
const byte light_orange = 9
const byte light_red = 10
const byte light_cyan = 11
const byte light_purple = 12
const byte light_green = 13
const byte light_blue = 14
const byte light_yellow = 15

View File

@ -6,4 +6,8 @@
// CHROUT. Write byte to default output. (If not screen, must call OPEN and CHKOUT beforehands.)
// Input: A = Byte to write.
asm void putchar(byte a) @$FFD2 extern
asm void putchar(byte a) @$FFD2 extern
inline void new_line() {
putchar(13)
}

View File

@ -10,11 +10,22 @@ inline asm void putchar(byte a) {
? ret
}
inline void new_line() {
putchar(13)
}
inline asm void set_border(byte a) {
out (254),a
? ret
}
inline asm void bell() {
? ld hl,$6A
? ld de,$105
? call $3B5
? ret
}
const byte black = 0
const byte blue = 1
const byte red = 2