├── .gitignore ├── Makefile ├── NetBoot_LC.s ├── README.md ├── t └── utils ├── blocks2rez.sh └── rezhex.format /.gitignore: -------------------------------------------------------------------------------- 1 | NetBoot_LC 2 | *.bin 3 | *.r 4 | *.o 5 | *.lst 6 | *.dsk 7 | *.po 8 | sshot 9 | 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ACMD=java -jar ~/bin/AppleCommander-1.3.5-ac.jar 2 | 3 | .PHONY: all 4 | all: NetBoot_LC.mac.bin ; 5 | 6 | test.po: NetBoot_LC.bin 7 | $(ACMD) -pro140 test.po NETBOOT.LC.TST 8 | $(ACMD) -p test.po NETBOOT.LC BIN 0x0800 < NetBoot_LC.bin 9 | 10 | emulate: boot.dsk test.po 11 | open boot.dsk test.po -a 'Virtual ][' 12 | 13 | NetBoot_LC.mac.bin: NetBoot_LC 14 | rm -f NetBoot_LC.mac.bin 15 | macbinary encode -t 2 -o NetBoot_LC.mac.bin NetBoot_LC 16 | 17 | NetBoot_LC: NetBoot_LC.r 18 | Rez -rd -o NetBoot_LC NetBoot_LC.r 19 | 20 | NetBoot_LC.r: NetBoot_LC.bin 21 | utils/blocks2rez.sh NetBoot_LC.bin > NetBoot_LC.r 22 | 23 | NetBoot_LC.bin: NetBoot_LC.o 24 | ld65 -t none -o NetBoot_LC.bin Netboot_LC.o 25 | 26 | NetBoot_LC.o: NetBoot_LC.s 27 | ca65 -o NetBoot_LC.o -l NetBoot_LC.lst NetBoot_LC.s 28 | 29 | .PHONY: clean 30 | clean: 31 | rm -f NetBoot_LC *.bin *.r *.o *.lst test.po 32 | 33 | -------------------------------------------------------------------------------- /NetBoot_LC.s: -------------------------------------------------------------------------------- 1 | ; Apple //e Workstation Card 2 | ; replacement for "hard-coded" boot blocks (in ca65 format). 3 | ; By Michael Guidero 4 | ; 5 | ; The Apple //e Card for Macintosh LC is quite capable. It 6 | ; emulates all of the functions of the Apple //e Workstation Card 7 | ; except for one: When you boot "over the network", instead of getting 8 | ; the boot blocks over the network, it loads them from the "IIe Startup" 9 | ; resource fork, from BBLK#5120. Because the boot blocks contain both 10 | ; ProDOS and the Logon program, as shipped by Apple the LC //e Card is 11 | ; "stuck" at ProDOS 1.9 and Logon 1.3 as shipped by Apple. Updating them 12 | ; requires using ResEdit to hack the IIe Startup program. 13 | ; 14 | ; The real Workstation Card finds a boot server on the network and loads 15 | ; the boot blocks over the network via ATP. Updating the boot blocks 16 | ; is as simple as replacing them on the boot server. 17 | ; 18 | ; While I figured out how to update the boot blocks in IIe Startup, having 19 | ; to hack it with ResEdit just to make it work the same as my regular //es 20 | ; with Workstation Cards every time a new ProDOS comes out was an annoying 21 | ; prospect. 22 | ; 23 | ; So as a solution, here's a replacement for BBLK#5120 that makes the LC 24 | ; //e Card work like a standard Apple //e with a Workstation Card. 25 | ; 26 | ; Other features: 27 | ; * Puts a letter in the lower left corner indicating what part of the 28 | ; boot process is happening, in case something goes wrong. 29 | ; * On-screen spinner, spins as each block is received. 30 | ; * Displays the current AppleTalk zone. 31 | ; * Displays the boot server network, node, and socket. 32 | ; 33 | ; Revisions since I gave out the Gist link: 34 | ; 07/10/2017 - Fix NBPBuf to be at $xx00 instead of $00xx 35 | ; - Display boot server address/socket & object name 36 | ; - convert output to use monitor routines rather than direct write 37 | ; for messages only, spinners and status still direct write 38 | ; - If in the boot scan loop, try next slot if we fail. 39 | ; 07/11/2017 - Convert all AT calls to macro 40 | ; - Adjust retry interval/tries in GetMyZone call. 41 | ; - Display zone if possible, when ca/option held. 42 | ; - Added missing init type flags byte to AT Init call. No harm no foul. 43 | ; 44 | 45 | .pc02 46 | 47 | .macro ATcall PList 48 | jsr GoCard 49 | .byte $42 50 | .addr PList 51 | .endmacro 52 | 53 | NBPBufSz = $0100 ; NBP buffer size 54 | 55 | DispTmp = $02 ; temp var for display routines 56 | ch = $24 ; cursor horizontal pos 57 | CardPtr = $fe ; ZP loc of card pointer 58 | IRQvect = $03fe ; ROM calls here on IRQ 59 | BootStart = $0800 ; where we load boot blocks 60 | NotifyLoc = $07d0 ; process notify screen loc 61 | SpinLoc = $428+19 ; spinner screen loc 62 | DeathLoc = $4A8+19 63 | 64 | mli = $bf00 ; ProDOS entry pt 65 | init = $fb2f ; init text screen 66 | tabv = $fb5b ; vtab to a-reg 67 | title = $fb60 ; clear screen, display "Apple //e" 68 | bell1 = $fbdd ; beep 69 | wait = $fca8 ; waste time 70 | cout = $fded ; character out 71 | setkbd = $fe89 ; set keyboard as input 72 | setvid = $fe93 ; set text screen as output 73 | 74 | clraltchar = $c00e 75 | 76 | .org BootStart ; code gets loaded here 77 | 78 | ; Main routine 79 | .proc NetBootLC 80 | jsr init ; init text screen 81 | jsr setkbd 82 | jsr setvid 83 | jsr HelloMsg ; Greeting message 84 | lda #'F'+$80 85 | sta NotifyLoc ; tell user we are finding the card 86 | jsr FindCard 87 | bcc :+ 88 | errend: jsr ErrorMsg ; whoopsie doodles 89 | die: jmp Death ; Try next slot or hang. 90 | : lda #'R'+$80 91 | sta NotifyLoc ; tell user we are moving boot code 92 | jsr ReloBoot ; move $0300 code 93 | lda #'I'+$80 94 | sta NotifyLoc ; tell user we are initing the card 95 | jsr InitCard 96 | bcs errend ; Init failed... sorry 97 | jsr GetInfo 98 | bcs errend 99 | ; local zone lookup doesn't always work when we don't have a bridge 100 | ; so if we don't have a bridge yet, don't do zone lookup unless ca/option is 101 | ; pressed 102 | lda ATbridge 103 | bne :+ ; if we have a bridge 104 | sec ; flag no zone info 105 | lda $c062 ; check closed-apple/option 106 | bpl :++ ; skip if not pressed 107 | : lda #'Z'+$80 108 | sta NotifyLoc ; tell user we are getting our zone 109 | jsr GetZone 110 | : jsr DispInfo ; carry set = do not try to display zone from NBPBuf 111 | lda #'L'+$80 112 | sta NotifyLoc ; tell user we are looking for server 113 | jsr FindSrv 114 | bcc :+ ; found it 115 | jsr NoServer ; didn't find one... sorry 116 | bra die 117 | : jsr DispServ ; give user boot network location 118 | lda #'B'+$80 119 | sta NotifyLoc ; tell user we are gonna boot 120 | ldx #3 ; copy boot server addr to ATP req 121 | : lda NBPBuf,x 122 | sta ATPaddr,x 123 | stz mli,x ; and zero out ProDOS MLI entry point, too, 124 | ; because the Logon program might check this and 125 | ; avoid initializing the card. 126 | dex 127 | bpl :- 128 | ; brk ; DEBUG 129 | jmp ATPBoot ; go to $300 code 130 | .endproc 131 | 132 | ; Find workstation card, since the //e Card is flexible about its 133 | ; placement. Also we can run on a regular //e with a Workstation Card 134 | ; for no particular reason. 135 | .proc FindCard 136 | lda #$f9 ; offset to ID bytes 137 | sta CardPtr 138 | lda #$c7 ; start at slot 7 139 | sta CardPtr+1 140 | nextslot: ldy #3 ; check ID bytes 141 | : lda (CardPtr),y 142 | cmp idtbl,y 143 | bne nomatch 144 | dey 145 | bpl :- 146 | ldy #4 ; This is card type byte offset 147 | ; 0 = IIgs 148 | ; 1 = Workstation Card 149 | ; 2 = unseen Server(!) Card 150 | ; $F0 = card diags in progress 151 | : lda (CardPtr),y 152 | sta NotifyLoc ; a little visual info 153 | cmp #$f0 ; Shouldn't happen on LC Card, but... 154 | beq :- ; wait for it all the same 155 | cmp #1 ; Because it's proper to make sure it's a working WS Card 156 | beq gotcard ; found it! 157 | nomatch: dec CardPtr+1 ; next slot 158 | lda CardPtr+1 ; get it 159 | cmp #$c0 ; hit slot 0? 160 | bne nextslot ; nope 161 | sec ; no card found 162 | rts 163 | gotcard: clc ; card found 164 | rts 165 | idtbl: .byte "ATLK" 166 | .endproc 167 | 168 | ; Initialize the WorkStation Card 169 | .proc InitCard 170 | sei ; disable interrupts for now 171 | lda #CardInt 174 | sta IRQvect+1 175 | lda CardPtr+1 176 | sta GoCard+2 ; init card MLI call addr 177 | sta CardInt+2 ; init card interrupt addr 178 | ATcall iniparms 179 | done: cli ; re-enable interrupts 180 | rts 181 | ; AppleTalk init call parms. Undocumented for the most part. 182 | iniparms: .byte 0,1 ; synchronous init 183 | .word $0000 ; result code, most likely 184 | .byte $00 ; init type. Known types & users: 185 | ; $00 - partial init, no MLI global page update 186 | ; used by: ETalk (ethernet NetBoot) 187 | ; $80 - full init, no MLI global page update 188 | ; used by: ETalk (no NetBoot), Fizzy 189 | ; Possibly not usable on WS Card. 190 | ; $40 - full init, MLI global page update 191 | ; used by: ATInit, Logon (boot block version) 192 | .dword $00000000 ; "ProDOS" entry point - zero seems to work 193 | ; if not using global page update 194 | .byte $00 ; node num preference, 0 = any node number 195 | .word $0000 ; unknown or reserved 196 | .endproc 197 | 198 | ; do GetInfo call 199 | .proc GetInfo 200 | ATcall inforeq 201 | bcs done 202 | lda abridge 203 | sta ATbridge 204 | lda thisnet 205 | sta ATnet 206 | lda thisnet+1 207 | sta ATnet+1 208 | lda nodenum 209 | sta ATnode 210 | done: rts 211 | inforeq: .byte 0,2 ; sync GetInfo 212 | .word $0000 ; result code 213 | .dword $00000000 ; completion address 214 | thisnet: .word $0000 ; this network # 215 | abridge: .byte $00 ; local bridge 216 | .byte $00 ; hardware ID 217 | .word $00 ; ROM version 218 | nodenum: .byte $00 ; node number 219 | .endproc 220 | 221 | ; Display our info. If carry is clear, try to display zone name 222 | ; from results of GetMyZone in NBPBuf 223 | ; i.e. call GetInfo, then call GetMyZone, then call this. 224 | .proc DispInfo 225 | php 226 | lda #17 ; line 18 227 | jsr tabv 228 | stz ch ; col 0 229 | ; display our address 230 | lda ATnet ; network is 16-bit 231 | ldx ATnet+1 232 | jsr PrintU16 233 | lda #'.'+$80 ; standard separator 234 | jsr cout 235 | lda #$00 236 | ldx ATnode ; node number 237 | jsr PrintU16 238 | ; display bridge node if present 239 | lda ATbridge 240 | beq :+ ; skip if 0 241 | ldx #msg4-msg1 ; " bridge ." 242 | jsr Disp 243 | lda #$00 244 | ldx ATbridge 245 | jsr PrintU16 246 | : plp ; see if we should display zone 247 | bcs done ; nope 248 | ; display zone 249 | ldx #msg5-msg1 ; " zone " 250 | jsr Disp 251 | jsr DispZone ; display it 252 | done: rts 253 | .endproc 254 | 255 | ; Get our zone - for information 256 | .proc GetZone 257 | ATcall zonereq 258 | bcs done ; error, bail 259 | lda NBPBuf ; check pascal str count 260 | bne done ; if nonzero, done 261 | sec ; otherwise signal error 262 | done: rts 263 | zonereq: .byte 0,$1a ; sync GetMyZone 264 | .word $0000 ; result 265 | .dword $00000000 ; completion 266 | .dword NBPBuf ; we'll use the NBP buffer since zone is just FYI 267 | .byte 4,4 ; 4 times every 1 sec 268 | .word $0000 ; reserved 269 | .endproc 270 | 271 | .proc DispZone 272 | ; below commented out because we assume we are called from DispInfo 273 | ;lda #17 ; line 19 274 | ;jsr tabv 275 | ;stz ch ; col 0 276 | ldx #$00 277 | : cpx NBPBuf ; did we display all of them? 278 | beq done ; yes, done 279 | lda NBPBuf+1,x ; get char 280 | ora #$80 281 | jsr cout ; display 282 | inx ; next 283 | bra :- 284 | done: rts 285 | .endproc 286 | 287 | ; Find a boot server in our zone 288 | .proc FindSrv 289 | ATcall lookup 290 | bcs done ; error, bail 291 | lda matches ; check # matches 292 | bne done ; OK if not zero 293 | sec 294 | done: rts 295 | ; parameter list for NBPLookup 296 | lookup: .byte 0,16 ; sync NBPLookup 297 | .word $0000 ; result 298 | .dword $00000000 ; completion 299 | .dword srvname ; pointer to name to find 300 | .byte 8,16 ; 16 times, every 2 secs 301 | .word $0000 ; reserved 302 | .word NBPBufSz ; buffer size 303 | .dword NBPBuf ; buffer loc 304 | .byte 1 ; matches wanted 305 | matches: .byte $00 ; matches found 306 | srvname: .byte 1,"=" ; object 307 | .byte 14,"Apple //e Boot" ; type 308 | .byte 1,"*" ; zone 309 | .endproc 310 | 311 | ; Display found boot server address and object name 312 | .proc DispServ 313 | lda #18 ; line 19 314 | jsr tabv 315 | stz ch ; col 0 316 | ; display the server address 317 | lda NBPBuf ; network is 16-bit 318 | ldx NBPBuf+1 319 | jsr PrintU16 320 | lda #'.'+$80 ; standard separator 321 | jsr cout 322 | lda #$00 323 | ldx NBPBuf+2 ; node number 324 | jsr PrintU16 325 | lda #'/'+$80 ; standard separator 326 | jsr cout 327 | lda #$00 328 | ldx NBPBuf+3 ; socket number 329 | jsr PrintU16 330 | lda #' '+$80 331 | ; now display server object name 332 | jsr cout 333 | ldx #$00 334 | : cpx NBPBuf+5 ; did we display all of them? 335 | beq done ; yes, done 336 | lda NBPBuf+6,x ; get char 337 | ora #$80 338 | jsr cout ; display 339 | inx ; next 340 | bra :- 341 | done: rts 342 | .endproc 343 | 344 | ; Print unsigned 16-bit integer 345 | ; adapted from 346 | ; https://groups.google.com/forum/#!topic/comp.sys.apple2/_y27d_TxDHA 347 | .proc PrintU16 348 | stx DispTmp 349 | sta DispTmp+1 350 | lda #$00 351 | : pha 352 | lda #$00 353 | clv 354 | ldy #$10 355 | : cmp #$05 356 | bcc :+ 357 | sbc #$85 358 | sec 359 | : rol DispTmp 360 | rol DispTmp+1 361 | rol a 362 | dey 363 | bne :-- 364 | ora #$b0 365 | bvs :--- 366 | : jsr cout 367 | pla 368 | bne :- 369 | rts 370 | .endproc 371 | 372 | ; we are dead and can't even start downloading boot blocks 373 | ; so go to next slot if we are booting, or hang otherwise 374 | ; can't be used after we go to $300 code 375 | .proc Death 376 | lda $00 ; $00 must be 0 377 | bne :+ ; or we are not booting 378 | lda $01 379 | and #$f0 380 | cmp #$c0 ; $01 must be $Cx 381 | bne :+ 382 | lda #$ff 383 | jsr wait ; wait a bit so user can see message 384 | jmp $faba 385 | : sta clraltchar ; make sure alt char set is off 386 | lda #$58 ; flashing (red) X 387 | sta DeathLoc ; on screen 388 | hang: bra hang ; hang 389 | .endproc 390 | 391 | ; display the "no boot server" message 392 | .proc NoServer 393 | ldx #msg3-msg1 394 | bra Disp 395 | .endproc 396 | 397 | ; display the "something went wrong" message 398 | .proc ErrorMsg 399 | ldx #msg2-msg1 400 | bra Disp 401 | .endproc 402 | 403 | ; display the greeting 404 | .proc HelloMsg 405 | jsr title ; apple ii title screen (card boot clears screen) 406 | ldx #msg1-msg1 ; better be zero! 407 | ; fall-through 408 | .endproc 409 | 410 | ; Display one of the messages, can't be used after we go to $300 code 411 | .proc Disp 412 | lda msg1,x 413 | bne :+ 414 | rts 415 | : inx ; set up for next message byte 416 | cmp #$18 ; last line + 1 417 | bcc repos 418 | eor #$80 419 | jsr cout ; not supposed to change anything 420 | bra Disp 421 | repos: jsr tabv ; destroys a and y, but not x 422 | lda msg1,x ; get horizontal 423 | sta ch ; and write 424 | inx ; next message byte 425 | bra Disp 426 | .endproc 427 | 428 | msg1: .byte 05,08,"NetBoot LC v1.0 by M.G." 429 | .byte 06,05,"Starting up over the network...",$00 430 | msg2: .byte 08,09,"Something went wrong!",$00 431 | msg3: .byte 08,12,"No boot server!",$00 432 | msg4: .byte ", bridge .",$00 433 | msg5: .byte ", zone ", $00 434 | 435 | ; move $300 code into position 436 | .proc ReloBoot 437 | ldx #BootOSize+1 438 | : lda BootRStrt-1,x 439 | sta $0300-1,x 440 | dex 441 | bne :- 442 | rts 443 | .endproc 444 | 445 | ; Code to be moved to $300 follows 446 | BootRStrt = * 447 | .org $0300 448 | BootOBgn = * 449 | ; Call the card's MLI 450 | .proc GoCard 451 | jmp $C714 ; For slot 7, modify in InitCard 452 | .endproc 453 | 454 | ; Provide an interrupt handler for the card 455 | .proc CardInt 456 | jsr $C719 ; For slot 7, modify in InitCard 457 | rti 458 | .endproc 459 | 460 | ; Boot using ATP requests to retrieve boot blocks. 461 | .proc ATPBoot 462 | fetch: lda #1 463 | sta ATPbmap ; want only block 0 (ATP-wise) 464 | ATcall ATPparms 465 | bcs error ; oops 466 | lda Status ; is EOF? 467 | beq :+ ; keep reading if not EOF 468 | sei ; otherwise, no more interrupts 469 | jmp BootStart ; and execute next boot stage 470 | : inc BlkNum ; implicitly limited, below 471 | lda BlkNum ; get it for spinner 472 | and #$03 ; mask in low bits 473 | tay 474 | lda spinner,y ; get spinner char 475 | sta SpinLoc ; put on middle of screen 476 | lda BlkPtr+1 ; block pointer (load addr) 477 | clc 478 | adc #$02 ; $200 bytes 479 | sta BlkPtr+1 ; inc address 480 | cmp #$c0 ; Reading too far? 481 | bcc fetch ; read next block if not 482 | error: jsr bell1 ; beep speaker 483 | lda #$58 ; flashing (red) X 484 | sta SpinLoc ; on screen 485 | hang: bra hang 486 | spinner: .byte '|'+$80 487 | .byte '/'+$80 488 | .byte '-'+$80 489 | .byte '\'+$80 490 | .endproc 491 | ATbridge: .byte $00 ; local bridge 492 | ATnet: .word $0000 ; local net 493 | ATnode: .byte $00 ; our node number 494 | ATPparms: .byte 0,18 ; sync SendATPReq 495 | .word $0000 ; result 496 | .dword $00000000 ; compl. addr 497 | .byte $00 ; socket # 498 | ATPaddr: .dword $00000000 ; destination address 499 | .word $0000 ; TID 500 | .word $0000 ; req buffer size 501 | .dword $00000000 ; req buffer addr 502 | .byte $02 ; boot type 503 | ; $01 = IIgs stage 1 504 | ; $02 = //e 505 | ; $03 = IIgs boot image 506 | BlkNum: .word $0000 ; block number to req 507 | .byte $00 ; unused 508 | .byte $01 ; one response buffer 509 | .dword BDS ; pointer to response BDS 510 | .byte $00 ; ATP flags 511 | .byte 8,32 ; try 32 times every 2 seconds 512 | ATPbmap: .byte $00 ; bitmap of blocks to recieve 513 | .byte $00 ; number of responses 514 | .res 6 ; 6 bytes reserved 515 | BDS: .word $0200 ; length of buffer 516 | BlkPtr: .dword BootStart ; block pointer 517 | Status: .dword $00000000 ; returned user bytes, first byte = 1 if EOF 518 | .word $0000 ; actual length 519 | BootOEnd = * 520 | .assert BootOEnd < $3d0, warning, "Page 3 code too big" 521 | BootOSize = BootOEnd - BootOBgn 522 | ; end of $300 code, fix up origin 523 | .org BootRStrt + BootOSize 524 | 525 | NBPBuf = (* >> 8 + 1)*$100 ; put this on next page boundary 526 | .out .sprintf("NBP Buffer at $%x", NBPBuf) 527 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NetBoot LC 2 | 3 | NetBoot LC is an alternative Apple II Workstation boot program for the Apple //e Card for Macintosh LC. 4 | 5 | The built-in Apple II Workstation functionality of the card closely mimics the combination of an Enhanced //e with a Workstation Card in all aspects except two: 6 | 7 | - It shares the AppleTalk node address with the host Macintosh. This is not really a problem, because most client applications don't care what the node number is (unless you want to access File Sharing or an AppleShare server on the host Macintosh - see here). 8 | - It does not load the boot blocks over the network, instead they are contained within the IIe Startup application's BBLK resources. This might be a problem depending on your use cases or preferences. For reference, the Apple II boot blocks contain ProDOS and the Logon program. 9 | 10 | The main problems I see with the “firm-coded” boot blocks are: 11 | 12 | They are more difficult to update as they require use of ResEdit each time a new ProDOS is released. While this was not a problem for some 25 years, new ProDOS releases have changed that. 13 | The behavior is not the same as the combination of Enhanced //e and Workstation Card. 14 | It is not clear to me why Apple decided to do it differently in the //e Card. My guesses are: It adds a little bit of speed; it prevents some administrative issues where the boot blocks served over the network have not been updated to meet a requirement of the card; and perhaps the engineers of the Card knew that the next version of AppleShare Server was going to drop Apple II boot support. 15 | 16 | In any case, after a small and successful quest to update the boot blocks to ProDOS 2.4.1 and Logon 1.5, I decided that I wanted the //e Card to boot like my other //es with Workstation Cards, and NetBoot LC is the result. 17 | 18 | ## What it Does 19 | 20 | NetBoot LC replaces the firm-coded ProDOS 1.9 and Logon 1.3 boot blocks in the IIe Startup program with a new program that downloads boot blocks over the network like any Enhanced //e with a Workstation Card. 21 | 22 | Along the way, it also provides some useful info such as the the workstation node address, bridge node number, AppleTalk zone, and boot server address and name. There is a nice spinner that lets you know something is happening. 23 | 24 | If the boot is happening due to system cold start and fails before the boot block download starts, the next slot will be tried (if “scan” is configured in the slot preferences). 25 | 26 | A status letter is indicated on the lower-left corner of the screen, useful for figuring out what is slow or failing: 27 | 28 | * ``F``: Finding Workstation Card. 29 | * ``R``: Relocating $300 code. 30 | * ``I``: Initializing Workstation Card & Getting Info. 31 | * ``Z``: Identifying local Zone. 32 | * ``L``: Looking for boot server. 33 | * ``B``: Downloading boot blocks. At this point spinner will start after the first block is retrieved. 34 | 35 | ## Building 36 | 37 | The only supported build environment for the moment is MacOS X. 38 | 39 | Requirements: 40 | 41 | * Working cc65 installation with binaries in PATH. 42 | * Apple command-line developer tools (``xcode-select --install``). 43 | * Make sure you have the following binaries in your PATH: 44 | * ``hexdump`` 45 | * ``Rez`` 46 | * ``macbinary`` 47 | 48 | There is a make target to build a disk image and execute in Virtual ][. To use it you will need AppleCommander and will need to edit the Makefile. This is for testing and is otherwise not necessary to build the code and use it. 49 | 50 | The build process uses resource forks, your filesystem must support them. 51 | 52 | To build, change to the project directory and execute ``make``. 53 | 54 | ## Installation 55 | 56 | - Download NetBoot LC to your Macintosh. 57 | - Decode the Macbinary file. The resulting file will look like an application, but it is not and clicking it will do nothing. 58 | - Open NetBoot LC and a copy of IIe Startup in ResEdit. 59 | - Open the BBLK resources in the copy of IIe Startup, there should be one resource with ID 5120. 60 | - Delete BBLK ID 5120. 61 | - Open the BBLK resources in NetBoot LC. 62 | - Copy ID 5120 from NetBoot LC to the BBLK resources in the copy of IIe Startup. 63 | - Quit ResEdit, save the copy of IIe Startup on your way out. 64 | 65 | At this point launching IIe Startup and booting over AppleTalk should work as described above. 66 | 67 | Obviously, to be useful, you need an AppleShare 2.x/3.x server or netatalk server, with Apple II booting set up, to make use of this. 68 | 69 | ## Technical / Developing 70 | 71 | I recommend having a look at the source code. It's a bit of a mess but it demonstrates some undocumented Apple II AppleTalk functionality, as well as use of ATP. 72 | 73 | If you add features or fix bugs, please send a pull request. 74 | 75 | 76 | -------------------------------------------------------------------------------- /t: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgcaret/NetBoot_LC/e6e9da709b8300e9b1c7ad99e9628a63da23c67c/t -------------------------------------------------------------------------------- /utils/blocks2rez.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | if [ ! -r "$1" ]; then 4 | echo "Usage: $0 " 5 | exit 1 6 | fi 7 | TFILE=`mktemp` 8 | hexdump -v -f `dirname $0`/rezhex.format "$1" | tr 'Q' '"' > $TFILE 9 | cat << EOF 10 | type 'BBLK' { 11 | hex string; 12 | }; 13 | 14 | resource 'BBLK' (5120, "Apple //e Boot Blocks") { 15 | `cat $TFILE` 16 | }; 17 | EOF 18 | rm -f $TFILE 19 | 20 | -------------------------------------------------------------------------------- /utils/rezhex.format: -------------------------------------------------------------------------------- 1 | "$Q" 1/1 "%02.2X" 1/1 "%02.2X " 1/1 "%02.2X" 1/1 "%02.2X " 1/1 "%02.2X" 1/1 "%02.2X " 1/1 "%02.2X" 1/1 "%02.2X " 1/1 "%02.2X" 1/1 "%02.2X " 1/1 "%02.2X" 1/1 "%02.2X " 1/1 "%02.2X" 1/1 "%02.2X " 1/1 "%02.2X" 1/1 "%02.2X" "Q\n" 2 | --------------------------------------------------------------------------------