commit d9b665d62ae494764cb3846f45eb510ab7f37c77 Author: mgcaret Date: Fri Sep 15 09:55:29 2017 -0700 initial 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 +