From d9b665d62ae494764cb3846f45eb510ab7f37c77 Mon Sep 17 00:00:00 2001 From: mgcaret Date: Fri, 15 Sep 2017 09:55:29 -0700 Subject: [PATCH] initial --- .gitignore | 9 + Makefile | 49 ++ README.md | 108 ++++ afp.sessions.s | 169 ++++++ afp.userprefix.s | 177 ++++++ alias.s | 581 +++++++++++++++++++ at.boot.s | 47 ++ at.info.s | 123 ++++ at.zones.s | 163 ++++++ boot.dsk | 1 + davex-mg.inc | 174 ++++++ deschw.s | 1321 ++++++++++++++++++++++++++++++++++++++++++ dmem.s | 48 ++ idemu.s | 214 +++++++ iie.card.s | 163 ++++++ mig.insp.s | 312 ++++++++++ nbp.lookup.s | 426 ++++++++++++++ nbp.parse.s | 235 ++++++++ tardis.s | 483 +++++++++++++++ utils/auto_origin.sh | 77 +++ utils/gen_help.sh | 14 + 21 files changed, 4894 insertions(+) create mode 100644 .gitignore create mode 100755 Makefile create mode 100644 README.md create mode 100644 afp.sessions.s create mode 100644 afp.userprefix.s create mode 100644 alias.s create mode 100644 at.boot.s create mode 100644 at.info.s create mode 100644 at.zones.s create mode 120000 boot.dsk create mode 100644 davex-mg.inc create mode 100644 deschw.s create mode 100644 dmem.s create mode 100644 idemu.s create mode 100644 iie.card.s create mode 100644 mig.insp.s create mode 100644 nbp.lookup.s create mode 100644 nbp.parse.s create mode 100644 tardis.s create mode 100755 utils/auto_origin.sh create mode 100755 utils/gen_help.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a7adac4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.o +*.p8c +*.lst +*.map +*.po +*.SHK +*.shk +help +test diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..3d18f63 --- /dev/null +++ b/Makefile @@ -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 + diff --git a/README.md b/README.md new file mode 100644 index 0000000..6101ad1 --- /dev/null +++ b/README.md @@ -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. + + diff --git a/afp.sessions.s b/afp.sessions.s new file mode 100644 index 0000000..f8c8d3e --- /dev/null +++ b/afp.sessions.s @@ -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 + 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 diff --git a/afp.userprefix.s b/afp.userprefix.s new file mode 100644 index 0000000..3446cae --- /dev/null +++ b/afp.userprefix.s @@ -0,0 +1,177 @@ +; %help +; afp.userprefix - Display or set the AFP user prefix. +; +; options: -s Set to , 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 + 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 diff --git a/alias.s b/alias.s new file mode 100644 index 0000000..e9479fc --- /dev/null +++ b/alias.s @@ -0,0 +1,581 @@ +;************************************************* +;************************************************* +; +; 'alias' -- external command for Davex +; +; alias -- view and modify Davex aliases +; +; alias [-s] [-l] [-r] +; +; alias displays all aliases +; alias adds alias +; alias -r removes alias +; 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 + ldy #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 diff --git a/boot.dsk b/boot.dsk new file mode 120000 index 0000000..e57ed5f --- /dev/null +++ b/boot.dsk @@ -0,0 +1 @@ +/Users/lshadow/DavexProDOS.dsk \ No newline at end of file diff --git a/davex-mg.inc b/davex-mg.inc new file mode 100644 index 0000000..52ddfba --- /dev/null +++ b/davex-mg.inc @@ -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 +; +; 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 +; ********* diff --git a/deschw.s b/deschw.s new file mode 100644 index 0000000..fe0cebd --- /dev/null +++ b/deschw.s @@ -0,0 +1,1321 @@ +;********************************************* +;********************************************* +; +; External command for Davex +; +; deschw -- describe hardware +; +; Options: +; -t system type +; -c cards +; -s SmartPort +; +; 15-Oct-89 DAL ==> v1.2 +; Changed "//" to "II" +; Added IIc+ identification +; & fixed mismatched parens +; Added IIe debugger ROM id +; +;********************************************* +; +; Converted to MPW IIgs 20-Sep-92 DAL +; +;********************************************* +; 27-Jul-17 MAG ==> v1.3 +; Added Apple IIe Card +; for Mac LC identification +; 28-Jul-17 MAG ==> v1.3 (still) +; Added CPU identification (6502, 65C02, 658xx) +; Added emulator identification +; Reduced repetition, reworded, saved a few bytes +; Fix bug where garbage is printed if smartport +; device name is 0 bytes long +; Fix AppleTalk identification & enhanced +; Fix case where an emulator doesn't execute +; missing SMB0 as two-byte opcode +; 05-Aug-17 MAG ==> v1.3 (still) +; Work around lazy IIe LC PDS Card SmartPort. +; 07-Aug-17 MAG ==> v1.3 (still) +; Show Smartport ID type info (Extended/SCSI/RAM card) +; Optional code to show SmartPort vendor and version (not working?) SmartPort TN #2 +; Support additional devices defined in SmartPort TN #4 +; Support subtype flags as described in SmartPort TN #7 +; 14-Aug-17 MAG ==> v1.3 (still) +; Reduce emulator detection to actual emulator for those supporting +; EMUBYTE, or "probable" if no floating bus detected. If you want more +; specific identification, see idemu program. + +;.segment "CODE_9000" + + .include "Common/2/Globals2.asm" + .include "Common/2/Apple.Globals2.asm" + .include "Common/2/Mli.Globals2.asm" + .include "Common/Macros.asm" + +OrgAdr = $9000 ;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. + +b_phy = $5a +b_xce = $fb +b_rep = $c2 +b_ldx = $a2 + +;********************************************* +; +; SmartPort constants +; +sptSTATUS = 0 +sptREADBLK = 1 +sptWRITEBLK = 2 +sptFORMAT = 3 +sptCONTROL = 4 +sptINIT = 5 +sptOPEN = 6 +sptCLOSE = 7 +sptREAD = 8 +sptWRITE = 9 +; +;********************************************* +MyVersion = $13 +MinVersion = $11 +;********************************************* + rts + .byte $ee,$ee + .byte MyVersion,MinVersion + .byte %00000000 ;hardware req + .addr descr + .addr OrgAdr + .addr start + .byte 0,0,0,0 +; parameters here + .byte $80+'t',t_nil + .byte $80+'c',t_nil + .byte $80+'s',t_nil + .byte 0,0 +descr: + pstr "describe system hardware" + +;********************************************* +; dum xczpage ;32 locations +slot = xczpage ;ds.b 1 +rom = slot+1 ;ds.b 2 +Unit = rom+2 ;ds.b 1 +scratch = Unit+1 ;ds.b 1 +totalmem = scratch+1 ;ds.b 4 +emubyte = totalmem+4 +emuver = emubyte+1 +scratch2 = emuver+1 +checkemu = scratch2+1 +; dend +; +start: + lda #$80 + sta checkemu + jsr xgetnump + beq do_all + lda #'t'+$80 ;system Type + jsr xgetparm_ch + bcs no_type + jsr my_crout + jsr systemtype +no_type: lda #'c'+$80 ;Cards + jsr xgetparm_ch + bcs no_cards + jsr my_crout + jsr scanslots +no_cards: lda #'s'+$80 + jsr xgetparm_ch + bcs no_sp + jsr my_crout + jsr DescribeSP +no_sp: rts +; +do_all: + jsr systemtype + jsr processor + jsr emulation + jsr my_crout + jsr scanslots + jsr my_crout + jsr DescribeSP + jsr my_crout + rts +; +systemtype: + jsr xmess + asc "System: " + .byte 0 + sec + jsr $fe1f + bcc st_gs + jmp IdentNotGS +; +st_gs: jsr xmess + + + asc "Apple IIgs, ROM version $" + + .byte 0 + clc + .byte b_xce,b_rep,$30 + jsr $fe1f + .byte b_phy + sec + .byte b_xce + pla + jsr $fdda + jsr xmess + + + asc " (Machine ID=$" + + .byte 0 + pla + jsr $fdda + jsr xmess + + + asc ")" + + .byte 0 + jsr my_crout + clc + .byte b_xce + .byte b_rep,$30 + pha + pha + .byte b_ldx + .addr $1d02 ;TotalMem + .byte $22,0,0,$E1 + pla + sta totalmem + pla + sta totalmem+2 + sec + .byte b_xce + jsr xmess + + + asc "Total RAM = " + + .byte 0 + ldx #10 +div1K: lsr totalmem+3 + ror totalmem+2 + ror totalmem+1 + ror totalmem + dex + bne div1K + lda totalmem+1 + ldy totalmem + jsr xprdec_2 + jsr xmess + asc "K" + .byte cr,0 + rts +; +IdentNotGS: + lda $fbb3 + cmp #$ea + bne not_2p3 + lda $fb1e + cmp #$ad + beq TwoPlus + cmp #$8a + beq Three +unknown: jsr xmess + asc "???" + .byte 0 + rts +TwoPlus: jsr xmess + asc "Apple ][+" + .byte 0 + rts +Three: jsr xmess + asc "Apple /// (in emulation mode)" + .byte 0 + rts +; +not_2p3: + lda $fbb3 + cmp #$06 + bne unknown + lda $fbc0 + cmp #$ea + bne Not2e1 + jsr apple2e + jsr xmess + + + asc "(unenhanced)" + + .byte 0 + rts +Not2e1: cmp #$e0 + bne not2e2 + lda $fbdd + cmp #$02 ; IIe for Power Mac also has this + bne NotLC + lda $fbde + cmp #$01 ; IIe for Power Mac does *not* have this + bne NotLC + jsr apple2e + jsr xmess + + + asc "(LC PDS Card, version $" + + .byte 0 + lda $fbbe ; version # of LC PDS Card + jsr $fdda + jsr xmess + asc ")" + .byte $00 + .pc02 + stz checkemu + .p02 + rts + +NotLC: + jsr apple2e + jsr xmess + + + asc "(enhanced)" + + .byte 0 + rts +not2e2: + cmp #$e1 + bne notDbgr + jsr apple2e + jsr xmess + + + asc "(special ROMs)" + + .byte 0 + rts +notDbgr: + cmp #$00 + bne unkn0 +; it's a IIc + lda $fbbf + cmp #5 + beq IIcPlus + jsr apple2c + jsr xmess + + + asc ", version " + + .byte 0 + lda $fbbf + cmp #$ff + beq TwoC1 + cmp #$00 + beq TwoC2 + cmp #$03 + beq TwoC3 + cmp #$04 + beq TwoC4 +unkn0: jmp unknown +IIcPlus: + jsr apple2c + jsr xmess + + + asc " Plus" + + .byte 0 + rts +TwoC1: jsr xmess + + + asc "1 (ROM 255)" + + .byte 0 + rts +TwoC2: jsr xmess + + + asc "2: 3.5" + + .byte $a2 + + + asc " disk (ROM 0)" + + .byte 0 + rts +TwoC3: jsr xmess + + + asc "3: " + + .byte 0 +memexp: + jsr xmess + asc "Mem. Expandable" + .byte $00 + rts +TwoC4: jsr xmess + + + asc "4: Revised " + + .byte 0 + .pc02 + bra memexp + .p02 +apple2e: + jsr xmess + asc "Apple IIe " + .byte $00 + rts +apple2c: + jsr xmess + asc "Apple IIc" + .byte $00 + rts +;**************************************************** +processor: + jsr xmess + .byte $8d + asc "CPU: " + .byte $00 + sed + lda #$99 + clc + adc #$01 + cld + bmi p6502 + ; 65C02 or 8xx + ldx #$00 ; see below + clc + .p816 + sep #%00000001 ; set carry, should be 2-byte NOP on the 'C02 + inx ; except when it isn't (Apple//jse) + ; so detect this with this inx that + ; gets skipped if sep #1 == nop ora zp,x + stx scratch2 + .p02 + bcs p658xx + ; we have a 65C02 + jsr xmess + asc "65C02" + .byte $00 + lda scratch2 ; is zero if broken + beq brokec02 + .pc02 + stz scratch2 + smb0 scratch2 ; ora [d] on 8xx + .p02 + lda scratch2 + bne procdone + jsr xmess + asc " (no x7/xF opcodes)" + .byte $00 +procdone: + rts +p6502: + jsr xmess + asc "6502" + .byte $00 + rts +p658xx: + jsr xmess + asc "658xx" + .byte $00 + rts +brokec02: + jsr xmess + asc " (broken)" + .byte $00 + rts +;**************************************************** +emulation: + lda checkemu ; skip if we positively identified hardware (LC PDS card) + beq noemu1 + sta $c04f ; get emubyte + lda $c04f ; Emulator ID + ldy $c04f ; The GS emulators (except Gus) all do version # here + sta emubyte + sty emuver + ldx #$ff ; now test 255 more times +: sta $c04f + lda $c04f + cmp emubyte ; floating bus gonna float + bne noemu1 ; not emulator if it changes + dex + beq econt + bne :- +noemu1: + rts +econt: + cmp #$a0 ; a space... if we somehow got 255 of them + beq noemu1 ; just assume we were lucky + jsr xmess + .byte $8d + asc "Emulator: " + .byte $00 + lda emubyte + cmp #$fe + bne notbernie + jsr xmess + asc "Bernie ][ the Rescue" + .byte $00 + .p816 + jmp emuversion ; out of range for bra + .p02 +notbernie: + cmp #$16 + bne notsweet16 + jsr xmess + asc "Sweet 16" + .byte $00 + .p816 + bra emuversion + .p02 +notsweet16: + cmp #$47 + bne notgsport + jsr xmess + asc "GSport or derivative" + .byte $00 + .p816 + bra emuversion + .p02 +notgsport: + cmp #$4b + bne notkegs + jsr xmess + asc "KEGS or derivative" + .byte $00 + .p816 + bra emuversion + .p02 +notkegs: + cmp #$ab + bne unkemu + jsr xmess + asc "Appleblossom" + .byte $00 +emuversion: + jsr xmess + asc ", version = $" + .byte $00 + lda emuver + jsr $fdda +noemu: + rts +unkemu: + jsr xmess + asc "Probable [" + .byte $00 + lda emubyte + jsr $fdda + lda emuver + jsr $fdda + jsr xmess + asc "]" + .byte $00 + rts +;**************************************************** +scanslots: + lda #1 + sta slot +ss1: jsr scan1 + inc slot + lda slot + cmp #8 + bcc ss1 + rts +; +scan1: jsr xmess + + + asc "Slot " + + .byte 0 + lda slot + ora #'0'+$80 + jsr cout + jsr xmess + + + asc ": " + + .byte 0 + lda slot + ora #$c0 + sta rom+1 + lda #0 + sta rom + jsr PrSlotDesc + jsr my_crout + jsr MaybeATLK +not_atlk: + rts +; +; MaybeATLK - if ATLK found, return carry clear +; otherwise return carry set. +ATLKsig: asc "ATLK" +; .byte 0 unneeded +MaybeATLK: + ldy #$F9 ;check $CnF9 +at_chk: lda (rom),y + cmp ATLKsig-$F9,y + sec ; anticipate failure + bne not_atlk + iny + cpy #$FD + bcc at_chk + jsr xmess + + + asc " AppleTalk " + + .byte $00 + ldy #$fd + lda (rom),y + bne notatgs + jsr xmess + asc "(IIgs)" + .byte $00 + jmp :+ +notatgs: + cmp #$01 + bne notatws + jsr xmess + asc "Workstation" + .byte $00 + jmp atcard +notatws: + cmp #$02 + bne notatsrv + jsr xmess + asc "Server" + .byte $00 +atcard: + jsr xmess + asc " Card" + .byte $00 + jmp :+ +notatsrv: + pha + jsr xmess + asc " (ID $" + .byte $00 + pla + jsr $fdda + jsr xmess + asc ")" + .byte $00 + ; fall through +: jsr xmess + + asc "; version=" + + .byte 0 + ldy #$fe + lda (rom),y + pha + lsr a + lsr a + lsr a + lsr a + jsr prnib + lda #'.'+$80 + jsr cout + pla + jsr prnib + ldy #$ff + lda (rom),y + jsr prbyte + jsr my_crout + clc +; not_atlk ; moved up + rts +; +prnib: and #$0F + cmp #$0A + bcc prn_dig + adc #6 +prn_dig: adc #$B0 + jmp cout +; +SlotEmpty: jsr xmess + + + asc "empty" + + .byte 0 + rts +; +notPasc0: jmp notPasc +PrSlotDesc: + ldy slot + lda bitpos,y + and sltbyt + beq SlotEmpty + ldy #5 + lda (rom),y + cmp #$38 + bne notPasc0 + ldy #7 + lda (rom),y + cmp #$18 + bne notPasc0 + ldy #$b + lda (rom),y + cmp #$1 + bne notPasc0 + iny + lda (rom),y + pha + jsr xmess + + + asc "Pascal ID = $" + + .byte 0 + pla + pha + jsr prbyte + jsr xmess + + + asc ": " + + .byte 0 + pla + lsr a + lsr a + lsr a + lsr a + asl a + tax + lda PascTbl+1,x + pha + lda PascTbl,x + pha + rts +PascTbl: + .addr ps0-1,ps1-1,ps2-1,ps3-1,ps4-1,ps5-1,ps6-1,ps7-1 + .addr ps8-1,ps9-1,ps10-1,ps0-1,ps0-1,ps0-1,ps0-1,ps0-1 +; +ps0: jsr xmess + + + asc "???" + + .byte 0 + rts +ps1: jsr xmess + + + asc "printer" + + .byte 0 + rts +ps2: jsr xmess + + + asc "joystick/mouse" + + .byte 0 + rts +ps3: jsr xmess + + + asc "serial or parallel card" + + .byte 0 + rts +ps4: jsr xmess + asc "modem" + .byte 0 + rts +ps5: jsr xmess + asc "sound/speech device" + .byte 0 + rts +ps6: jsr xmess + asc "clock" + .byte 0 + rts +ps7: jsr xmess + asc "disk/storage device" + .byte 0 + rts +ps8: jsr xmess + asc "80-column card" + .byte 0 + rts +ps9: jsr xmess + asc "network/bus interface" + .byte 0 + rts +ps10: jsr xmess + asc "other" + .byte 0 + rts +; +notPasc: + jsr chk_clock + bcs chk_sp + jsr xmess + asc "ThunderClock/compatible" + .byte 0 + rts +chk_sp: jsr chk_smport + bcs chkb + ldy #$fb ; smartport ID byte + lda (rom),y + pha + and #%10000000 + beq :+ + jsr xmess + asc "Extended " + .byte 0 +: pla + pha + and #%00000010 + beq :+ + jsr xmess + asc "SCSI " + .byte 0 +: pla + pha + and #%00000001 + beq :+ + jsr xmess + asc "RAM Card " + .byte 0 +: pla ; clean stack + jsr xmess + asc "SmartPort" + .byte 0 + rts +chkb: jsr chk_blkdev + bcs notblk +; Is it a Disk II? + ldy #$ff + lda (rom),y + bne notDiskII + jsr xmess + asc "5.25" + .byte $A2 + asc " disk drive" + .byte 0 + rts +notDiskII: + jsr xmess + asc "ProDOS block device" + .byte 0 + rts +notblk: jsr xmess + asc "unknown card" + .byte 0 + rts +; +bitpos: + .byte %00000001 + .byte %00000010 + .byte %00000100 + .byte %00001000 + .byte %00010000 + .byte %00100000 + .byte %01000000 + .byte %10000000 +; +; If ROM at (rom) is a ProDOS-recognized clock card, +; return CLC +; +chk_clock: ldy #0 + lda (rom),y + cmp #$08 + bne chks_no + ldy #2 + lda (rom),y + cmp #$28 + bne chks_no + ldy #4 + lda (rom),y + cmp #$58 + bne chks_no + ldy #6 + lda (rom),y + cmp #$70 + bne chks_no + clc + rts +; +; If ROM at (rom) is for a SmartPort, return CLC +; +chk_smport: + jsr chk_blkdev + bcs chks_no + ldy #7 + lda (rom),y + bne chks_no + clc + rts +chks_no: sec + rts +; +; If ROM at (rom) is for a block device, return CLC +; +chk_blkdev: + ldy #1 + lda (rom),y + cmp #$20 + bne chkb_no + ldy #3 + lda (rom),y + bne chkb_no + ldy #5 + lda (rom),y + cmp #$03 + bne chkb_no + clc + rts +chkb_no: sec + rts +; +; DescribeSP -- show all SmartPort information +; +DescribeSP: lda #1 + sta slot + lda #0 + sta rom +desSp1: lda slot + ora #$c0 + sta rom+1 + jsr chk_smport + bcs desNotSP + jsr Descr1SP +desNotSP: inc slot + lda slot + cmp #8 + bcc desSp1 + rts +; +Descr1SP: + jsr xmess + + + asc "SmartPort controller found in slot " + + .byte 0 + lda slot + ora #'0'+$80 + jsr cout + jsr xmess + .byte $80+'.',cr,0 +; find the entry point + ldy #$ff + lda (rom),y + clc + adc #3 + sta SpTrick+1 + lda rom+1 + sta SpTrick+2 +; + jsr SpStatus + jsr EachStatus + rts +; +; SpStatus -- get and print global status of a SmartPort chain +; +staterr: jmp xProDOS_err +SpStatus: + ldx #sptSTATUS + lda #>GlobStat + ldy #Stat1parms + ldy #emIIe + bne foundemu1 +iiecard: lda $fbbe + sta emuver + ldy #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 + 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 + 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 + 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 +foundemu1: + jmp foundemu +: cmp #$fe ; Bernie + bne :+ + ldy #emBernie + bne foundemu +: cmp #$16 ; Sweet 16 + bne :+ + ldy #emS16 + bne foundemu +: cmp #$47 ; GSport + bne :+ + ldy #emGSport + bne foundemu +: cmp #$4b ; KEGS + bne :+ + ldy #emKEGS + bne foundemu +: cmp #$ab ; AppleBlossom + bne :+ + ldy #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 +foundemu: ldx emuver + clc + rts +noemu: ldy #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 \ No newline at end of file diff --git a/iie.card.s b/iie.card.s new file mode 100644 index 0000000..9f57808 --- /dev/null +++ b/iie.card.s @@ -0,0 +1,163 @@ +; %help +; iie.card -- Display info about or control the Apple //e Card for Mac LC. +; +; options: +; -s 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 diff --git a/mig.insp.s b/mig.insp.s new file mode 100644 index 0000000..3a270f1 --- /dev/null +++ b/mig.insp.s @@ -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+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 diff --git a/nbp.lookup.s b/nbp.lookup.s new file mode 100644 index 0000000..99e4cb5 --- /dev/null +++ b/nbp.lookup.s @@ -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+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 + ldy #$00 + jsr copystr + ; now we have a complete name to look up + ; rts ; DEBUG +doit: 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 + 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 diff --git a/nbp.parse.s b/nbp.parse.s new file mode 100644 index 0000000..078515d --- /dev/null +++ b/nbp.parse.s @@ -0,0 +1,235 @@ +; %help +; nbp.parse - parse and output parts of NBP +; +; 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+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+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 diff --git a/tardis.s b/tardis.s new file mode 100644 index 0000000..8342ddc --- /dev/null +++ b/tardis.s @@ -0,0 +1,483 @@ +; %help +; tardis - Get date/time from TimeLord server. +; +; options: +; -v Verbose mode, prints server info. +; -n Specify NBP query, default =:TimeLord@* +; -p Set ProDOS global page date/time. +; -s Set a clock of , 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+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+1 + ldy #$00 + ldx #defname + jsr copystr + ldx #deftype + jsr copystr + ldx #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 + 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+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 diff --git a/utils/auto_origin.sh b/utils/auto_origin.sh new file mode 100755 index 0000000..eb71056 --- /dev/null +++ b/utils/auto_origin.sh @@ -0,0 +1,77 @@ +#!/bin/bash +END_FENCE=45056 + +if [ -z "${1}" ]; then + cat < + ++ should be an ld65 command line with exactly one object +file containing + +Appends --start-addr
to if the first object file in + has X_DX_AUTO_LOAD exported. Such a command should probably +only have one object file, one CODE segment, and no other initialized +segments. + +
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 +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} + diff --git a/utils/gen_help.sh b/utils/gen_help.sh new file mode 100755 index 0000000..29b21c8 --- /dev/null +++ b/utils/gen_help.sh @@ -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 +