Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ A800_AS_SRC=\
# FP Interpreter ASM files
A800_FP_AS_SRC=\
$(A800_AS_SRC)\
src/interp/a800/fujinet.asm\
src/interp/atarifp/fp_coef.asm\
src/interp/atarifp/fp_abs.asm\
src/interp/atarifp/fp_atn.asm\
Expand Down
25 changes: 13 additions & 12 deletions manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -2550,22 +2550,23 @@ The general flow of use is:
- 2: Change LF to ATASCII EOL.
- 3: Change CR and LF to EOL.

*Note:* the _url_ is passed to the
FujiNet device without a terminating
zero byte, so any characters after
the string in memory can be read as
part of the URL. End the URL with a
zero byte, using the `$0` escape:

NOPEN 1,12,3,"N:http://www.example.com/"$0

A string variable needs the zero byte
added explicitly, for example:
The _url_ can be a string variable or
a constant string. String variables
are terminated automatically and can
have up to 254 characters:

URL$ = "N:http://www.example.com/"
URL$ =+ CHR$(0)
NOPEN 1,12,3,URL$

Constant strings are copied to a
temporary buffer and can have up to
127 characters:

NOPEN 1,12,3,"N:http://www.example.com/"

Other string expressions must first be
assigned to a string variable.

**Close a Network Connection**
**NCLOSE _unit_ / NC.**

Expand Down
87 changes: 87 additions & 0 deletions src/interp/a800/fujinet.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
;
; FastBasic - Fast basic interpreter for the Atari 8-bit computers
; Copyright (C) 2017-2025 Daniel Serpell
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 2 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License along
; with this program; if not, write to the Free Software Foundation, Inc.,
; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
;
; In addition to the permissions in the GNU General Public License, the
; authors give you unlimited permission to link the compiled version of
; this file into combinations with other programs, and to distribute those
; combinations without any restriction coming from the use of this file.
; (The General Public License restrictions do apply in other respects; for
; example, they cover modification of the file, and distribution when not
; linked into a combine executable.)

; FujiNet support
; ---------------

.include "atari.inc"

.import get_pointers, get_str_eol
.importzp move_dest, saddr

.export FUJI_NOPEN, FUJI_NOPEN_CONST, FUJI_COMMON

.segment "RUNTIME"

; Open a network connection. SADDR points to the URL string variable
; slot. get_pointers allocates the string if needed, so an empty
; variable works too.
.proc FUJI_NOPEN
jsr get_pointers

ldy #0
lda (move_dest),y
tay
iny
bne lenok
; The string allocation has no byte after 255 characters.
; Truncate the last character so the URL is still terminated.
ldy #255
lenok:
lda #0
sta (move_dest),y

ldx move_dest
ldy move_dest+1
inx
bne FUJI_SETBUF
iny
.endproc ; Fall through

.proc FUJI_SETBUF
stx $304
sty $305
.endproc ; Fall through

; Common FujiNet SIO call. All FujiNet statements use device $71 and
; the same timeout.
.proc FUJI_COMMON
lda #$71
sta $300
lda #$1F
sta $306
jmp SIOV
.endproc

; Constant strings are copied to LBUFF with an ATASCII EOL appended.
.proc FUJI_NOPEN_CONST
jsr get_str_eol
ldx #<LBUFF
ldy #>LBUFF
bne FUJI_SETBUF
.endproc

; vi:syntax=asm_ca65
2 changes: 2 additions & 0 deletions src/interp/copystr.asm
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

.segment "RUNTIME"

.export get_pointers

; Store source and destination pointers, allocating destination string if needed.
; Returns Y=0
.proc get_pointers
Expand Down
4 changes: 4 additions & 0 deletions src/parse.asm
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
.import EXE_END, PMGMODE, PMGBASE
; Interpreted commands
.import CLEAR_DATA, SOUND_OFF
.ifdef FASTBASIC_FP
; FujiNet commands
.import FUJI_NOPEN, FUJI_NOPEN_CONST, FUJI_COMMON
.endif
; From errors.asm
.import error_msg_list
.importzp ERR_PARSE, ERR_NO_ELOOP, ERR_LABEL, ERR_TOO_LONG
Expand Down
73 changes: 44 additions & 29 deletions src/syntax/fujinet.syn
Original file line number Diff line number Diff line change
Expand Up @@ -13,60 +13,75 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# In addition to the permissions in the GNU General Public License, the
# authors give you unlimited permission to link the compiled version of
# this file into combinations with other programs, and to distribute those
# combinations without any restriction coming from the use of this file.
# (The General Public License restrictions do apply in other respects; for
# example, they cover modification of the file, and distribution when not
# linked into a combine executable.)

#
# FujiNet syntax additions by Thomas Cherryhomes
# <thom dot cherryhomes at gmail dot com>
#

SYMBOLS {
FUJI_NOPEN = import
FUJI_NOPEN_CONST = import
FUJI_COMMON = import
}

NOPEN_URL: NOPEN URL argument
# String variables are terminated in place, with no extra buffer.
VAR_STR_LVALUE_SADDR emit { TOK_NUM, &FUJI_NOPEN, TOK_USR_ADDR }
# Constant strings are copied to LBUFF and get an ATASCII EOL.
emit { TOK_NUM, &FUJI_NOPEN_CONST, TOK_USR_ADDR } STR_EXPR

FUJI_HEAD:
EXPR emit { TOK_NUM_POKE, &$301 }

FUJI_TAIL:
emit { TOK_NUM_POKE, &$303, TOK_NUM, &FUJI_COMMON, TOK_USR_ADDR, TOK_USR_CALL }

STATEMENT:
"NOpen" EXPR emit { TOK_NUM_POKE, &$301 } \
"NOpen" FUJI_HEAD \
COMMA_EXPR emit { TOK_NUM_POKE, &$30A } \
COMMA_EXPR emit { TOK_NUM_POKE, &$30B } \
"," emit { TOK_NUM, &$304, TOK_SADDR } STR_EXPR emit { TOK_PUSH_1, TOK_ADD, TOK_DPOKE } \
emit { TOK_BYTE, $71, TOK_NUM_POKE, &$300 } \
emit { TOK_BYTE, $4F, TOK_NUM_POKE, &$302 } \
emit { TOK_BYTE, $80, TOK_NUM_POKE, &$303 } \
emit { TOK_BYTE, $1F, TOK_NUM_POKE, &$306 } \
emit { TOK_NUM, &$308, TOK_SADDR, TOK_NUM, &$100, TOK_DPOKE } \
emit { TOK_NUM, &$E459, TOK_USR_ADDR, TOK_USR_CALL }
emit { TOK_NUM, &$308, TOK_SADDR, TOK_NUM, &$100, TOK_DPOKE } \
emit { TOK_BYTE, $4F, TOK_NUM_POKE, &$302 } \
emit { TOK_BYTE, $80, TOK_NUM_POKE, &$303 } \
"," NOPEN_URL emit { TOK_USR_CALL }

"NClose" EXPR emit { TOK_NUM_POKE, &$301 } \
emit { TOK_BYTE, $71, TOK_NUM_POKE, &$300 } \
"NClose" FUJI_HEAD \
emit { TOK_BYTE, $43, TOK_NUM_POKE, &$302 } \
emit { TOK_BYTE, $00, TOK_NUM_POKE, &$303 } \
emit { TOK_BYTE, $1F, TOK_NUM_POKE, &$306 } \
emit { TOK_NUM, &$308, TOK_SADDR, TOK_0, TOK_DPOKE } \
emit { TOK_NUM, &$E459, TOK_USR_ADDR, TOK_USR_CALL }
emit { TOK_BYTE, $00 } \
FUJI_TAIL

"NStatus" EXPR emit { TOK_NUM_POKE, &$301 } \
emit { TOK_BYTE, $71, TOK_NUM_POKE, &$300 } \
"NStatus" FUJI_HEAD \
emit { TOK_BYTE, $53, TOK_NUM_POKE, &$302 } \
emit { TOK_BYTE, $40, TOK_NUM_POKE, &$303 } \
emit { TOK_BYTE, $1F, TOK_NUM_POKE, &$306 } \
emit { TOK_NUM, &$304, TOK_SADDR, TOK_NUM, &$2EA, TOK_DPOKE } \
emit { TOK_BYTE, $04, TOK_NUM_POKE, &$308 } \
emit { TOK_BYTE, $00, TOK_NUM_POKE, &$309 } \
emit { TOK_NUM, &$E459, TOK_USR_ADDR, TOK_USR_CALL }
emit { TOK_BYTE, $40 } \
FUJI_TAIL

"NGet" EXPR emit { TOK_NUM_POKE, &$301 } \
"NGet" FUJI_HEAD \
"," emit { TOK_NUM, &$304, TOK_SADDR } EXPR emit { TOK_DPOKE } \
"," emit { TOK_NUM, &$308, TOK_SADDR } EXPR emit { TOK_DPOKE } \
emit { TOK_NUM, &$30A, TOK_SADDR, TOK_NUM, &$308, TOK_DPEEK, TOK_DPOKE } \
emit { TOK_BYTE, $71, TOK_NUM_POKE, &$0300 } \
emit { TOK_BYTE, $52, TOK_NUM_POKE, &$0302 } \
emit { TOK_BYTE, $40, TOK_NUM_POKE, &$0303 } \
emit { TOK_BYTE, $1F, TOK_NUM_POKE, &$0306 } \
emit { TOK_NUM, &$E459, TOK_USR_ADDR, TOK_USR_CALL }
emit { TOK_BYTE, $40 } \
FUJI_TAIL

"NPut" EXPR emit { TOK_NUM_POKE, &$301 } \
"NPut" FUJI_HEAD \
"," emit { TOK_NUM, &$304, TOK_SADDR } EXPR emit { TOK_DPOKE } \
"," emit { TOK_NUM, &$308, TOK_SADDR } EXPR emit { TOK_DPOKE } \
emit { TOK_NUM, &$30A, TOK_SADDR, TOK_NUM, &$308, TOK_DPEEK, TOK_DPOKE } \
emit { TOK_BYTE, $71, TOK_NUM_POKE, &$0300 } \
emit { TOK_BYTE, $57, TOK_NUM_POKE, &$0302 } \
emit { TOK_BYTE, $80, TOK_NUM_POKE, &$0303 } \
emit { TOK_BYTE, $1F, TOK_NUM_POKE, &$0306 } \
emit { TOK_NUM, &$E459, TOK_USR_ADDR, TOK_USR_CALL }
emit { TOK_BYTE, $80 } \
FUJI_TAIL
42 changes: 42 additions & 0 deletions testsuite/tests/stmt-fujinet.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
' Test DCB setup of the other FujiNet statements
DIM BUF(4) BYTE

URL$="N:http://example.com/"
NOPEN 3,4,2,URL$

NCLOSE 3
? "cdev="; PEEK($300)=$71
? "cunit="; PEEK($301)=3
? "ccmd="; PEEK($302)=$43
? "cstat="; PEEK($303)=138
? "ctim="; PEEK($306)=$1F
? "clen="; DPEEK($308)=0

NSTATUS 3
? "sdev="; PEEK($300)=$71
? "sunit="; PEEK($301)=3
? "scmd="; PEEK($302)=$53
? "sstat="; PEEK($303)=138
? "stime="; PEEK($306)=$1F
? "sbuf="; DPEEK($304)=$2EA
? "slen="; DPEEK($308)=4

NGET 3,&BUF,4
? "gdev="; PEEK($300)=$71
? "gunit="; PEEK($301)=3
? "gcmd="; PEEK($302)=$52
? "gstat="; PEEK($303)=138
? "gtime="; PEEK($306)=$1F
? "gbuf="; DPEEK($304)=ADR(BUF)
? "glen="; DPEEK($308)=4
? "gaux="; DPEEK($30A)=4

NPUT 3,&BUF,4
? "pdev="; PEEK($300)=$71
? "punit="; PEEK($301)=3
? "pcmd="; PEEK($302)=$57
? "pstat="; PEEK($303)=138
? "ptime="; PEEK($306)=$1F
? "pbuf="; DPEEK($304)=ADR(BUF)
? "plen="; DPEEK($308)=4
? "paux="; DPEEK($30A)=4
32 changes: 32 additions & 0 deletions testsuite/tests/stmt-fujinet.chk
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Name: Test FujiNet statement DCB setup
Test: run, fp
Output:
cdev=1
cunit=1
ccmd=1
cstat=1
ctim=1
clen=1
sdev=1
sunit=1
scmd=1
sstat=1
stime=1
sbuf=1
slen=1
gdev=1
gunit=1
gcmd=1
gstat=1
gtime=1
gbuf=1
glen=1
gaux=1
pdev=1
punit=1
pcmd=1
pstat=1
ptime=1
pbuf=1
plen=1
paux=1
65 changes: 65 additions & 0 deletions testsuite/tests/stmt-nopen.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
' Test NOPEN SIO parameters and URL termination
'
' The URL is first made longer and then shorter, so the end of the
' shorter string contains a stale nonzero byte. NOPEN must write a
' zero terminator at the new end.
URL$="N:http://example.com/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/"
URL$="N:http://example.com/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/"
NOPEN 3,4,2,URL$

P=DPEEK($304)
L=LEN(URL$)
A=PEEK(P)
B=PEEK(P+L-1)
Z=PEEK(P+L)
DEV=PEEK($300)
UNIT=PEEK($301)
CMD=PEEK($302)
TIM=PEEK($306)
MODE=PEEK($30A)
TRANS=PEEK($30B)
BLEN=DPEEK($308)
ERR=SERR()

? "dev="; DEV=$71
? "unit="; UNIT=3
? "cmd="; CMD=$4F
? "tim="; TIM=$1F
? "mode="; MODE=4
? "trans="; TRANS=2
? "len="; BLEN=256
? "first="; A=78
? "last="; B=47
? "nul="; Z=0
? "serr="; ERR=138

' Constant-string path: get_str_eol appends ATASCII EOL ($9B).
NOPEN 3,4,2,"N:http://www.textfiles.com/"
P=DPEEK($304)
L=LEN("N:http://www.textfiles.com/")
A=PEEK(P)
B=PEEK(P+L-1)
Z=PEEK(P+L)
ERR=SERR()

? "cfirst="; A=78
? "clast="; B=47
? "ceol="; Z=$9B
? "cserr="; ERR=138

' An uninitialized string variable must be allocated before SIO.
DIM EMPTY$
NOPEN 3,4,2,EMPTY$
P=DPEEK($304)
? "empty="; P<>0
? "empty0="; PEEK(P)=0

' A 255-byte string is truncated by one byte so it can be terminated.
DIM LONG$
LONG$="N:"
FOR I=1 TO 253
LONG$=+ "x"
NEXT
NOPEN 3,4,2,LONG$
P=DPEEK($304)
? "max="; PEEK(P+254)=0
Loading
Loading