This commit is contained in:
mgcaret 2017-09-15 09:55:29 -07:00
commit d9b665d62a
21 changed files with 4894 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
*.o
*.p8c
*.lst
*.map
*.po
*.SHK
*.shk
help
test

49
Makefile Executable file
View File

@ -0,0 +1,49 @@
DAVEX=../davex-code/src
ACMD=java -jar ~/bin/AppleCommander-1.3.5-ac.jar
NULIB2=nulib2
BOOTDSK=~/vii_hd.2mg
CA65=ca65
LD65=utils/auto_origin.sh ld65
GENHELP=utils/gen_help.sh
MG_CMDS=at.info.p8c at.zones.p8c afp.userprefix.p8c afp.sessions.p8c alias.p8c at.boot.p8c deschw.p8c dmem.p8c nbp.lookup.p8c tardis.p8c nbp.parse.p8c iie.card.p8c idemu.p8c mig.insp.p8c
.PHONY: all
all: shk ;
.phony: shk
shk: DAVEX.MG.SHK ;
.phony: disk
disk: davex.mg.po ;
davex.mg.po: $(MG_CMDS)
$(ACMD) -pro140 davex.mg.po DAVEX.MG
set -x; for CMD in $(MG_CMDS); do $(ACMD) -p davex.mg.po $${CMD%.*} 'BIN' '0x8001' < $$CMD; done
#set -x; for HLP in help/*; do $(ACMD) -p davex.mg.po $$HLP 'TXT' < $$HLP; done
# Adjust for your emulation scenario
emulate: davex.mg.po
open $(BOOTDSK) davex.mg.po -a 'Virtual ]['
DAVEX.MG.SHK: $(MG_CMDS)
rm -f DAVEX.MG.SHK
set -x; for CMD in $(MG_CMDS); do cp -p $$CMD "$${CMD%.*}#2E8001"; done
$(NULIB2) -ae DAVEX.MG.SHK *2E8001
rm -f *2E8001
set -x; for HLP in help/*; do cp -p $$HLP "$$HLP#040000"; done
$(NULIB2) -ae DAVEX.MG.SHK help/*040000
rm -f help/*040000
ls -l DAVEX.MG.SHK
%.p8c: %.o
${LD65} -t none -m $@.map -o $@ $<
%.o: %.s
$(CA65) --include-dir $(DAVEX) -l $@.lst -o $@ $<
mkdir -p help; FILE="$<"; $(GENHELP) $< "help/$${FILE%.*}"
.PHONY: clean
clean:
rm -f *.o *.p8c *.lst *.map davex.mg.po DAVEX.MG.SHK help/*
rmdir help

108
README.md Normal file
View File

@ -0,0 +1,108 @@
# MG's DaveX Utilities
This is a collection utilities for [davex](https://sourceforge.net/p/davex/home/Home/), mostly centered around AppleTalk, but also a few others including fixed or enhanced versions of a few existing davex.
## Utilities
See the source or generated help files for each utility, for further information/options/etc.
### AppleTalk
#### afp.sessions
Displays AFP sessions.
#### afp.userprefix
Print or set the AFP user prefix.
#### at.boot
Boots over Appletalk.
#### at.info
Display some AppleTalk info
#### at.zones
Display AppleTalk zone information.
#### nbp.lookup
Look up NBP names registered on the network.
#### nbp.parse
Parse an NBP name and display the parts. Mainly used for testing the parsing routine.
#### tardis
Get time from TimeLord server.
### Fixed/Enhanced
#### alias
This is a fixed version of the alias command included in davex 1.30p.
#### deschw
This has been enhanced to identify the CPU and to detect emulation. If an emulator supporting EMUBYTE is found, displays its name and version if known.
See idemu for more comprehensive emulator detection.
There are also a few other enhancements around SmartPort device info.
### Misc
#### dmem
Displays info on davex "dynamic memory." Mainly for testing purposes.
#### idemu
Identifies emulators. If a positive ID on EMUBYTE can be used, uses it. Otherwise, attempts to use the various emulators' idiosynchracies regarding emulator ROM and I/O space to make the identification. It does not interact with any slot hardware.
#### iie.card
Display or change the speed of the 65C02 on the Apple //e Card for Macintosh LC.
Optionally, use undocumented features to display the user-selected startup slot.
#### mig.insp
View the contents of the Apple IIc Plus MIG RAM.
## Building
Building the utilities requires a Unix-like environment with GNU Make and the usual set of Unix utilities such as sed, awk, egrep, etc.
A working installtion of cc65 must be present and in the PATH (for ca65, ld65, od65).
The davex source code (link at top) must be present somewhere, and the DAVEX variable in the Makefile should point to it.
In order to build the default target (a ShrinkIt file), nulib2 must be present and in the PATH.
In order to build a disk image, you must have AppleCommander CLI version set up and must modify the Makefile.
The utilities are developed on macOS X.
### Interesting make targets
* ``all``: build shrinkit file DAVEX.MG.SHK
* ``disk``: build davex.mg.po
* ``emulate``: builds disk and attempts to open with Virtual ][. Set BOOTDSK in Makefile first.
## Developing
Fork it, send pull requests, etc.
I created a custom set of macros and tools for doing davex external commands. These are in ``davex-mg.inc`` and in the ``utils`` directory.
In particular, the macros along with ``utils/auto_origin.sh`` allow automatically meeting the davex external command loading recommendations, which are "load on a page boundary so that the end of the file loads between $AF00 and $AFFF."
Additionaly, ``utils/gen_help.sh`` is used to extract the help file contents from the source code of each utility.

169
afp.sessions.s Normal file
View File

@ -0,0 +1,169 @@
; %help
; afp.sessions - Display AFP sessions.
; %hend
.pc02
.include "davex-mg.inc"
sptr = xczpage
altbuf = filebuff3 ; if no dynamic mem avail
altbufsz = $04 ; pages
DX_start dx_mg_auto_origin ; load address
DX_info $01,$12,dx_cc_iie_or_iigs,$00
DX_ptab
DX_end_ptab
DX_desc "Display AFP sessions."
DX_main
cli ; appletalk requires interrupts
ATcall inforeq
bcc :+
jmp noatalk
: jsr getatbuf
sta bufp+1
sty bufp
stx buflen+1
ATcall filsess
bcs nosess1
lda nument ; number of entries returned
bne :+
jsr xmess
asc_hi "No sessions."
.byte $8d,$00
nosess1: jmp nosess
: lda bufp+1
sta sptr+1
lda bufp
sta sptr
jsr xmess
asc_hi " session vol id dev volume name (* = user volume)"
.byte $8d
asc_hi " ------- ------ --- --------------------------------"
.byte $8d,$00
; loop to display sessions
dispsess: ldy #$00
sty num+1
sty num+2
lda (sptr),y ; ref num
sta num
jsr xprdec_pad
lda #' '+$80
jsr cout
ldy #$1e ; offset of volume id
lda (sptr),y
sta num
iny
lda (sptr),y
sta num
jsr xprdec_pad
lda #' '+$80
jsr cout
ldy #$01 ; offset of devnum
lda (sptr),y
pha
jsr xprint_sd
lda #' '+$80
jsr cout
pla
and #$01 ; isolate user volume flag
beq notuser
lda #'*'+$80
bne :+
notuser: lda #' '+$80
: jsr cout
lda sptr+1
pha ; save sptr
lda sptr
pha
lda #$02 ; offset to volume name
jsr addsptr
jsr prpas
lda #$8d
jsr cout
pla ; restore sptr to where it was
sta sptr
pla
sta sptr+1
lda #$20 ; size of entry
jsr addsptr ; now point at next entry
jsr xcheck_wait ; see if should pause or quit
bcs nosess ; quit if esc pressed
dec nument
bne dispsess
nosess: ;ldx mli_close ; free mem
;jsr xmmgr ; do it
rts
noatalk: lda #$01
jsr xredirect
jsr xmess
asc_hi "AppleTalk offline!"
.byte $00
exiterr: lda #$ff
jsr xredirect
jmp xerr
;
; increment sptr by a
.proc addsptr
clc
adc sptr
sta sptr
bcc :+
inc sptr+1
: rts
.endproc
; print pascal string at sptr
; leave sptr pointed at one past end
; of string
.proc prpas
ldy #$00
lda (sptr),y ; get length
tax
next: lda #$01
jsr addsptr
dex
bpl :+
rts
: lda (sptr),y ; get char
ora #$80 ; make printable
jsr cout
bra next
.endproc
; allocate a big buffer for appletalk operations
; returns ay = start, x = size in pages
; tries to use dynamic mem for operations
; otherwise returns altbuf
.proc getatbuf
ldx #mli_read
jsr xmmgr
bcs usealt
cmp #altbufsz
bcc usealt
sta tmp ; save num pages
ldx #mli_open
jsr xmmgr ; allocate all
bcc usealt ; if error
ldx tmp ; get num pages
ldy #$00 ; always on page boundary
rts
usealt: ldy #<altbuf
lda #>altbuf
ldx altbufsz
rts
tmp: .byte $00
.endproc
;
inforeq: .byte 0,2 ; sync GetInfo
.word $0000 ; result code
.dword $00000000 ; completion address
thisnet: .word $0000 ; this network #
abridge: .byte $00 ; local bridge
hwid: .byte $00 ; hardware ID, IIgs only
romver: .word $00 ; ROM version, IIgs only
nodenum: .byte $00 ; node number
;
filsess: .byte 0,$2f ; sync FIListSessions
.word $0000 ; result code
buflen: .word altbufsz*$100 ; buffer length
bufp: .dword altbuf ; buffer pointer
nument: .byte $00 ; entries returned
DX_end

177
afp.userprefix.s Normal file
View File

@ -0,0 +1,177 @@
; %help
; afp.userprefix - Display or set the AFP user prefix.
;
; options: -s <path> Set to <path>, normally only if not already set.
; -f Force setting even if it is already set.
; -c Set current prefix to user prefix.
;
; Note that setting the user prefix uses undocumented features of the
; AppleTalk stack.
; %hend
.pc02
.include "davex-mg.inc"
sptr = xczpage
setflag = sptr+2
pfxbuf = filebuff2
DX_start dx_mg_auto_origin ; load address
DX_info $01,$12,dx_cc_iie_or_iigs,$00
DX_ptab
DX_parm 's',t_path ; path to set
DX_parm 'f',t_nil ; force setting
DX_parm 'c',t_nil ; set prefix
DX_end_ptab
DX_desc "Display or set AFP User Prefix."
DX_main
cli ; appletalk requires interrupts
ATcall inforeq
bcc :+
jmp noatalk
: stz setflag
lda #'s'|$80
jsr xgetparm_ch
bcs :+ ; set not requested
inc setflag
: lda #'f'|$80
jsr xgetparm_ch
bcs getit ; not being forced to set
lda setflag
beq :+ ; user said -f without -s, go to error
jmp setpfx ; -s and -f, set prefix
: lda #$01
jsr xredirect
jsr xmess
asc_hi "-f without -s!"
.byte $00
bra exiterr
getit: stz dirflag ; make sure we are getting, not setting
ATcall pfxreq ; get user prefix
bcc :+ ; if no error
lda setflag ; error, see if we should try setting it?
beq pfxerr ; nope, error out
bra tryset ; otherwise, try setting
: lda #<pfxbuf ; set sptr to prefix buffer
sta sptr
lda #>pfxbuf
sta sptr+1
ldy #$00 ; index of length byte
lda (sptr),y ; check length
beq :+ ; no prefix, see if we should set it
stz setflag ; have a prefix already, so flag don't set
jsr prpas ; and print
: lda setflag ; user wants prefix set?
beq :+ ; no, so skip doing it
tryset: jmp setpfx ; go to the set routine
: lda #'c'|$80
jsr xgetparm_ch ; change to wanted?
bcs :+ ; nope, skip to the end
P8call $c6,p8pfxreq ; enact the change
bcc :+ ; all good, skip error
jmp xProDOS_err ; if something went pear-shaped
: rts ; buhbye
pfxerr: lda #$01
jsr xredirect
jsr xmess
asc_hi "Get/set user prefix error!"
.byte $00
bra exiterr
noatalk: lda #$01
jsr xredirect
jsr xmess
asc_hi "AppleTalk offline!"
.byte $00
exiterr: lda #$ff
jsr xredirect
jmp xerr
;
setpfx: lda #'s'|$80 ; get the pointer to option
jsr xgetparm_ch
bcs badpath ; shouldn't happen here!!!
sty sptr ; set sptr to check length
sty parm1 ; and parm1 for copy
sta sptr+1
sta parm1+1
lda (sptr),y ; check length
beq badpath ; and if zero, it must be bad
jsr xpmgr ; copy from user option to pfxbuf
.byte pm_copy ; davex function
parm1: .addr pfxbuf ; source, initially something not entirely insane
.addr pfxbuf ; destination
P8call $c4,fileinfo ; P8 GET_FILE_INFO
bcc :+ ; no error, continue
jmp xProDOS_err ; something went pear-shaped
: lda fitype ; get file type
cmp #$0f ; is directory?
bne badpath ; nope... error out
lda #$aa ; undocumented, found in LOGON program
sta dirflag
ATcall pfxreq ; set user prefix
bcc :+ ; all good, skip error
jmp pfxerr ; sigh... error out
: stz setflag ; avoid infinite loop
jmp getit ; wind back to get/print/maybe change dir
badpath: lda #$01
jsr xredirect
jsr xmess
asc_hi "Bad new prefix!"
.byte $00
bra exiterr
; increment sptr by a
.proc addsptr
clc
adc sptr
sta sptr
bcc :+
inc sptr+1
: rts
.endproc
; print pascal string at sptr
; leave sptr pointed at one past end
; of string
.proc prpas
ldy #$00
lda (sptr),y ; get length
tax
next: lda #$01
jsr addsptr
dex
bpl :+
rts
: lda (sptr),y ; get char
ora #$80 ; make printable
jsr cout
bra next
.endproc
;
inforeq: .byte 0,2 ; sync GetInfo
.word $0000 ; result code
.dword $00000000 ; completion address
thisnet: .word $0000 ; this network #
abridge: .byte $00 ; local bridge
hwid: .byte $00 ; hardware ID, IIgs only
romver: .word $00 ; ROM version, IIgs only
nodenum: .byte $00 ; node number
;
pfxreq: .byte 0,$2a ; sync FIUserPrefix
.word $0000 ; result
dirflag: .byte $00 ; direction flag (bit 7)
.dword pfxbuf ; buffer (at least 64 bytes)
;
p8pfxreq: .byte $01
.addr pfxbuf
;
fileinfo: .byte $0a
.addr pfxbuf ; buffer
.byte $00 ; access
fitype: .byte $00 ; want to see $0f
.word $0000 ; aux type
.byte $00 ; storage type
.word $0000 ; blocks used
.word $0000 ; mod date
.word $0000 ; mod time
.word $0000 ; create date
.word $0000 ; create time
DX_end

581
alias.s Normal file
View File

@ -0,0 +1,581 @@
;*************************************************
;*************************************************
;
; 'alias' -- external command for Davex
;
; alias -- view and modify Davex aliases
;
; alias [-s] [-l] [-r] <str1> <str2>
;
; alias displays all aliases
; alias <a> <b> adds alias
; alias -r <a> removes alias <a>
; alias -s saves aliases to %aliases
; alias -l loads aliases from %aliases
;
;*************************************************
;
; Converted to MPW IIgs 20-Sep-92 DAL
;
; Fixed from the 1.30P version on SourceForge 26-Jul-17 MG
;
;*************************************************
;.segment "CODE_A000"
OrgAdr = $A000 ;change as necessary (end below $B000)
.org OrgAdr ; Makes the listing more readable, though it doesn't really org the code - the linker does that.
.include "Common/2/Globals2.asm"
.include "Common/2/Apple.Globals2.asm"
.include "Common/2/Mli.Globals2.asm"
.include "Common/Macros.asm"
;include 'm16.util2'
low_cr = $0D
;
MyVersion = $09
MinVersion = $12
MinVerAux = $05
;*************************************************
rts
.byte $ee,$ee
.byte MyVersion,MinVersion
.byte %00000000 ;hardware req
.addr descr
.addr OrgAdr
.addr start
.byte MinVerAux,0,0,0
; parameters here
.byte 0,t_string
.byte 0,t_string
.byte $80+'r',t_nil
.byte $80+'s',t_nil
.byte $80+'l',t_nil
.byte 0,0
descr:
pstr "display or modify command aliases"
;*************************************************
; dum xczpage ;32 locations
AliasPages = xczpage
AliasP = AliasPages+1
AliasEnd = AliasP+2
myP = AliasEnd+2
str1 = myP+2
str2 = str1+2
char = str2+2
count = char+1 ;.res 2
; dend
;
start = *
sta str1+1
sty str1
lda #1
jsr xgetparm_n
sta str2+1
sty str2
ldx #1
jsr xshell_info
sta AliasP+1
sty AliasP
sty AliasEnd
stx AliasPages
txa
clc
adc AliasP+1
sta AliasEnd+1
lda #$80+'l'
jsr xgetparm_ch
bcs noLoad
jsr load_aliases
noLoad:
jsr DoAlias
lda #$80+'s'
jsr xgetparm_ch
bcs noSave
jsr save_aliases
noSave:
rts
;*************************************************
;
; handle adding, removing, or showing aliases
;
DoAlias:
lda #$80+'r'
jsr xgetparm_ch
bcs noRmv
jmp remove_alias
noRmv:
ldy #0
lda (str1),y
bne doAdd
lda (str2),y
bne doAdd
jsr xgetnump
cmp #2
beq show_aliases
rts
doAdd: jmp add_alias
;*************************************************
;
; Display all the aliases
;
show_aliases:
jsr CalcUsedSize
jsr xprdec_2
jsr xmess
asc_hi " bytes used (of "
.byte 0
lda AliasPages
ldy #0
jsr xprdec_2
jsr xmess
asc_hi ") to store these aliases:"
.byte low_cr
asc_hi " "
.byte 0
;
lda AliasP+1
ldy AliasP
sta myP+1
sty myP
ShowA1: lda (myP),y
beq ShowedA
jsr NeatCout
bcs ShowedA
iny
bne ShowA1
inc myP+1
bne ShowA1
ShowedA: rts
NeatCout: ora #$80
cmp #$8d
beq isCR
jsr cout
clc
rts
isCR: jsr xcheck_wait
bcs isCR2
jsr crout
lda #$80+' '
jsr cout
jsr cout
clc
isCR2: rts
;*************************************************
;
; Save aliases to %aliases file
;
save_aliases:
lda #>AliasName
ldy #<AliasName
jsr xbuild_local
sta aPath+1
sty aPath
sta acPath+1
sty acPath
jsr mli
.byte mli_create
.addr CreateA
bcc CreateOK
cmp #err_dupfil
bne DiskError
CreateOK:
jsr mli
.byte mli_open
.addr OpenA
bcs DiskError
lda aRef
sta aRef2
sta aRef3
sta aRef4
jsr CalcUsedSize
sta WriteA+5
sty WriteA+4
jsr mli
.byte mli_write
.addr WriteA
bcs DiskError
jsr mli
.byte mli_getmark
.addr MarkA
jsr mli
.byte mli_seteof
.addr MarkA
jsr mli
.byte mli_close
.addr CloseA
bcs DiskError
rts
;*************************************************
;
; Load aliases from %aliases file
;
load_aliases:
lda #>AliasName
ldy #<AliasName
jsr xbuild_local
sta aPath+1
sty aPath
jsr mli
.byte mli_open
.addr OpenA
bcs DiskError
lda aRef
sta aRef2
sta aRef3
lda AliasPages
ldy #0
sta ReadA+5
sty ReadA+4
jsr mli
.byte mli_read
.addr WriteA
php
pha
jsr strip7
pla
plp
bcs DiskError
jsr mli
.byte mli_close
.addr CloseA
bcs DiskError
rts
DiskError: jmp xProDOS_err
CreateA: .byte 7
acPath: .addr 0
.byte $C3 ;access
.byte tTXT ;filetype
.addr 0 ;auxtype
.byte 1 ;storage type
.addr 0,0 ;create date/time
OpenA: .byte 3
aPath: .addr 0
.addr filebuff
aRef: .byte 0
ReadA:
WriteA: .byte 4
aRef2: .byte 0
.addr Aliases,$0000,0
MarkA: .byte 2
aRef4: .byte 0
.byte 0,0,0
CloseA: .byte 1
aRef3: .byte 0
AliasName:
.byte 7,"ALIASES"
strip7: lda AliasPages
sta count
lda AliasP+1
ldy AliasP
sta myP+1
sty myP
ldy #0
strip1: lda (myP),y
and #%01111111
sta (myP),y
dey
bne strip1
dec count
bne strip1
rts
;*************************************************
;
; remove an alias
;
remove_alias:
ldy #0
lda (str2),y
beq rmv2ok
jsr xmess
.byte cr
asc_hi "*** too many parameters for removing an alias"
.byte low_cr,0
jmp xerr
rmv2ok:
jsr FindAlias
bcc rmvFound
jsr xmess
.byte cr
asc_hi "*** no such alias found"
.byte low_cr,0
jmp xerr
rmvFound: jsr remove_it
rts
;
; Add an alias, possibly replacing an existing one
;
add_alias:
jsr FindAlias
bcs addMissing
lda #1
jsr xredirect
jsr xmess
asc_hi "Okay to replace existing alias "
.byte $A2,0
lda str1+1
ldy str1
jsr xprint_path
lda #$A2
jsr cout
lda #$80+'n'
jsr xyesno2
php
lda #<-1
jsr xredirect
plp
bne ReplacIt
rts
ReplacIt: jsr remove_it
addMissing:
jsr CalcUsedSize
ldy #0
clc
lda (str1),y
adc (str2),y
adc #3
adc count
lda count+1
adc #0
cmp AliasPages
bcc haveRoom
jsr xmess
.byte cr
asc_hi "*** no room for that alias"
.byte low_cr,0
jmp xerr
haveRoom:
ldy #0
lda (str1),y
tax
bne aNameOK
jsr xmess
.byte cr
asc_hi "*** empty string is not a legal alias"
.byte low_cr,0
jmp xerr
aNameOK: iny
lda (str1),y
jsr CramChar
dex
bne aNameOK
lda #$80+' '
jsr CramChar
ldy #0
lda (str2),y
tax
beq aDefDone
AddDef: iny
lda (str2),y
jsr CramChar
dex
bne AddDef
aDefDone: lda #$0d
jsr CramChar
lda #0
jmp CramChar
;
; CramChar -- append A to (myP)
;
CramChar: sty cramY
ldy #0
sta (myP),y
ldy cramY
inc myP
bne cram_ok
inc myP+1
cram_ok: rts
cramY: .byte 0
;
; FindAlias -- return CLC if found, myP points to it
;
FindAlias:
lda AliasP+1
ldy AliasP
sta myP+1
sty myP
FindA1:
jsr compare
bcc FoundIt
jsr NextAlias
ldy #0
lda (myP),y
bne FindA1
sec
FoundIt: rts
;
; compare--check if alias at myP matches str1, returning
; CLC if they do (and preserving myP)
;
compare:
lda myP+1
pha
lda myP
pha
ldy #0
lda (str1),y
tax
beq NoMatch
iny ;Y=1
jsr decP
cmp1:
lda (str1),y
jsr xdowncase
sta char
jsr FetchChar
and #%01111111
beq NoMatch
jsr xdowncase
cmp char
bne NoMatch
iny
dex
bne cmp1
jsr FetchChar
cmp #$80+' '
bne NoMatch
matches: clc
compared:
pla
sta myP
pla
sta myP+1
rts
NoMatch:
sec
bcs compared
;
; increment myP and return the character it points at
;
FetchChar: inc myP
bne P2ok
inc myP+1
P2ok = *
sty ytemp
ldy #0
lda (myP),y
ldy ytemp
ora #%10000000
rts
ytemp: .res 1
;
; advance myP to next alias
;
NextAlias: jsr FetchChar
cmp #$8d
beq FetchChar
and #%01111111
bne NextAlias
rts
;*************************************************
;
; Remove the alias that myP is pointing at
;
remove_it:
ldy #0
lda (myP),y
beq removed
pha
jsr KillCharP
pla
and #$7f
cmp #$0d
bne remove_it
removed: rts
;
; Kill a character at myP, shifting forward all the
; characters after myP until AliasEnd
;
KillCharP:
lda myP+1
pha
lda myP
pha
KillLoop:
ldy #1
lda (myP),y
dey
sta (myP),y
inc myP
bne p_ok
inc myP+1
p_ok: lda myP+1
cmp AliasEnd+1
bne KillLoop
lda myP
cmp AliasEnd
bne KillLoop
pla
sta myP
pla
sta myP+1
rts
;
; CalcUsedSize--return used bytes in AY,
; myP pointing at the $00 marker at the end
; of the alias data
;
CalcUsedSize:
lda #0
sta count
sta count+1
lda AliasP+1
ldy AliasP
sta myP+1
sty myP
ldy #0
cus1: lda (myP),y
beq cus_done
inc count
bne count_ok
inc count+1
count_ok: inc myP
bne cus1
inc myP+1
bne cus1
cus_done: lda count+1
ldy count
rts
;
decP: lda myP
bne decP1
dec myP+1
decP1: dec myP
rts

47
at.boot.s Normal file
View File

@ -0,0 +1,47 @@
; %help
; at.boot - Boot over AppleTalk.
; %hend
; TODO: If AT is not initialized, then:
; If //e: Find and init workstation card and execute boot if it's not already
; initialized.
; If IIgs: Try Apple IIgs AT boot vectors.
.pc02
.include "davex-mg.inc"
DX_start dx_mg_auto_origin ; load address
DX_info $01,$12,dx_cc_iie_or_iigs,$00
DX_ptab
DX_end_ptab
DX_desc "Reboot over the network."
DX_main
cli ; appletalk requires interrupt
ATcall inforeq
bcs noatalk
ATcall boot
lda #$01
jsr xredirect
jsr xmess
asc_hi "Network boot failed!"
.byte $00
bra errexit
noatalk: lda #$01
jsr xredirect
jsr xmess
asc_hi "AppleTalk offline!"
.byte $00
errexit: lda #$ff
jsr xredirect
jmp xerr
inforeq: .byte 0,2 ; sync GetInfo
.word $0000 ; result code
.dword $00000000 ; completion address
thisnet: .word $0000 ; this network #
abridge: .byte $00 ; local bridge
hwid: .byte $00 ; hardware ID, IIgs only
romver: .word $00 ; ROM version, IIgs only
nodenum: .byte $00 ; node number
boot: .byte $00,$06 ; sync boot
.word $0000 ; result code
DX_end

123
at.info.s Normal file
View File

@ -0,0 +1,123 @@
; %help
; at.info -- Display AppleTalk info.
;
; syntax: at.info
;
; Displays AppleTalk node number, bridge node, and (for IIgs) hardware
; ID and ROM version.
;
; If AppleTalk is offline, will print the slot number of an installed
; Workstation Card.
; %hend
.pc02
.include "davex-mg.inc"
cardptr = xczpage
DX_start $ae00 ; load address
DX_info $01,$12,dx_cc_iie_or_iigs,$00
DX_ptab
DX_end_ptab
DX_desc "Display AppleTalk info."
DX_main
cli ; appletalk requires interrupt
ATcall inforeq
bcs noatalk
lda thisnet
ldy thisnet+1
jsr xprdec_2
jsr xmess
asc_hi "."
.byte $00
lda #$00
ldy nodenum
jsr xprdec_2
ldy abridge
beq :+
phy
jsr xmess
asc_hi ", bridge "
.byte $00
ply
lda #$00
jsr xprdec_2
: lda #$8d
jsr cout
sec
jsr checkmach
bcs :+
; display IIgs specific
jsr xmess
asc_hi "Hardware ID: "
.byte $00
lda #$00
ldy hwid
jsr xprdec_2
jsr xmess
asc_hi ", ROM version "
.byte $00
lda #$00
ldy romver
jsr xprdec_2
lda #$8d
jsr cout
: rts
noatalk: lda #$01
jsr xredirect
jsr xmess
asc_hi "AppleTalk offline!"
.byte $00
jsr FindCard
bcs :+ ; no card
and #$0f ; get slot #
pha
jsr xmess
asc_hi "Workstation Card in slot "
.byte $00
pla
tay
lda #$00
jsr xprdec_2
jsr xmess
.byte $8d,$00
: lda #$ff
jsr xredirect
jmp xerr
.proc FindCard
lda #$f9 ; offset to ID bytes
sta cardptr
lda #$c7 ; start at slot 7
sta cardptr+1
NextSlot: ldy #$03
: lda (cardptr),y
cmp idtbl,y ; check ID byte
bne NoMatch
dey
bpl :-
ldy #$04
lda (cardptr),y
beq NoMatch ; Skip IIgs AppleTalk
cmp #$01 ; Workstation card?
bne NoCard ; nope, something else
clc
lda cardptr+1 ; get slot
rts
NoMatch: dec cardptr+1
lda cardptr+1
cmp #$c0 ;are we finished scanning the slots?
bne NextSlot
NoCard: lda #$00
sec
rts
idtbl: .byte "ATLK" ; msb off
.endproc
inforeq: .byte 0,2 ; sync GetInfo
.word $0000 ; result code
.dword $00000000 ; completion address
thisnet: .word $0000 ; this network #
abridge: .byte $00 ; local bridge
hwid: .byte $00 ; hardware ID, IIgs only
romver: .word $00 ; ROM version, IIgs only
nodenum: .byte $00 ; node number
DX_end

163
at.zones.s Normal file
View File

@ -0,0 +1,163 @@
; %help
; at.zones -- Display AppleTalk zones.
;
; syntax: at.info
;
; Displays local AppleTalk zone and all known zones.
; %hend
.pc02
.include "davex-mg.inc"
sptr = xczpage
altbuf = filebuff3 ; if no dynamic mem avail
altbufsz = $04 ; pages
DX_start dx_mg_auto_origin ; load address
DX_info $01,$12,dx_cc_iie_or_iigs,$00
DX_ptab
DX_end_ptab
DX_desc "Display AppleTalk zones."
DX_main
cli ; appletalk requires interrupts
ATcall inforeq
bcc :+
jmp noatalk
jsr getatbuf ; allocate buffer
sta bufp1+1
sty bufp1
sta bufp2+1
sty bufp2
stx buflen2+1
: lda abridge
sta zbridge ; zone req needs it
ATcall myzone
bcs nozone
lda bufp1+1
sta sptr+1
lda bufp1
sta sptr
ldy #$00
lda (sptr),y
beq nozone
jsr xmess
asc_hi "Local zone: "
.byte $00
jsr prpas
lda #$8d
jsr cout
nozone: ATcall getzones
bcs nozones ; TODO: check for buffer overflow and display what we get
lda numzones+1
ora numzones
beq nozones ; short circuit if no zones
jsr xmess
asc_hi "Zone list:"
.byte $8d,$00
lda bufp2+1 ; set up pointer
sta sptr+1
lda bufp2
sta sptr
przone: ;lda numzones+1
;ldy numzones
;jsr xprdec_2
jsr xmess
asc_hi " "
.byte $00
jsr prpas ; print zone name
lda #$8d
jsr cout
lda numzones
sec
sbc #$01
sta numzones
bcs :+ ; no borrow
dec numzones+1
bit numzones+1 ; set N flag
bmi nozones
: jsr xcheck_wait
bcs nozones
lda numzones
ora numzones+1
beq nozones ; if zero
bra przone
nozones: rts
noatalk: lda #$01
jsr xredirect
jsr xmess
asc_hi "AppleTalk offline!"
.byte $00
exiterr: lda #$ff
jsr xredirect
jmp xerr
; print pascal string at sptr
; leave sptr pointed at one past end
; of string
.proc prpas
ldy #$00
lda (sptr),y ; get length
tax
next: lda sptr
clc
adc #$01
sta sptr
bcc :+
inc sptr+1
: dex
bpl :+
rts
: lda (sptr),y ; get char
ora #$80 ; make printable
jsr cout
bra next
.endproc
; allocate a big buffer for appletalk operations
; returns ay = start, x = size in pages
; tries to use dynamic mem for operations
; otherwise returns altbuf
.proc getatbuf
ldx #mli_read
jsr xmmgr
bcs usealt
cmp #altbufsz
bcc usealt
sta tmp ; save num pages
ldx #mli_open
jsr xmmgr ; allocate all
bcc usealt ; if error
ldx tmp ; get num pages
ldy #$00 ; always on page boundary
rts
usealt: ldy #<altbuf
lda #>altbuf
ldx altbufsz
rts
tmp: .byte $00
.endproc
inforeq: .byte 0,2 ; sync GetInfo
.word $0000 ; result code
.dword $00000000 ; completion address
thisnet: .word $0000 ; this network #
abridge: .byte $00 ; local bridge
hwid: .byte $00 ; hardware ID, IIgs only
romver: .word $00 ; ROM version, IIgs only
nodenum: .byte $00 ; node number
;
myzone: .byte 0,$1a ; sync GetMyZone
.word $0000 ; result
.dword $00000000 ; completion
bufp1: .dword altbuf ; buffer
.byte 4,4 ; 4 times every 1 sec
.word $0000 ; reserved
;
getzones: .byte 0,$1b ; async GetZoneList
.word $0000 ; result
.dword $00000000 ; completion
buflen2: .word altbufsz*$100 ; buffer len
bufp2: .dword altbuf ; buffer
zbridge: .byte $00 ; bridge node
.word $0001 ; start index
.byte 8,16 ; 16 times every 2 secs
numzones: .word $0000 ; num zones returned
.dword $0000000 ; reserved
DX_end

1
boot.dsk Symbolic link
View File

@ -0,0 +1 @@
/Users/lshadow/DavexProDOS.dsk

174
davex-mg.inc Normal file
View File

@ -0,0 +1,174 @@
; MG's davex macros
;
; A skeleton for using this:
; DX_start $a000 ; load address
; DX_info $01,$26,dx_cc_iie_or_iigs,$00
; DX_ptab
; DX_parm 's',t_path
; DX_end_ptab
; DX_desc "My command"
; DX_main
; <code>
; DX_end
;
; *********
.ifdef I_MG_DAVEX
.warning "davex-mg included more than once"
.else
I_MG_MAC = 1
; *********
.include "Common/2/Globals2.asm"
.include "Common/2/MLI.Globals2.asm"
.include "Common/2/Macros2.asm"
cout = $fded ; character out
checkmach = $fe1f ; clears carry on IIgs, no effect on //e
p8_mli = $bf00
mli_atlk = $42
dx_cc_any = 0
dx_cc_40col = 1 << 7
dx_cc_80col = 1 << 6
dx_cc_iie_or_iigs = 1 << 5
dx_cc_iic = 1 << 4
dx_cc_iigs = 1 << 3
dx_cc_bit2 = 1 << 2
dx_cc_bit1 = 1 << 1
dx_cc_bit0 = 1 << 0
dx_mg_auto_origin = 0 ; value for auto origination
; using utils/auto_origin.sh
dx_desc_none = 0
.macro P8call CallNum, PList
jsr p8_mli
.byte CallNum
.addr PList
.endmacro
.macro ATcall PList
P8call mli_atlk, PList
.endmacro
; if the Load address is zero, we don't export X_DX_LOAD
; so that later we can calculate an appropriate start addr
; and let the linker do it.
.macro DX_start Load
.ifdef DID_DX_start
.warning "DX_start used more than once"
.else
.export DID_YOU_DX_end
.export X_DX_MACROS
X_DX_MACROS = 1
.if Load > 0
.org Load
.export X_DX_LOAD
.else
.export X_DX_AUTO_LOAD
X_DX_AUTO_LOAD = 1
.endif
X_DX_LOAD := *
ext_start:
rts
.byte $ee, $ee
DID_DX_start = 1
.endif
.endmacro
.macro DX_info CVer, DXVer, CCs, DAVer
.ifdef DID_DX_start
.byte CVer, DXVer, CCs ; versions and characteristics
.addr X_DX_DESC ; description pointer to pascal str
.addr X_DX_LOAD ; load address
.addr X_DX_EXEC ; exec address
.byte DAVer ; minor version
.byte $00, $00, $00 ; spares
DID_DX_info = 1
.else
.warning "DX_info must happen after DX_start"
.endif
.endmacro
.macro DX_ptab
.ifdef DID_DX_info
; start parameter table
DID_DX_ptab = 1
.else
.warning "DX_ptab must come after DX_info"
.endif
.endmacro
.macro DX_parm Char, Type
.ifdef DID_DX_ptab
.if Char > 0
.byte Char|$80,Type
.else
.byte Char,Type
.endif
.else
.warning "DX_parm must come after DX_ptab"
.endif
.endmacro
.macro DX_end_ptab
.ifdef DID_DX_info
.byte $00,$00
DID_DX_end_ptab = 1
.else
.warning "DX_end_ptab must come after DX_info"
.endif
.endmacro
.macro DX_desc Desc
.ifndef DID_DX_end_ptab
.warning "DX_desc must come after DX_end_ptab"
.endif
X_DX_DESC: .byte .strlen(Desc)
asc_hi Desc
.assert (* - ext_start) < 512, warning, "Description must end in the first 512 bytes"
.endmacro
.macro DX_main
X_DX_EXEC = *
.endmacro
.macro DX_end
.ifndef DID_DX_start
.error "DX_start not used"
.endif
X_DX_END = *
X_DX_SIZE = X_DX_END - X_DX_LOAD
DID_YOU_DX_end = 1
.ifndef DID_DX_info
.error "DX_info not used"
.endif
.ifndef X_DX_EXEC
.error "DX_main not used"
.endif
.ifndef X_DX_DESC
.out "Note: no DX_end_ptab used, hope that's okay"
.endif
.ifndef X_DX_DESC
.out "Note: no description provided"
X_DX_DESC := 0
.endif
.ifndef X_DX_AUTO_LOAD
.out .sprintf("Code ends at $%x, size $%x", X_DX_END, X_DX_SIZE)
.assert * < $b000, error, "Code is past $b000!"
.if * < $af00
.out "Consider moving code start to place end shortly before $b000"
.out .sprintf("Perhaps at $%x", ($b000-X_DX_SIZE)&$ff00)
.endif
.else
.out .sprintf("Auto load address, size $%x", X_DX_SIZE)
.endif
.endmacro
; *********
.endif
; *********

1321
deschw.s Normal file

File diff suppressed because it is too large Load Diff

48
dmem.s Normal file
View File

@ -0,0 +1,48 @@
; %help
; dmem -- Display davex dynamic memory info.
;
; syntax: dmem
; %hend
.pc02
.include "davex-mg.inc"
DX_start dx_mg_auto_origin ; load address
DX_info $01,$12,dx_cc_any,$00
DX_ptab
DX_end_ptab
DX_desc "Display DaveX dynamic memory info."
DX_main
jsr xmess
asc_hi "Dynamic memory available to external cmds:"
.byte $8d,$8d,00
ldx #mli_close ; free all
jsr xmmgr ; ask for it
; fall-through
.proc showfree
ldx #mli_read ; num free pages
jsr xmmgr ; ask for it
pha
tay
lda #$00
jsr xprdec_2
jsr xmess
asc_hi " page"
.byte $00
pla
tay
lda #$00
jsr xplural
jsr xmess
asc_hi " free"
.byte $8d
asc_hi "Lowest page: $"
.byte $00
ldx #mli_gfinfo ; lowest free page
jsr xmmgr
jsr $fdda ; prbyte
jsr xmess
.byte $8d,00
rts
.endproc
DX_end

214
idemu.s Normal file
View File

@ -0,0 +1,214 @@
; %help
; idemu -- Identify emulator.
;
; syntax: idemu
;
; Uses official ways of detecting emulators if possible, otherwise uses the
; various idiosyncrasies that many emulators have regarding the ROM or I/O
; pages.
; %hend
.p02
.include "davex-mg.inc"
temp0 = xczpage
DX_start dx_mg_auto_origin ; load address
DX_info $02,$12,dx_cc_any,$00
DX_ptab
DX_end_ptab
DX_desc "Identify emulator."
DX_main
;rts
jsr idemu
; bcs noemu
stx temp0
jsr xprint_path
lda temp0
beq :+
jsr xmess
asc_hi ", version "
.byte $00
lda temp0
jsr xprint_ver
: jsr xmess
.byte $8d,$00
rts
; identify emulator
; return cs if no emulator found
; return cc if one is found
; ay = name pointer (even for none), x = version (if nonzero)
.proc idemu
lda #$00
sta emuver
sec
jsr $fe1f
bcc doemub ; skip the BS if it claims to be a GS
; okay, let's check for some obvious things first
lda $fbb3
cmp #$06 ; Apple IIe or better
bne :+
lda $fbdd
cmp #$02 ; PDS card or IIe for classic MacOS
bne :+
lda $fbde
cmp #$40 ; IIe for classic MacOS
bne iiecard
ldy #<emIIe
lda #>emIIe
bne foundemu1
iiecard: lda $fbbe
sta emuver
ldy #<emPDS
lda #>emPDS
bne foundemu1
: jmp doemub ; fall back to emubyte
;
; Routine to handle emulator detected, but emubyte=$00
zeroid: sec
jsr $fe1f ; is GS?
bcs :+
ldy #<emGus ; assume Gus if GS and ID 0
lda #>emGus
bne foundemu1
; check for Virtual II
: ldy #$00
ldx #$10 ; loop to check for Virtual ][
viilp: lda $c04f
and #$b0
cmp #$b0 ; VII has mostly this here
bne :+
iny
: dex
bne viilp
cpy #$0d ; more than 14 $Bx?
bcc :+ ; nope
stx emuver ; zero version
ldy #<emVII
lda #>emVII
bne foundemu1
; check for Apple IIjs or jse
; which always have zeros from $c001-$c00f
: lda #$00
ldx #$0f
jslp: lda $c000,x
bne :+
dex
bne jslp
stx emuver
ldy #<emJS
lda #>emJS
bne foundemu1
: jmp unkemu
; Routine to identify by emubyte value if possible
doemub: jsr getemub
bne noemu
cmp #$00 ; yes this is needed
beq zeroid ; do zero identification
cmp #$ad ; Catakig always has this in $c04f
bne :+
lda #$00
sta emuver ; catakig doesn't have a version byte
ldy #<emCatak
lda #>emCatak
foundemu1:
jmp foundemu
: cmp #$fe ; Bernie
bne :+
ldy #<emBernie
lda #>emBernie
bne foundemu
: cmp #$16 ; Sweet 16
bne :+
ldy #<emS16
lda #>emS16
bne foundemu
: cmp #$47 ; GSport
bne :+
ldy #<emGSport
lda #>emGSport
bne foundemu
: cmp #$4b ; KEGS
bne :+
ldy #<emKEGS
lda #>emKEGS
bne foundemu
: cmp #$ab ; AppleBlossom
bne :+
ldy #<emAB
lda #>emAB
bne foundemu
: ; well, ID byte didn't match a known emu
; but we don't have floating bus at $c04f
; so it must be an emulator
unkemu: lda emubyte
jsr setemub
ldy #<emUnk
lda #>emUnk
foundemu: ldx emuver
clc
rts
noemu: ldy #<emNone
lda #>emNone
ldx #$00
sec
rts
; get emubyte and version if possible
; returns with z clear if floating bus found instead
; if z set, a has emubute and y has emuver
; which are also saved in memory
getemub: sta $c04f ; de-facto standard among IIgs emulators
lda $c04f ; program ID
ldy $c04f ; version
sta emubyte
sty emuver
ldx #$ff ; now check ID again 255 times
: sta $c04f
lda $c04f
cmp emubyte ; floating bus gonna float
bne :+ ; and if it does, we gotta nope
dex
bne :-
: rts
; set emubyte in unknown entry, enter with a = emubyte
setemub: sed ; decimal mode trick for hex->ascii
tax ; save it
and #$0f ; low nibble
cmp #$0a
adc #$30
ora #$80 ; to Apple II
sta unkemub+1
txa
lsr ; high nibble
lsr
lsr
lsr
cmp #$0a
adc #$30
ora #$80
sta unkemub
cld
rts
; ***
emubyte: .byte $00
emuver: .byte $00
; ***
emNone: pstr_hi "None identified"
emUnk: pstr_hi "Unknown, emubyte = $XX"
unkemub = *-2
emPDS: pstr_hi "Apple IIe Card"
emVII: pstr_hi "Virtual ]["
emIIe: pstr_hi "IIe"
emGus: pstr_hi "Gus (probably)"
emCatak: pstr_hi "Catakig"
emBernie: pstr_hi "Bernie ][ the Rescue"
emS16: pstr_hi "Sweet 16"
emGSport: pstr_hi "GSport"
emKEGS: pstr_hi "KEGS"
emAB: pstr_hi "AppleBlossom"
emJS: pstr_hi "Apple IIjs or jse"
.endproc
DX_end

163
iie.card.s Normal file
View File

@ -0,0 +1,163 @@
; %help
; iie.card -- Display info about or control the Apple //e Card for Mac LC.
;
; options:
; -s <num> Set speed, 0 = normal (1 MHz), 1 = fast (1.9 MHz),
; anything else = option panel speed
; -x Show experimental info, uses undocumented features.
; %hend
curspeed = xczpage
.pc02
.include "davex-mg.inc"
DX_start dx_mg_auto_origin ; load address
DX_info $01,$12,dx_cc_iie_or_iigs,$00
DX_ptab
DX_parm 's',t_int1 ; set speed (0 = normal, 1 = fast, others = default)
DX_parm 'x',t_nil ; experimental info
DX_end_ptab
DX_desc "Control Apple //e LC PDS Card."
DX_main
; davex has already identified the machine as a //e or IIgs
sec
jsr checkmach ; see if IIgs
bcs :+ ; not a IIgs
badiie: lda #$01
jsr xredirect
jsr xmess
asc_hi "This program requires the Apple //e Card for Macintosh LC!"
.byte $8d,$00
exiterr: lda #$ff
jsr xredirect
jmp xerr
: lda $fbc0 ; check for enhanced monitor
cmp #$e0 ; $e0 = enhanced
bne badiie
lda $fbdd ; //e Card ID byte
cmp #$02
bne badiie
lda #'s'|$80 ; set speed?
jsr xgetparm_ch
bcs doinfo
jsr setspeed
jmp dispspeed
doinfo: jsr dispinfo
lda #'x'|$80 ; experimental?
jsr xgetparm_ch
bcs :+
jsr dispslot
: jsr dispspeed
rts
.proc dispinfo
jsr xmess
asc_hi "Card revision: "
.byte $00
ldy $fbbe
iny
lda #$00
jsr xprdec_2
jsr xmess
.byte $8d,$00
rts
.endproc
.proc dispspeed
jsr xmess
asc_hi "CPU speed: "
.byte $00
lda $c02b
and #%00000100 ; bit 2 = CPU speed
sta curspeed
jsr speedmsg
lda $c05c
and #%00000100 ; bit 2 = option panel speed
cmp curspeed
beq done
pha
jsr xmess
asc_hi " (option panel: "
.byte $00
pla
jsr speedmsg
jsr xmess
asc_hi ")"
.byte $00
done: jsr xmess
.byte $8d,$00
rts
.endproc
.proc speedmsg
bne fast
jsr xmess
asc_hi "normal"
.byte $00
rts
fast: jsr xmess
asc_hi "fast"
.byte $00
rts
.endproc
.proc setspeed
cpy #$00
beq norm ; set normal
dey
beq fast
lda $c05c
and #%00000100 ; bit 2 = option panel speed
beq norm
fast: lda #%00000100
ora $c02b
store: sta $c02b
rts
norm: lda #%11111011
and $c02b
bra store
.endproc
.proc dispslot
jsr xmess
asc_hi "Startup slot: "
.byte $00
.byte $02,$02 ; magic trick 1
cmp #$c8
beq chkscan
prslot: and #$0f
tay
dey
lda #$00
jsr xprdec_2
done: jsr xmess
.byte $8d,$00
rts
chkscan: lda #$c6 ; see if slot 7 is picked, less likely than scan
.byte $02,$03 ; magic trick 2, introduces a visual anomaly if slot 7
bne prscan
; the following is to fix the screen up after it prints
; "UNABLE TO BOOT FROM STARTUP SLOT"
; if slot 7 is selected.
lda $28 ; save BASL
pha
lda $29 ; save BASH
pha
ldx #23 ; row 23
: txa
jsr $fbc1 ; bascalc, preserves x
ldy #39
: lda ($28),y ; read char from screen via BASL/BASH
sta ($28),y ; write back, clearing message
dey
bpl :- ; if line not done
dex
bpl :-- ; if screen not done
pla
sta $29 ; restore BASH
pla
sta $28 ; restore BASL
lda #$c8 ; slot 7+1
bne prslot
prscan: jsr xmess
asc_hi "scan"
.byte $00
bra done
.endproc
DX_end

312
mig.insp.s Normal file
View File

@ -0,0 +1,312 @@
; %help
; mig.insp -- MIG Inspector by M.G., davex version
;
; Displays the MIG RAM from the Apple IIc Plus this is used by the 3.5 drive
; firmware and the accelerator.
;
; When run, 4 pages of the MIG RAM are displayed at a time. If a dynamic
; buffer is allocated, its address is placed on the screen in the lower-right
; corner.
;
; Keys:
; Arrows - change pages in view
; 0 - 9 - jump to page n*7, 0 = page 0, 9 = page 63
; ESC - quit
; ~ - Jump to page 0 and copy all 2K of the MIG to the buffer, if it's big
; enough. Beeps if not.
; %hend
; Technical:
; The MIG is briefly mentioned in the Apple IIc
; Techincal Reference 2nd Edition. It gives the
; pinouts of the chip and general function description
; but not the level of detail we are used to for Apple
; II technical manuals.
; I wanted to see what was behind the smoke and mirrors.
; The MIG RAM is a 2K SRAM that is accessed through
; a small window from $CE00-$CFFF (and $DE00-$DFFF)
; when the alternate firmware bank is active.
; 32 bytes of MIG RAM are accessed in 64 pages, with
; $CEA0 resetting to page 0, and $CE20 incrementing it
; All but page 2 is used by the 3.5 code. Page 2 is
; used by the accelerator code.
; Other locations in the MIG window are likely used to
; control the 3.5 drive control signals that the MIG
; outputs.
.pc02
.code
.include "davex-mg.inc"
; build options
SKIPROMID = 1 ; skip ROM identification
; lets you use on a non-
; IIc Plus, but obviously
; isn't useful beyond some
; testing purposes
; Our authorized zero page storage
BufFlag = xczpage ; if $FF, have big buffer
BufLoc = BufFlag+1
BufPtr = BufLoc+2
MigPage = BufPtr+2
; entry points
COut1 = $fdf0
TabV = $fb5b
PrByte = $fdda
Home = $fc58
VTab = $fc22
;KeyIn = $fd1b ; do not use for davex
PrntAX = $f941
; locs
CH = $24
CV = $25
AltBuffer = filebuff3 ; if we can't get big buffer
ROMBank = $c028
MigBase = $ce00
MigRAM = MigBase
MigPage0 = MigBase+$A0
MigPageI = MigBase+$20
DX_start dx_mg_auto_origin ; load address
.if SKIPROMID
DX_info $01,$12,dx_cc_any|dx_cc_40col,$00
.else
DX_info $01,$12,dx_cc_iic|dx_cc_40col,$00
.endif
DX_ptab
DX_end_ptab
DX_desc "Display MIG RAM."
DX_main
cld
.if SKIPROMID
bra init
.else
lda $fbbf ; davex says it's a //c already
cmp #$05 ; but is it a IIc Plus?
beq init ; all good!
lda #$01
jsr xredirect
jsr xmess
asc_hi "Requires a IIc Plus!"
.byte $00
.endif
exiterr: lda #$ff
jsr xredirect
jmp xerr
init: stz MigPage
stz BufFlag
lda #<AltBuffer
sta BufLoc
lda #>AltBuffer
sta BufLoc+1
ldx #mli_read
jsr xmmgr
cmp #$08 ; 8 pages available?
bcc :+ ; nope
lda #$08
ldx #mli_open
jsr xmmgr
bcs :+ ; shouldn't happen
stz BufLoc
sta BufLoc+1
dec BufFlag ; flag it
: ; moving on...
; davex does the below for us
;lda #$91
;jsr COut1 ; go to 40 cols if 80 col firmware active
jsr Home
lda #21
jsr TabV
jsr xmess
asc_hi "Arrows=Page, 0-9=Jump, ESC=Quit"
.byte $8d,$8d
asc_hi "MIG Inspector by M.G. 08/30/2017 "
.byte $00
bit BufFlag
bpl dispmig ; Don't print addr if using AltBuffer
lda #'@'|$80
jsr COut1
ldx BufLoc ; display buffer location
lda BufLoc+1
jsr PrntAX
dispmig: jsr get4mig ; 4 mig pages to buffer
jsr d4page
uinput: lda #' '+$80
jsr xrdkey ; davex read key
cmp #$8b ; up arrow
beq goup
cmp #$8a ; down arrow
beq godn
cmp #$88 ; left arrow
bne :+
goup: dec MigPage
bra dispmig
: cmp #$95 ; right arrow
bne :+
godn: inc MigPage
bra dispmig
: cmp #'~'+$80 ; tilde - git all MIG RAM to buffer, maybe
bne :+
jsr getallmig
bra dispmig
: cmp #$9b ; escape
bne jump
rts
jump: sbc #$b0 ; check for digit for page jump
bmi uinput ; nope
cmp #10 ; 10 or bigger?
bcs uinput ; also nope
sta MigPage ; compute digit * 7
asl ; * 2
asl ; * 4
asl ; * 8
sec
sbc MigPage ; * 7
sta MigPage
bra dispmig
; display 4 MIG pages on screen
.proc d4page
jsr rsetbptr
lda #$00
jsr TabV
ldx #$00
: stz CH
txa
clc
adc MigPage
and #$3f
jsr PrByte
lda #':'+$80
jsr COut1
jsr d4line
inc CV
jsr VTab
inx
cpx #$04
bne :-
rts
.endproc
; display 4 lines at BufPtr, inc bufptr as we go
; assume CV is where we want it to be
.proc d4line
phx
ldx #$03
: jsr dline
inc CV
jsr VTab
lda #$08
jsr addbptr
dex
bpl :-
plx
rts
.endproc
; display 1 line at BufPtr
.proc dline
lda #4
sta CH
ldy #$00 ; start hex display
: lda (BufPtr),y
jsr PrByte
lda #' '+$80
jsr COut1
iny
cpy #$08 ; done?
bne :- ; nope, next hex
ldy #$00 ; start ASCII display
: lda (BufPtr),y
ora #$80
cmp #' '+$80 ; space
bcs :+ ; if not ctrl char
lda #'.'+$80 ; if so, use dot
: jsr COut1
iny
cpy #$08 ; done?
bne :-- ; nope, next ASCII
rts
.endproc
; reset buffer BufPtr
.proc rsetbptr
pha
lda BufLoc
sta BufPtr
lda BufLoc+1
sta BufPtr+1
pla
rts
.endproc
; add A to buffer BufPtr
.proc addbptr
clc
adc BufPtr
bcc done
inc BufPtr+1
done: sta BufPtr
rts
.endproc
; copy all mig pages (2048 bytes) to (bufptr)
.proc getallmig
bit BufFlag
bmi :+
jsr xbell
rts
: stz MigPage
ldx #$3f
bra getxmig
.endproc
; copy 4 mig pages (128 bytes) to (bufptr)
.proc get4mig
ldx #$03
; fall through
.endproc
; copy x mig pages (x*32 bytes) to (bufptr)
.proc getxmig
lda MigPage
and #$3f ; enforce range
sta MigPage
sta ROMBank ; mig only visible when alt ROM switched in
jsr setmigpg
jsr rsetbptr
: jsr copymig
lda #$20
jsr addbptr ; next buffer segment
bit MigPageI ; next MIG page
dex
bpl :-
sta ROMBank
rts
.endproc
; copy one mig page (32 bytes) to (bufptr)
.proc copymig
phy
ldy #$1f
: lda MigRAM,y
sta (BufPtr),y
dey
bpl :-
ply
rts
.endproc
; set MIG page
.proc setmigpg
phx
bit MigPage0
ldx MigPage
beq done
: bit MigPageI
dex
bne :-
done: plx
rts
.endproc
DX_end

426
nbp.lookup.s Normal file
View File

@ -0,0 +1,426 @@
; %help
; nbp.lookup [nbp-name]
;
; Perform NBP lookups.
;
; options:
; nbp-name Optional, name or partial name to lookup.
;
; -v Verbose mode, prints query and zone
; info.
;
; Returns a list of addresses and associated NBP entries.
; or "No results." if none found.
; %hend
.pc02 ; appletalk requires it anyway
.include "davex-mg.inc"
ch = $24 ; cursor horizontal pos
sptr = xczpage
sptr2 = sptr+2
stemp = sptr2+2
verbose = stemp+1 ; flag to show zone
zonebuf = filebuff2 ; for local zone name
namebuf = zonebuf+$0100 ; for building NBP name for lookup req
altbuf = filebuff3 ; used if no dynamic mem avail
altbufsz = $04 ; pages
DX_start dx_mg_auto_origin ; load address
DX_info $02,$12,dx_cc_iie_or_iigs,$00
DX_ptab
DX_parm $00,t_string ; name
DX_parm 'v',t_nil ; verbose
DX_end_ptab
DX_desc "Perform AppleTalk NBP lookups."
DX_main
cli ; appletalk requires interrupts
ATcall inforeq
bcc :+
jmp noatalk ; commented for debug
: jsr getatbuf ; allocate buffer
sta bufp+1
sty bufp
stx buflen+1
; process command line parms
stz verbose
lda #'v'|$80 ; verbose
jsr xgetparm_ch
bcs :+
inc verbose
: lda #<namebuf
sta sptr
lda #>namebuf
sta sptr+1
; get name
lda #$00
jsr xgetparm_n
ldx #$80 ; name, return wildcard if not given
jsr get_nbp
bcs badnbp1
inx
txa
jsr addsptr
; get type
lda #$00
jsr xgetparm_n
ldx #$81 ; type, return wildcard if not given
jsr get_nbp
badnbp1: bcs badnbp
inx
txa
jsr addsptr
; get zone
lda #$00
jsr xgetparm_n
ldx #$82 ; type, return * if not given
jsr get_nbp
bcs badnbp
; sptr points at where we put the zone
ldy #$01
lda (sptr),y
cmp #'*' ; were we given it?
bne doit
; get local zone if possible
ATcall myzone
bcs doit ; error, just stick with what we got
lda zonebuf ; if none
beq doit ; attempt with default value
ldx #<zonebuf ; copy returned zone in place of what we have
lda #>zonebuf
ldy #$00
jsr copystr
; now we have a complete name to look up
; rts ; DEBUG
doit: lda #<namebuf
sta sptr
lda #>namebuf
sta sptr+1
lda verbose
beq :+ ; don't print unless verbose
jsr prnbptup
jsr xmess
.byte $8d,$00
: ATcall lkupreq
bcc :+
jmp error ; TODO: check for buffer overflow and display what we get
: lda matches
bne :+
jsr xmess
asc_hi "No results."
.byte $8d,$00
rts
: lda bufp+1 ; set up pointer to response buffer
sta sptr+1
lda bufp
sta sptr
prent: ;lda #$00 ; this and next 2 debugging
;ldy matches
;jsr xprdec_2
jsr prnbpent
jsr xcheck_wait
bcs :+ ; if user pressed escape
dec matches
bne prent
: rts
badnbp: lda #$01
jsr xredirect
jsr xmess
asc_hi "Bad name."
.byte $00
bra exiterr
noatalk: lda #$01
jsr xredirect
jsr xmess
asc_hi "AppleTalk offline!"
.byte $00
exiterr: lda #$ff
jsr xredirect
error: jmp xerr
;
; ***
; get_nbp - get part of a name at ay and copy to sptr
; x = 0:name 1:type 2:zone, +$80 sub wildcard or default if none given
; return: (sptr) = string, x = length of it
.proc get_nbp
sty sptr2
sta sptr2+1
stx stemp
ldy #$00
sty colon ; init these
sty at
lda sptr ; copy sptr to self-modifying wrtdest
sta wrtdest+1
lda sptr+1
sta wrtdest+2
jsr incdest ; and move to first char position
lda (sptr2),y ; length
beq notfound ; zero, just give up
sta end
; find the delimiters
tay
: lda (sptr2),y
cmp #':'
bne notcolon
sty colon
notcolon: cmp #'@'
bne nxtdelim
sty at
nxtdelim: dey
bne :-
; now make sure that if @ is given, it is after :
lda at
beq :+
cmp colon
bcc bad
; now get the part requested
: lda stemp
and #$7f
beq getname
cmp #$01
beq gettype
getzone: ldy at
beq notfound
cpy end
beq notfound
; need to copy from at(+1) to end
docopy: ldx #$00
: iny
lda (sptr2),y
jsr wrtdest
cpy end ; was that the last char
bcc :- ; nope, next char
ldy #$00
txa
sta (sptr),y ; save copied length
clc
rts ; and return
getname: ldy colon
bne :+
ldy at
beq :++
: dey
sty end
: ldy end
beq notfound
ldy #$00 ; initially at pos 0
; need to copy from pos 1 to end
beq docopy ; always
gettype: ldy colon
beq notfound ; early out if no colon
cpy end
beq notfound
ldy at
beq :+ ; use end as-is
dey ; otherwise end at pos before @
sty end
: ldy colon
; need to copy from colon(+1) to end
bne docopy ; should be always
notfound: lda stemp
and #$80
bne :+ ; if client asked for a default
lda #$00
tay
tax ; x is officially length of string result
sta (sptr),y ; put a zero in destination
bad: sec ; tell client we gave an empty string
rts
: ldx #$01 ; length of default
ldy #$00
txa
sta (sptr),y
iny
lda stemp
cmp #$82 ; want default zone? ('*')
bne :++ ; nope
lda #'*'
: sta (sptr),y
clc
rts
: lda #'=' ; wildcard for name or type
bne :-- ; always
wrtdest: sta $ffff
inx ; inc count of copied chars
incdest: inc wrtdest+1
bne :+
inc wrtdest+2
: rts
colon: .byte $00
at: .byte $00
end: .byte $00
.endproc
; print an NBP entry at sptr
.proc prnbpent
ldy #$00 ; offset into entry, net number low byte
lda (sptr),y ; big end of network num
pha
iny
lda (sptr),y
tay
pla
jsr xprdec_2
jsr xmess
asc_hi "."
.byte $00
; print node
ldy #$02
lda (sptr),y
tay
lda #$00
jsr xprdec_2
jsr xmess
asc_hi ":"
.byte $00
; print socket
ldy #$03
lda (sptr),y
tay
lda #$00
jsr xprdec_2
jsr xmess
asc_hi " " ; print space in case output is not to screen.
.byte $00
lda #20 ; Position NBP tuple on screen.
sta ch
lda #$05 ; offset to NBP tuple
jsr addsptr
jsr prnbptup
jsr xmess ; CR
.byte $8d,$00
rts
.endproc
; print an NBP tuple at sptr
; leave sptr at byte just after tuple
.proc prnbptup
; print name
jsr prpas
jsr xmess
asc_hi ":"
.byte $00
; print type
jsr prpas
lda verbose
beq skipzone ; if not verbose, don't display @zone
jsr xmess
asc_hi "@"
.byte $00
; print zone
jsr prpas
bra :+
skipzone: ldy #$00
lda (sptr),y ; get length of zone name
inc a ; account for length byte
jsr addsptr ; and skip the lot
: rts ; done
.endproc
; increment sptr by a
.proc addsptr
clc
adc sptr
sta sptr
bcc :+
inc sptr+1
: rts
.endproc
; print pascal string at sptr
; leave sptr pointed at one past end
; of string
.proc prpas
ldy #$00
lda (sptr),y ; get length
tax
next: lda #$01
jsr addsptr
dex
bpl :+
rts
: lda (sptr),y ; get char
ora #$80 ; make printable
jsr cout
bra next
.endproc
; copy a pascal string to sptr offset by y
; a,x = source
; return: y = new offset after copied str
.proc copystr
sta sptr2+1
stx sptr2
sty stemp ; save offset
ldy #$00
lda (sptr2),y ; get number of chars
tax ; to copy
ldy stemp ; get the offset
sta (sptr),y ; store the length byte
inc stemp ; increment the offset
inc sptr2 ; next source char
bne :+
inc sptr2+1
: ldy #0
; copy loop
: phy
lda (sptr2),y
ldy stemp
sta (sptr),y
inc stemp
ply
iny
dex
bne :-
ldy stemp
rts
.endproc
; allocate a big buffer for appletalk operations
; returns ay = start, x = size in pages
; tries to use dynamic mem for operations
; otherwise returns altbuf, which should usually
; be one of the file buffers.
.proc getatbuf
ldx #mli_read
jsr xmmgr
bcs usealt
cmp #altbufsz
bcc usealt
sta tmp ; save num pages
ldx #mli_open
jsr xmmgr ; allocate all
bcc usealt ; if error
ldx tmp ; get num pages
ldy #$00 ; always on page boundary
rts
usealt: ldy #<altbuf
lda #>altbuf
ldx altbufsz
rts
tmp: .byte $00
.endproc
;
inforeq: .byte 0,2 ; sync GetInfo
.word $0000 ; result code
.dword $00000000 ; completion address
thisnet: .word $0000 ; this network #
abridge: .byte $00 ; local bridge
hwid: .byte $00 ; hardware ID, IIgs only
romver: .word $00 ; ROM version, IIgs only
nodenum: .byte $00 ; node number
;
myzone: .byte 0,$1a ; sync GetMyZone
.word $0000 ; result
.dword $00000000 ; completion
.dword zonebuf ; buffer, needs at least 33 bytes
.byte 4,4 ; 4 times every 1 sec
.word $0000 ; reserved
;
lkupreq: .byte 0,$10 ; sync LookupName
.word $0000 ; result
.dword $00000000 ; completion
.dword namebuf ; name pointer
.byte 4,4 ; 4 times every 1 sec
.word $0000 ; reserved
buflen: .word $0000 ; buffer length
bufp: .dword $00000000 ; buffer pointer
.byte $ff ; max # matches
matches: .byte $00 ; actual matches
DX_end

235
nbp.parse.s Normal file
View File

@ -0,0 +1,235 @@
; %help
; nbp.parse <name> - parse and output parts of NBP <name>
;
; options: -s Substitute defaults for unspecified portions.
; %hend
.pc02
.include "davex-mg.inc"
ch = $24 ; cursor horizontal pos
sptr = xczpage
sptr2 = sptr+2
stemp = sptr2+2
mode = stemp+1
namebuf = filebuff2
DX_start dx_mg_auto_origin
DX_info $01,$12,dx_cc_iie_or_iigs,$00
DX_ptab
DX_parm $00,t_string ; NBP name to parse
DX_parm 's',t_nil ; if given, sub defaults
DX_end_ptab
DX_desc "Parse AppleTalk NBP names."
DX_main
lda #$00
sta mode
lda #'s'+$80
jsr xgetparm_ch
bcs :+
lda #$80
sta mode
: jsr setsptr
lda #$00
jsr xgetparm_n
ldx mode
jsr get_nbp
php
phx
ply
lda #$00
jsr xprdec_2
jsr xmess
.byte ' '+$80,$00
plp
bcc printv
lda #<nonestr
sta sptr
lda #>nonestr
sta sptr+1
printv: jsr prpas
jsr xmess
.byte $8d,$00
next: inc mode
lda mode
and #$7f
cmp #$03
bcc :-
rts
setsptr: lda #<namebuf
sta sptr
lda #>namebuf
sta sptr+1
rts
nonestr: .byte 6,"(none)"
; ***
; get_nbp - get part of a name at ay and copy to sptr
; x = 0:name 1:type 2:zone, +$80 sub wildcard or default if none given
; return: (sptr) = string, x = length of it
.proc get_nbp
sty sptr2
sta sptr2+1
stx stemp
ldy #$00
sty colon ; init these
sty at
lda sptr ; copy sptr to self-modifying wrtdest
sta wrtdest+1
lda sptr+1
sta wrtdest+2
jsr incdest ; and move to first char position
lda (sptr2),y ; length
beq notfound ; zero, just give up
sta end
; find the delimiters
tay
: lda (sptr2),y
cmp #':'
bne notcolon
sty colon
notcolon: cmp #'@'
bne nxtdelim
sty at
nxtdelim: dey
bne :-
; now make sure that if @ is given, it is after :
lda at
beq :+
cmp colon
bcc bad
; now get the part requested
: lda stemp
and #$7f
beq getname
cmp #$01
beq gettype
getzone: ldy at
beq notfound
cpy end
beq notfound
; need to copy from at(+1) to end
docopy: ldx #$00
: iny
lda (sptr2),y
jsr wrtdest
cpy end ; was that the last char
bcc :- ; nope, next char
ldy #$00
txa
sta (sptr),y ; save copied length
clc
rts ; and return
getname: ldy colon
bne :+
ldy at
beq :++
: dey
sty end
: ldy end
beq notfound
ldy #$00 ; initially at pos 0
; need to copy from pos 1 to end
beq docopy ; always
gettype: ldy colon
beq notfound ; early out if no colon
cpy end
beq notfound
ldy at
beq :+ ; use end as-is
dey ; otherwise end at pos before @
sty end
: ldy colon
; need to copy from colon(+1) to end
bne docopy ; should be always
notfound: lda stemp
and #$80
bne :+ ; if client asked for a default
lda #$00
tay
tax ; x is officially length of string result
sta (sptr),y ; put a zero in destination
bad: sec ; tell client we gave an empty string
rts
: ldx #$01 ; length of default
ldy #$00
txa
sta (sptr),y
iny
lda stemp
cmp #$82 ; want default zone? ('*')
bne :++ ; nope
lda #'*'
: sta (sptr),y
clc
rts
: lda #'=' ; wildcard for name or type
bne :-- ; always
wrtdest: sta $ffff
inx ; inc count of copied chars
incdest: inc wrtdest+1
bne :+
inc wrtdest+2
: rts
colon: .byte $00
at: .byte $00
end: .byte $00
.endproc
; increment sptr by a
.proc addsptr
clc
adc sptr
sta sptr
bcc :+
inc sptr+1
: rts
.endproc
; print pascal string at sptr
; leave sptr pointed at one past end
; of string
.proc prpas
ldy #$00
lda (sptr),y ; get length
tax
next: lda #$01
jsr addsptr
dex
bpl :+
rts
: lda (sptr),y ; get char
ora #$80 ; make printable
jsr cout
bra next
.endproc
; copy a pascal string to sptr offset by y
; a,x = source
; return: y = new offset after copied str
.proc copystr
sta sptr2+1
stx sptr2
sty stemp ; save offset
ldy #$00
lda (sptr2),y ; get number of chars
tax ; to copy
ldy stemp ; get the offset
sta (sptr),y ; store the length byte
inc stemp ; increment the offset
inc sptr2 ; next source char
bne :+
inc sptr2+1
: ldy #0
; copy loop
: phy
lda (sptr2),y
ldy stemp
sta (sptr),y
inc stemp
ply
iny
dex
bne :-
ldy stemp
rts
.endproc
DX_end

483
tardis.s Normal file
View File

@ -0,0 +1,483 @@
; %help
; tardis - Get date/time from TimeLord server.
;
; options:
; -v Verbose mode, prints server info.
; -n <nbp-name> Specify NBP query, default =:TimeLord@*
; -p Set ProDOS global page date/time.
; -s <type> Set a clock of <type>, current supported
; types: none.
; %hend
.pc02
.include "davex-mg.inc"
ch = $24 ; cursor horizontal pos
entname = filebuff2 ; buffer to build NBP entity name
NBPBuf = filebuff3 ; buffer for NBP request
NBPBufSz = $0400 ; size of the file buffer
P8DtTm = $bf90
sptr = xczpage
sptr2 = sptr+2
stemp = sptr2+2
verbose = stemp+1 ; verbose flag
DX_start dx_mg_auto_origin ; load address
DX_info $01,$12,dx_cc_iie_or_iigs,$00
DX_ptab
DX_parm 'v',t_nil ; verbose
DX_parm 'n',t_string ; name
DX_parm 'z',t_string ; zone
DX_parm 'p',t_nil ; set prodos time
DX_parm 's',t_string ; set clock
DX_end_ptab
DX_desc "Get time from TimeLord server."
DX_main
cli ; appletalk requires interrupts
ATcall inforeq
bcc :+
jmp noatalk
: stz verbose
lda #'v'|$80 ; verbose
jsr xgetparm_ch
bcs :+
inc verbose
: lda #<entname
sta sptr
lda #>entname
sta sptr+1
; get name
lda #'n'|$80 ; NBP name param
jsr xgetparm_ch
bcc :+ ; was specified
; name param not given, use default
lda #<entname
sta sptr
lda #>entname
sta sptr+1
ldy #$00
ldx #<defname
lda #>defname
jsr copystr
ldx #<deftype
lda #>deftype
jsr copystr
ldx #<defzone
lda #>defzone
jsr copystr
jmp doit
: ldx #$80 ; name, return wildcard if not given
jsr get_nbp
bcs badnbp
inx
txa
jsr addsptr
; get type
lda #'n'|$80
jsr xgetparm_ch
ldx #$01 ; type, return empty if not given
jsr get_nbp
bcc :+
ldy #$00
ldx #<deftype
lda #>deftype
jsr copystr
tya
bra :++ ; to addsptr
: inx
txa
: jsr addsptr
; get zone
lda #'n'+$80
jsr xgetparm_ch
ldx #$82 ; zone, return * if not given
jsr get_nbp
bcc doit
badnbp: lda #$01
jsr xredirect
jsr xmess
asc_hi "Bad NBP name."
.byte $00
bra exiterr1
doit: lda #<entname
sta sptr
lda #>entname
sta sptr+1
lda verbose
beq :+ ; don't print unless verbose
jsr prnbptup
jsr xmess
.byte $8d,$00
; Locate TimeLord on network
: ATcall lookup
bcc :+ ; no error, don't bail
notlord: lda #$01
jsr xredirect
jsr xmess
asc_hi "No TimeLord found!"
.byte $00
exiterr1: jmp exiterr
: lda matches ; check # matches
beq notlord ; no matches
; Copy found address/socket to request
ldx #3
: lda NBPBuf,x
sta ATPaddr,x
dex
bpl :-
lda verbose
beq :+
; display NBP entry if verbose
lda bufp+1 ; set up pointer to response buffer
sta sptr+1
lda bufp
sta sptr
jsr prnbpent
; now make ATP request to TimeLord
: lda #$01
sta ATPbmap
ATcall ATPparms
bcs notime ; if error, bail now
; now do big-endian addition of the base offset
sec
ldx #$03
: lda To,x
sbc Base,x
sta From,x
dex
bpl :-
; Use the WS card to convert it to ProDOS format
ATcall CvtParms
bcs notime ; bail if error
; Display date/time
ldy To
lda To+1
jsr xpr_date_ay
jsr xmess
asc_hi " "
.byte $00
ldy To+2
lda To+3
jsr xpr_time_ay
jsr xmess
.byte $8d,$00
; set Prodos date/time if asked
lda #'p'|$80 ; set prodos date/time?
jsr xgetparm_ch
bcs nosetp8 ; skip if -p not given
; Copy converted values to the global page
ldx #$03
: lda To,x
sta P8DtTm,x
dex
bpl :-
nosetp8: ; TODO: set NSC or ThunderClock or something
rts
notime: lda #$01
jsr xredirect
jsr xmess
asc_hi "Error getting date/time!"
.byte $00
bra exiterr
noatalk: lda #$01
jsr xredirect
jsr xmess
asc_hi "AppleTalk offline!"
.byte $00
exiterr: lda #$ff
jsr xredirect
jmp xerr
; ***
; get_nbp - get part of a name at ay and copy to sptr
; x = 0:name 1:type 2:zone, +$80 sub wildcard or default if none given
; return: (sptr) = string, x = length of it
.proc get_nbp
sty sptr2
sta sptr2+1
stx stemp
ldy #$00
sty colon ; init these
sty at
lda sptr ; copy sptr to self-modifying wrtdest
sta wrtdest+1
lda sptr+1
sta wrtdest+2
jsr incdest ; and move to first char position
lda (sptr2),y ; length
beq notfound ; zero, just give up
sta end
; find the delimiters
tay
: lda (sptr2),y
cmp #':'
bne notcolon
sty colon
notcolon: cmp #'@'
bne nxtdelim
sty at
nxtdelim: dey
bne :-
; now make sure that if @ is given, it is after :
lda at
beq :+
cmp colon
bcc bad
; now get the part requested
: lda stemp
and #$7f
beq getname
cmp #$01
beq gettype
getzone: ldy at
beq notfound
cpy end
beq notfound
; need to copy from at(+1) to end
docopy: ldx #$00
: iny
lda (sptr2),y
jsr wrtdest
cpy end ; was that the last char
bcc :- ; nope, next char
ldy #$00
txa
sta (sptr),y ; save copied length
clc
rts ; and return
getname: ldy colon
bne :+
ldy at
beq :++
: dey
sty end
: ldy end
beq notfound
ldy #$00 ; initially at pos 0
; need to copy from pos 1 to end
beq docopy ; always
gettype: ldy colon
beq notfound ; early out if no colon
cpy end
beq notfound
ldy at
beq :+ ; use end as-is
dey ; otherwise end at pos before @
sty end
: ldy colon
; need to copy from colon(+1) to end
bne docopy ; should be always
notfound: lda stemp
and #$80
bne :+ ; if client asked for a default
lda #$00
tay
tax ; x is officially length of string result
sta (sptr),y ; put a zero in destination
bad: sec ; tell client we gave an empty string
rts
: ldx #$01 ; length of default
ldy #$00
txa
sta (sptr),y
iny
lda stemp
cmp #$82 ; want default zone? ('*')
bne :++ ; nope
lda #'*'
: sta (sptr),y
clc
rts
: lda #'=' ; wildcard for name or type
bne :-- ; always
wrtdest: sta $ffff
inx ; inc count of copied chars
incdest: inc wrtdest+1
bne :+
inc wrtdest+2
: rts
colon: .byte $00
at: .byte $00
end: .byte $00
.endproc
;
; print an NBP entry at sptr
.proc prnbpent
ldy #$00 ; offset into entry, net number low byte
lda (sptr),y ; big end of network num
pha
iny
lda (sptr),y
tay
pla
jsr xprdec_2
jsr xmess
asc_hi "."
.byte $00
; print node
ldy #$02
lda (sptr),y
tay
lda #$00
jsr xprdec_2
jsr xmess
asc_hi ":"
.byte $00
; print socket
ldy #$03
lda (sptr),y
tay
lda #$00
jsr xprdec_2
jsr xmess
asc_hi " " ; print space in case output is not to screen.
.byte $00
;lda #20 ; Position NBP tuple on screen.
;sta ch
lda #$05 ; offset to NBP tuple
jsr addsptr
jsr prnbptup
jsr xmess ; CR
.byte $8d,$00
rts
.endproc
; print an NBP tuple at sptr
; leave sptr at byte just after tuple
; does not print zone unless verbose flag set
.proc prnbptup
; print name
jsr prpas
jsr xmess
asc_hi ":"
.byte $00
; print type
jsr prpas
lda verbose
beq skipzone ; if not verbose, don't display @zone
jsr xmess
asc_hi "@"
.byte $00
; print zone
jsr prpas
bra :+
skipzone: ldy #$00
lda (sptr),y ; get length of zone name
inc a ; account for length byte
jsr addsptr ; and skip the lot
: rts ; done
.endproc
; increment sptr by a
.proc addsptr
clc
adc sptr
sta sptr
bcc :+
inc sptr+1
: rts
.endproc
; print pascal string at sptr
; leave sptr pointed at one past end
; of string
.proc prpas
ldy #$00
lda (sptr),y ; get length
tax
next: lda #$01
jsr addsptr
dex
bpl :+
rts
: lda (sptr),y ; get char
ora #$80 ; make printable
jsr cout
bra next
.endproc
; copy a pascal string to sptr offset by y
; a,x = source
; return: y = new offset after copied str
.proc copystr
sta sptr2+1
stx sptr2
sty stemp ; save offset
ldy #$00
lda (sptr2),y ; get number of chars
tax ; to copy
ldy stemp ; get the offset
sta (sptr),y ; store the length byte
inc stemp ; increment the offset
inc sptr2 ; next source char
bne :+
inc sptr2+1
: ldy #0
; copy loop
: phy
lda (sptr2),y
ldy stemp
sta (sptr),y
inc stemp
ply
iny
dex
bne :-
ldy stemp
rts
.endproc
;
inforeq: .byte 0,2 ; sync GetInfo
.word $0000 ; result code
.dword $00000000 ; completion address
thisnet: .word $0000 ; this network #
abridge: .byte $00 ; local bridge
hwid: .byte $00 ; hardware ID, IIgs only
romver: .word $00 ; ROM version, IIgs only
nodenum: .byte $00 ; node number
; some pointers & values for building names
defname: .byte 1,"=" ; object
deftype: .byte 8,"TimeLord" ; type
defzone: .byte 1,"*" ; zone
; Base offset for epoch conversion
Base: .byte $B4,$93,$56,$70 ; in big-endian order
; parameter list for NBPLookup
lookup: .byte 0,16 ; sync NBPLookup
.word $0000 ; result
.dword $00000000 ; completion
.dword entname ; pointer to name to find
.byte 4,4 ; 4 times, every 1 sec
.word $0000 ; reserved
.word NBPBufSz ; buffer size
bufp: .dword NBPBuf ; buffer loc
.byte 1 ; matches wanted
matches: .byte $00 ; matches found
; ATP request parameters
ATPparms: .byte 0,18 ; sync SendATPReq
.word $0000 ; result
.dword $00000000 ; compl. addr
.byte $00 ; socket #
ATPaddr: .dword $00000000 ; destination address
.word $0000 ; TID
.word $0000 ; req buffer size
.dword $00000000 ; req buffer addr
.dword $00000000 ; user bytes, $00 = get time
.byte $01 ; one response buffer
.dword BDS ; pointer to response BDS
.byte $00 ; ATP flags
.byte 4,4 ; try 4 times every 1/4 second
ATPbmap: .byte $00 ; bitmap of blocks to recieve
.byte $00 ; number of responses
.res 6 ; 6 bytes reserved
; BDS for ATP request
BDS: .word $000c ; 12-byte buffer for full response from TimeLord
.dword From ; Buffer pointer
Status: .dword $00000000 ; returned user bytes, first byte = 12 if OK
.word $0000 ; actual length
; Convert time paraameters
; note that ATP response is written to From
CvtParms: .byte 0,$34 ; sync ConvertTime
.word $0000 ; result
.byte $00 ; 0 = from AFP to ProDOS, 1 = reverse
From: .dword $00000000 ;
To: .dword $00000000 ; initially contains time from ATP response
.res 4 ; fill out remaining part of buffer
DX_end

77
utils/auto_origin.sh Executable file
View File

@ -0,0 +1,77 @@
#!/bin/bash
END_FENCE=45056
if [ -z "${1}" ]; then
cat <<USAGE_END
Usage: $0 <command> <args>
<command>+<args> should be an ld65 command line with exactly one object
file containing
Appends --start-addr <address> to <command> if the first object file in
<command> has X_DX_AUTO_LOAD exported. Such a command should probably
only have one object file, one CODE segment, and no other initialized
segments.
<address> is calculated to be a page boundary that causes the linked
object file in question to end somewhere between $AF00 and $AFFF.
od65 should be in the same location as <command>
USAGE_END
exit 1
fi
shopt -s extglob
COMMW=`which ${1}`
if [ "${?}" -gt 0 ]; then
echo "Cannot locate ${1}"
exit 2
fi
OD65="`dirname ${COMMW}`/od65"
if [ ! -x "${OD65}" ]; then
echo "Cannot use ${OD65}"
exit 3
fi
CMD_SUFFIX=
OBJECT_FILE=
for ARG in ${*}; do
# echo "${ARG}"
if [[ "${ARG}" == @(\-*) ]]; then
:
# echo "Skipping ${ARG}"
else
if [ -r "${ARG}" ]; then
${OD65} --dump-exports ${ARG} | grep -q X_DX_AUTO_LOAD
RESULT="${?}"
if [ "${RESULT}" -eq 0 ]; then
OBJECT_FILE="${ARG}"
else
:
# echo "No X_DX_AUTO_LOAD found in ${ARG}: ${RESULT}"
fi
fi
fi
done
if [ -z "${OBJECT_FILE}" ]; then
echo "X_DX_AUTO_LOAD not detected, not auto-originating"
else
echo "Auto-originating ${OBJECT_FILE}"
CODE_SIZE=`${OD65} -S ${OBJECT_FILE} | awk '/CODE:/{print $2}'`
if [ -z "${CODE_SIZE}" -o "${CODE_SIZE}" -lt 1 ]; then
echo "Could not determine code size, got '${CODE_SIZE}'!"
exit 4
fi
echo "Code size: ${CODE_SIZE}"
START=$(( (${END_FENCE} - ${CODE_SIZE}) / 256 * 256 ))
if [ -z "${START}" ]; then
echo "Could not calculate a start address!"
exit 4
else
CMD_SUFFIX="${CMD_SUFFIX} --start-addr ${START}"
fi
fi
CMD="${*}${CMD_SUFFIX}"
echo "${CMD}"
${CMD}

14
utils/gen_help.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/bash
if [ -z "$2" ]; then
echo "Usage: $0 infile outfile"
exit 1
fi
sed -n '/%help/,/%hend/p' "$1" | awk -F '; ' '{print $2}' | egrep -v '^%.+' | tr '\n' '\r' > "$2"
if [ -s "$2" ]; then
echo "Help file created."
else
echo "Help file missing or size zero."
rm -f "$2"
fi
exit 0