; AZMNT_09 r09 EXPERIMENT: r05 + ONLY two-instruction STOP handler / 2026-10-18 ; Hardware baseline remains r05. No IRQ masks added in controller/SD paths. ; Parent: user-tested AZMNT_03 r01 controller table read. ; Read-only controller mapping: 32 x 396 bytes, staged 4-page banks. ; All D00-D31 geometry; paths now come from controller, not demo. ; Double buffered mono framebuffer with DMA011 and frame IRQ. ; Source: r16, 2026-10-17; MUST be assembled/tested before hardware release. ; BK strings English; constants/octals default (trailing dot = decimal). ; Controller reads: 000/027/011/015; browser: 016/003/013/015. ; Network service: 110 when idle; 000 at start of each controller transaction. ; AZMNT_09 r04: bounded STM32 READY/CSR checks after controller map DR streams. ; AZMNT_09 r03: SOB range correction + AZMNT_09 source naming. ; AZMNT_09 r02: agreed MicroSD guards and 5 transaction retries on INI transport faults. ; r09 MAIN automatically refreshes AZINI.BAK AFTER explicit YES, then writes + checks AZ.INI. ; INI read 023/050/051/052/022; MAIN write 023/053/051/054/023/055; reset+037. ; R03 fixes W5 high-byte row COUNT to match measured BK DMA semantics. ; R02 telemetry retained; nested paths optionally probed without trailing /. ; 016+Dnn+014 unmount / 016+004 mount only after explicit YES; MAIN AZ.INI protected by BAK. ; V18+ mandatory; no firmware downgrade permitted. .LA 1000 ; ----- constants (octal unless followed by decimal point) ----- AZCSR = 177220 AZDR = 177222 NET_ENABLE_CMD = 110 ; network+IRQ enable for idle periods (AZ firmware) FPGA_REG = 177370 VIDMODE_REG = 177230 VIDBASE_REG = 177232 VSCROLL = 177250 HSCROLL = 177252 WIN120 = 177324 WIN130 = 177326 WIN170 = 177336 ; CPU AZ RAM fast window 170000..176777 (3584 bytes) WIN170_MASK = 100000 ; mask bit for CPU window 170000 AZ_DATA_PAGE = 2140 ; dedicated AZ RAM 4KiB page, only first 3584 CPU visible AZ_DATA_PROBE = 176770 ; last safe aligned word before I/O at 177000 ; Fixed absolute addresses: no .blkb bytes in regular 32KiB BK image. ; This memory becomes accessible only after HW_EnterMono initializes WIN170. BR_Entries = 170000 ; 64 * 22-byte browser cache; also AP/SG scratch AP_OldPath = BR_Entries SG_SavedPath = BR_Entries AP_NewPath = 170602 ; +386 decimal AP_MountText = 171404 ; +772 decimal BR_EntriesTail = 172214 ; +1164 decimal; browser last 244 bytes BR_Path = 172600 ; +1408 decimal, 256-byte browser current path BR_SelectedPath = 173200 ; +1664 decimal, 260-byte selected file path INI_Line = 173604 ; +1924 decimal, 512-byte parser/generator buffer ; Last occupied byte 174603, so 174604..176777 remain available. WIN_ENABLE = 177340 WIN_RO = 177342 WIN_DENY = 177344 SYSCTRL = 177346 SYSCTRL_SHADOW = 177352 SYSCTRL716 = 177716 KEYCSR = 177660 KEYDATA = 177662 VIDMODE = 021100 ; 512 x 384 x 1, 6 pages VRAM_PAGE = 2000 ; user approved AZ RAM 1000..4000 VRAM_NPAGES = 6. ; decimal 6; pages 2000..2005 MON_FONT_PAGE = 135 AZBOOT_PAGE = 100 FONT130_BASE = 131576 ; 111576 remapped 110000 -> 130000 K_ENTER = 12 K_ESC = 3 K_SPACE = 40 K_DEBUG = 2 ; BK IND SU = 0202 oct (10000010b), KEYDATA 7-bit => 0002 K_LEFT = 10 K_RIGHT = 31 K_UP = 32 K_DOWN = 33 KEY_TIMER_PRESET = 1165. ; 50ms, from AZVIDT24 KEY_TIMER_FIRST = 11655. ; 500ms initial arrow hold, AZVIDT24 PATH_COL = 9. ; "A: D00 = ": path begins column 9 PATH_VIEW = 55. ; 64 cols - 9 chars prefix FOCUS_MAX = 35. ; 0..31 disks, 32 READ, 33 WRITE, 34 EXIT, 35 HELP STM_MIN = 18. ERR_NO_AZ = 1 ERR_FW_OLD = 2 ERR_API_TIMEOUT = 3 ERR_API_STATUS = 4 ERR_ROM = 5 ERR_MAP_STATUS = 6 ERR_MAP_BAD = 7 AW_READBACK_BANK = 2100 ; 8 pages, never touches source AZ.INI or WORK SG_OUTPUT_BANK = 2110 ; 8 pages canonical WORK-derived AZ2.INI SG_CHECK_BANK = 2120 ; 4 pages parse-and-compare scratch mapping AB_FRESH_BANK = 2130 ; 8 pages fresh AZ.INI on-card copy, distinct from original/WORK AP_ACTUAL_BANK = 2061 ; pages 2061..2064, independent real-controller snapshot MAP_BANK_A = 2065 ; pages 2065..2070 MAP_BANK_B = 2071 ; pages 2071..2074 INI_FILE_BANK_A = 2020 ; octal physical pages 2020..2027 (32KiB) INI_FILE_BANK_B = 2030 ; octal physical pages 2030..2037 (32KiB) INI_MAX_BYTES = 32768. INI_LINE_LIMIT = 511. BR_BACKUP_PAGE = 2050 ; pages 2050..2052, exactly 12000 B DL_BACKUP_PAGE = 2055 ; dedicated 4KB page for 46x6 confirmation (2760 B) DL_BACK_LOW = 064000 ; physical WORD offset of 2055; 32-word aligned DL_SCREEN_LOW = 011304 ; pixel y150, text col8 -> word(150*32+4) DL_W5 = 0036026 ; 60 scanlines x 23 words: actual height=60, width-1=22 DL_W6 = 12 ; 32-(23-1) = 10 decimal = octal 12 BR_WIN_X = 8. ; popup 48 glyphs at x64 pixels BR_WIN_Y = 7. ; popup 25 glyphs at y70 pixels BR_ROWS = 18. ; visible directory entries y11..28 BR_MAX_ENTRIES = 16384. ; guard for endless/corrupt FAT iterator BR_MARK_WIDTH = 46. ; highlight x9..54 incl name AND filesize; frame x8/x55 untouched BR_CACHE_SIZE = 64. ; 64 * 22 = 1408 BK bytes BR_CACHE_STEP = 32. ; recache only after leaving 64-entry window BR_SCROLL_BACK = 2053 ; temporary AZ RAM pages 2053..2054 BR_SCROLL_LOW = 054000 ; 2053 physical word offset; 3740 words BR_SCROLL_W5 = 0125025 ; 170 lines x 22 words; hardware row COUNT BR_SCROLL_W6 = 13 ; 32 - 22 + 1 = decimal 11 stride BR_SCROLL_UP_IN = 007405 ; y120 row12, x10 (5 words) BR_SCROLL_UP_OUT= 006705 ; y110 row11, x10 BR_SCROLL_DN_IN = 006705 ; y110 row11, x10 BR_SCROLL_DN_OUT= 007405 ; y120 row12, x10 BR_PAGE1_W5 = 0140027 ; W5.HI=192 actual lines; LO=23 (24 words) BR_PAGE2_W5 = 0035027 ; W5.HI=58 actual lines; LO=23 (24 words) BR_SCREEN1_LOW = 004304 ; word offset y70*32 + 4 BR_SCREEN2_LOW = 020304 ; word offset y262*32 + 4 BR_BACK1_LOW = 040000 ; page 2050 begin BR_BACK2_LOW = 051000 ; after 192*24 words BR_WIDTH_STEP = 11 ; 32 - (24 - 1) = 9 decimal MAP_RECORD_LEN = 396. MAP_PATH_OFFSET = 10. MAP_PATH_BYTES = 386. MAP_WORDS = 6336. ; exactly 32*396/2, 12672 bytes ; ABI codes 3/4 retain their original meaning; APIStage identifies phase. API_STAGE_RESET = 1 API_STAGE_027 = 2 BOX_TL = 252 ; octal, top-left corner (BK Monitor ROM) BOX_TR = 243 ; octal, top-right corner BOX_BL = 246 ; octal, bottom-left corner BOX_BR = 271 ; octal, bottom-right corner BOX_H = 265 ; octal, horizontal line BOX_V = 267 ; octal, vertical line ; AZ RAM scratch pages are isolated from firmware disk data. BL_REG = 177270 BL_PACKET_REG = 177272 BL_PACKET_PAGE = 2056 BL_SOURCE_PAGE = 2057 BL_DEST_PAGE = 2060 BL_POISON = 052345 ; guard for six-page clone ; ----- Entry: bus-error trap is installed ONLY for ONE 4-byte MOV ----- Begin: clr NetReadyToUse ; No-AZ early keyboard MUST NOT write AZCSR clr NetIdleOn mov @#4,OldBusPC mov @#6,OldBusPSW mov #ProbeBusErr,@#4 mov #340,@#6 clr BusFault clr FPGAValue mov @#FPGA_REG,R0 ; 4-byte instruction if it traps mov R0,FPGAValue mov OldBusPC,@#4 mov OldBusPSW,@#6 tst BusFault bne NoAZ tst FPGAValue beq NoAZ cmp FPGAValue,#177777 beq NoAZ ; r09: install STOP only after successful FPGA probe and vector restoration. ; 004/006 is shared with genuine bus errors: diagnostics must not use this build. mov #STOP_Ignore,@#4 mov #340,@#6 jmp HW_Snapshot ProbeBusErr: inc BusFault add #4,(SP) ; skip faulting MOV @#addr,R0 rti ; r09: IRQ1/STOP: the next instruction word is RTI=000002; rewind saved PC. ; PSW is restored from exception stack by RTI. Not safe for genuine bus faults. STOP_Ignore: sub (PC),(SP) rti ; Even the earliest probe error must remain on screen until a key. ; BK standard keyboard registers exist without AZ; do not write AZ-only ; state. Temporarily mask BK key IRQ and restore its original mask. NoAZ: mov #MsgNoAZ,R3 jsr PC,MON_Print mov #MsgPressKey,R3 jsr PC,MON_Print mov @#KEYCSR,R0 bic #177677,R0 mov R0,OldKeyMask bis #100,@#KEYCSR jsr PC,KEY_ReadOne tst OldKeyMask bne NoAZFinish bic #100,@#KEYCSR NoAZFinish: jmp @#100000 ; ----- State snapshot: exact push/pop order from AZVIDT24 ----- ; Important: SYSCTRL_SHADOW is READ of 177716 configuration; writing ; the saved value back goes to 177716, NOT 177352. HW_Snapshot: mov @#VIDMODE_REG,-(SP) mov @#VIDBASE_REG,-(SP) mov @#VSCROLL,-(SP) mov @#HSCROLL,-(SP) mov @#WIN120,-(SP) mov @#WIN130,-(SP) mov @#WIN170,-(SP) ; original upper-window bank for ANDOS mov @#100,-(SP) mov @#102,-(SP) mov @#WIN_ENABLE,-(SP) mov @#WIN_RO,-(SP) mov @#WIN_DENY,-(SP) mov @#SYSCTRL_SHADOW,-(SP) mov @#SYSCTRL,-(SP) mov #1,HW_Saved ; Preserve ORIGINAL keyboard IRQ masked/unmasked state. mov @#KEYCSR,R0 bic #177677,R0 ; keep only bit 0100 mov R0,OldKeyMask ; Stage02 saves+uses BK timer 177706/177712 for polling. ; H briefly owns vectors 100/102 and restores them. jsr PC,API_GetVersion tst R0 beq GateAPIOK jmp GateAPIError GateAPIOK: mov STM_Major,R0 cmp R0,#STM_MIN bhis GateFWOK jmp GateUnsupported GateFWOK: jsr PC,HW_EnterMono tst R0 beq GateVideoOK jmp GateInitError GateVideoOK: mov #1,NetReadyToUse ; FPGA+firmware+video initialization passed ; No D00-D31 list until user successfully selects source. ; Only the framed LOAD DISK MAPPING modal is visible. jsr PC,UI_Clear6Pages clr DebugMode ; explicitly OFF on each new launch clr ModalSource jsr PC,UI_ModalStub ; Initial source selection modal precedes the main event loop. ModalKey: jsr PC,KEY_ReadOne cmp R0,#K_ESC beq ModalExit cmp R0,#K_LEFT beq ModalUseController cmp R0,#K_RIGHT beq ModalUseIni cmp R0,#K_ENTER beq ModalContinue br ModalKey ModalUseController: tst ModalSource beq ModalKey ; do not redraw same selection jsr PC,UI_ModalHighlight ; old choice OFF (XOR) clr ModalSource jsr PC,UI_ModalHighlight ; new choice ON jsr PC,UI_ModalRefresh ; only dynamic status row br ModalKey ModalUseIni: tst ModalSource bne ModalKey jsr PC,UI_ModalHighlight mov #1,ModalSource jsr PC,UI_ModalHighlight jsr PC,UI_ModalRefresh br ModalKey ModalExit: jmp HW_Exit ModalContinue: tst ModalSource bne ModalReadIni jsr PC,MAP_LoadController tst R0 bne ModalReadFailed mov #1,MapSource br ModalMapOK ModalReadIni: jsr PC,INI_LoadMapping tst R0 beq ModalMapOK mov R0,MapErrorCode mov INI_LastCSR,MapLastCSR ModalReadFailed: jsr PC,UI_ModalReadError jmp ModalKey ModalMapOK: jsr PC,NET_EnableIdle ; enable network before slow UI redraw clr WorkDirty clr WorkOriginalBase jsr PC,UI_RenderAll clr FocusIndex clr ReadTarget clr WriteTarget clr MarqueeOffset clr HeldArrow clr PendingCommand mov #1,AppMain jsr PC,UI_DrawFocus jsr PC,UI_DrawStatus jsr PC,CLK_Start jmp MainKey ; Native navigation. The long selected path animates after 1s idle. MainKey: jsr PC,KEY_Poll tst R0 beq MainKey cmp R0,#K_DEBUG bne MainNotStep jsr PC,APP_ToggleDebug jmp MainKey MainNotStep: cmp R0,#K_ESC beq MainExit cmp R0,#K_UP beq FocusUp cmp R0,#K_DOWN beq FocusDown cmp R0,#K_LEFT beq FocusLeft cmp R0,#K_RIGHT beq FocusRight cmp R0,#K_ENTER bne MainNotEnter jmp FocusEnter MainNotEnter: cmp R0,#K_SPACE bne MainNotSpace jmp FocusClear MainNotSpace: br MainKey ; KT from the mapping list returns to the source chooser, NOT ANDOS. MainExit: jsr PC,APP_ConfirmDiscard tst R0 bne APP_MainResume jsr PC,APP_BackToSource jmp ModalKey APP_MainResume: jmp MainKey FocusUp: jsr PC,UI_ResetMarquee ; normal A is restored by scroll session jsr PC,UI_DrawFocus ; XOR toggles old highlight OFF tst FocusIndex bne FocusUpDec mov #FOCUS_MAX,FocusIndex br FocusChanged FocusUpDec: dec FocusIndex br FocusChanged FocusDown: jsr PC,UI_ResetMarquee jsr PC,UI_DrawFocus inc FocusIndex cmp FocusIndex,#FOCUS_MAX blos FocusChanged clr FocusIndex FocusChanged: clr MarqueeOffset clr MarqueeAge clr MarqueeDone jsr PC,UI_DrawFocus ; new focus ON jmp MainKey FocusLeft: mov FocusIndex,R0 cmp R0,#35. beq FocusLeftHelp cmp R0,#32. beq FocusReadLeft cmp R0,#33. beq FocusWriteLeft jmp MainKey ; disk: LEFT is NOT DELETE FocusLeftHelp: jsr PC,UI_DrawFocus mov #34.,FocusIndex jsr PC,UI_DrawFocus jmp MainKey FocusWriteLeft: jsr PC,UI_DrawFocus clr WriteTarget jsr PC,UI_DrawFocus jmp MainKey FocusReadLeft: jsr PC,UI_DrawFocus clr ReadTarget jsr PC,UI_DrawFocus jmp MainKey FocusRight: mov FocusIndex,R0 cmp R0,#34. beq FocusRightExit cmp R0,#32. beq FocusReadRight cmp R0,#33. beq BE_RightWrite jmp MainKey FocusRightExit:jsr PC,UI_DrawFocus mov #35.,FocusIndex jsr PC,UI_DrawFocus jmp MainKey BE_RightWrite: jsr PC,UI_DrawFocus mov #1,WriteTarget jsr PC,UI_DrawFocus jmp MainKey FocusReadRight: jsr PC,UI_DrawFocus mov #1,ReadTarget jsr PC,UI_DrawFocus jmp MainKey ; Explicit SPACE clears only a selected disk path in WORK. K_LEFT=010 ; collides with the historic ZB code and is NOT used as erase until the ; physical keyboard is characterized. Never repeat SPACE while held. FocusClear: cmp FocusIndex,#32. blo FocusClearDisk jmp MainKey FocusClearDisk: jsr PC,UI_ResetMarquee clrb @#BR_SelectedPath jsr PC,WORK_ApplyFile tst R0 bne FocusClearError tst WorkRowChanged beq FocusClearDone jsr PC,UI_RedrawSelectedDisk mov #37.,UY jsr PC,UI_DrawStatus FocusClearDone: jmp MainKey FocusClearError: mov #StrWorkError,R3 jsr PC,UI_StatusText jmp MainKey FocusEnter: cmp FocusIndex,#35. bne FE_NotHelp jsr PC,HL_Show jmp MainKey FE_NotHelp: cmp FocusIndex,#34. bne FocusEnterNoExit jsr PC,APP_ConfirmDiscard tst R0 beq FE_DiscardOK jmp APP_MainResume FE_DiscardOK: jsr PC,WORK_Discard jmp HW_Exit FocusEnterNoExit: cmp FocusIndex,#32. bne FE_NotRead jsr PC,APP_ConfirmDiscard tst R0 beq FE_ReadDiscardOK jmp APP_MainResume FE_ReadDiscardOK: jsr PC,WORK_Discard tst ReadTarget beq FE_ReadIni jsr PC,MAP_LoadController tst R0 beq FE_ReadOK jsr PC,UI_ShowMapError jmp MainKey FE_ReadOK: mov #1,MapSource FE_ReadRepaint: jsr PC,NET_EnableIdle ; enable network while displaying map clr WorkDirty clr WorkOriginalBase clr MarqueeDone clr MarqueeAge jsr PC,UI_RenderAll jsr PC,UI_DrawFocus jsr PC,UI_DrawStatus jmp MainKey FE_ReadIni: jsr PC,INI_LoadMapping tst R0 beq FE_ReadIniOK jsr PC,UI_ShowIniError jmp MainKey FE_ReadIniOK: jmp FE_ReadRepaint FE_NotRead: cmp FocusIndex,#33. bne FE_Browse tst WriteTarget bne FE_ApplyController ; r10: one safe BACKUP+MAIN+REBOOT path, no AZ2/BAK chooser. ; Historical test helpers remain in source but are not reachable. jsr PC,AM_MainSaveUI jmp MainKey FE_ApplyController: jsr PC,AP_ControllerUI jmp MainKey FE_Browse: jsr PC,UI_ResetMarquee jsr PC,BR_Run tst BR_Error bne FE_BrowseNoFile tst BR_HasSelection beq FE_BrowseNoFile jsr PC,WORK_ApplyFile tst R0 bne FE_WorkError tst WorkRowChanged beq FE_WorkNoChange jsr PC,UI_RedrawSelectedDisk mov #37.,UY jsr PC,UI_DrawStatus FE_WorkNoChange: jmp MainKey FE_WorkError: mov #StrWorkError,R3 jsr PC,UI_StatusText jmp MainKey FE_BrowseNoFile: tst BR_Error beq FE_BrowseNormalClose mov #StrBrowseErrorStatus,R3 jsr PC,UI_StatusText mov BR_Error,R1 jsr PC,UI_PrintDec2 cmp BR_Error,#11. beq FE_BrowserDiag cmp BR_Error,#12. bne FE_BrowserNoDiag FE_BrowserDiag: jsr PC,BR_PrintDmaDiag FE_BrowserNoDiag: jmp MainKey FE_BrowseNormalClose: ; A cancelled browser selection has NO visible side effect. ; BR_Close already restored the exact original pixels. jmp MainKey GateUnsupported: mov #MsgOldFW,R3 jsr PC,MON_Print jmp PreVideoPause GateAPIError: cmp #API_STAGE_RESET,APIStage bne GateCmdTimeoutTest cmp R0,#ERR_API_TIMEOUT bne GateResetStatus mov #MsgResetTimeout,R3 br GateAPIPrint GateResetStatus: mov #MsgResetStatus,R3 br GateAPIPrint GateCmdTimeoutTest: cmp R0,#ERR_API_TIMEOUT bne GateCmdStatus mov #MsgAPITimeout,R3 br GateAPIPrint GateCmdStatus: mov #MsgAPIStatus,R3 GateAPIPrint: jsr PC,MON_Print mov #MsgCSRPre,R3 jsr PC,MON_Print mov CSR_Pre,R1 jsr PC,MON_PrintOct6 mov #MsgCSRReset,R3 jsr PC,MON_Print mov CSR_Reset,R1 jsr PC,MON_PrintOct6 mov #MsgCSRCmd,R3 jsr PC,MON_Print mov CSR_Cmd,R1 jsr PC,MON_PrintOct6 jmp PreVideoPause GateInitError: cmp R0,#2 bne GateInitOther mov #Msg170Fail,R3 jsr PC,MON_Print jmp PreVideoPause GateInitOther: mov #MsgInitFail,R3 jsr PC,MON_Print jmp PreVideoPause ; Pre-video error MUST remain visible until a new physical key press. ; Prepare keyboard polling using AZVIDT24's known BK-0010 path, and ; reverse it through the saved 177352/177716 and 177660 state on exit. ; No video writes and no controller command is issued from here. PreVideoPause: mov #MsgPressKey,R3 jsr PC,MON_Print bis #100,@#KEYCSR mov #14020,@#SYSCTRL716 jsr PC,KEY_ReadOne jmp HW_Exit ; ------------------------------------------------------------------------ ; Editor workflow: source snapshots are immutable. First replacement clones ; current 4-page mapping into inactive bank, then changes WORK only. ; Dirty means WORK differs from originally loaded source. No API writes. ; A successful new source load clears WORK; failed load preserves it. ; ------------------------------------------------------------------------ WORK_ApplyFile: clr WorkRowChanged mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov FocusIndex,R0 jsr PC,MAP_GetPath tst R0 bne WORK_Bad mov #BR_SelectedPath,R2 mov #MapPathCache,R3 WORK_SameLoop: movb (R2)+,R0 cmpb R0,(R3)+ bne WORK_Changed tstb R0 bne WORK_SameLoop clr R0 br WORK_End WORK_Changed: mov #1,WorkRowChanged tst WorkDirty bne WORK_Write jsr PC,WORK_Clone tst R0 bne WORK_End WORK_Write: mov FocusIndex,R0 mov #MAP_PATH_OFFSET,R4 tst R0 beq WORK_OffsetDone WORK_OffsetLoop: add #MAP_RECORD_LEN,R4 sob R0,WORK_OffsetLoop WORK_OffsetDone: mov MapActiveBase,R5 WORK_FindPage: cmp R4,#4096. blo WORK_PageReady sub #4096.,R4 inc R5 br WORK_FindPage WORK_PageReady: mov R5,@#WIN120 mov #120000,R3 add R4,R3 mov #BR_SelectedPath,R2 mov #MAP_PATH_BYTES,R4 WORK_ByteLoop: movb (R2)+,R0 movb R0,(R3)+ tstb R0 bne WORK_HasText ; clear remaining record bytes including two NUL guards WORK_ZeroLoop: dec R4 beq WORK_Modified cmp R3,#130000 blo WORK_ZeroNoPage inc R5 mov R5,@#WIN120 mov #120000,R3 WORK_ZeroNoPage:clrb (R3)+ br WORK_ZeroLoop WORK_HasText: cmp R3,#130000 blo WORK_BytePageOK inc R5 mov R5,@#WIN120 mov #120000,R3 WORK_BytePageOK: sob R4,WORK_ByteLoop WORK_Modified: jsr PC,WORK_CheckCurrent clr R0 br WORK_End WORK_Bad: clr WorkRowChanged mov #1,R0 WORK_End: mov #VRAM_PAGE,@#WIN120 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; 16384-byte work map clone uses mapped 120000 (read) / 130000 (write). ; Protect existing ROM mapping by restoring WIN130 before UI rendering. WORK_Clone: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov MapActiveBase,WorkOriginalBase cmp MapActiveBase,#MAP_BANK_A beq WORK_UseB mov #MAP_BANK_A,R5 br WORK_CloneBegin WORK_UseB: mov #MAP_BANK_B,R5 WORK_CloneBegin:bic #4000,@#WIN_RO mov MapActiveBase,R4 mov #4.,R3 WORK_ClonePage: mov R4,@#WIN120 mov R5,@#WIN130 mov #120000,R1 mov #130000,R2 mov #2048.,R0 WORK_CloneWords:mov (R1)+,(R2)+ sob R0,WORK_CloneWords inc R4 inc R5 sob R3,WORK_ClonePage ; Destination is one of two distinct 4-page banks. cmp WorkOriginalBase,#MAP_BANK_A beq WORK_SetBankB mov #MAP_BANK_A,MapActiveBase br WORK_CloneDone WORK_SetBankB: mov #MAP_BANK_B,MapActiveBase WORK_CloneDone: bis #4000,@#WIN_RO mov #MON_FONT_PAGE,@#WIN130 mov #VRAM_PAGE,@#WIN120 clr R0 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Recompute dirty by comparing all four copied pages, not by ; remembering that the user edited once. Reverting to original source ; automatically restores original bank as active and clears dirty. WORK_CheckCurrent: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov MapActiveBase,R4 mov WorkOriginalBase,R5 mov #4.,R3 WORK_CheckPage: mov R4,@#WIN120 mov R5,@#WIN130 mov #120000,R1 mov #130000,R2 mov #2048.,R0 WORK_CheckWord: cmp (R1)+,(R2)+ bne WORK_CheckDiff sob R0,WORK_CheckWord inc R4 inc R5 sob R3,WORK_CheckPage mov WorkOriginalBase,MapActiveBase clr WorkDirty clr WorkOriginalBase br WORK_CheckDone WORK_CheckDiff: mov #1,WorkDirty WORK_CheckDone:mov #MON_FONT_PAGE,@#WIN130 mov #VRAM_PAGE,@#WIN120 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC WORK_Discard: tst WorkDirty beq WORK_DiscardDone mov WorkOriginalBase,MapActiveBase WORK_DiscardDone:clr WorkDirty clr WorkOriginalBase rts PC ; ======================================================================== ; AZMNT_06 r05: READ-ONLY WORK diff preview. Compare only 386 path bytes of ; every record, not the 10-byte controller metadata. Both records may cross ; a 4096-byte AZ page. Immutable SOURCE stays at WorkOriginalBase; edited ; paths stay at MapActiveBase. No controller write commands are used. ; ======================================================================== WORK_CountDiff: mov R0,-(SP) mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) clr DiffCount mov #DiffMarksLo,R1 mov #16.,R0 WORK_DiffClearLo: movb #'.,(R1)+ sob R0,WORK_DiffClearLo mov #DiffMarksHi,R1 mov #16.,R0 WORK_DiffClearHi: movb #'.,(R1)+ sob R0,WORK_DiffClearHi tst WorkDirty beq WORK_DiffDone tst WorkOriginalBase beq WORK_DiffDone mov WorkOriginalBase,DiffSrcStart mov MapActiveBase,DiffDstStart mov #MAP_PATH_OFFSET,R4 mov #32.,DiffRows WORK_DiffNextRow: mov DiffSrcStart,DiffSrcPage mov DiffDstStart,DiffDstPage mov DiffSrcPage,@#WIN120 mov DiffDstPage,@#WIN130 mov #120000,R1 add R4,R1 mov #130000,R2 add R4,R2 mov #193.,R0 ; 386 path bytes = 193 words WORK_DiffNextWord: cmp (R1)+,(R2)+ bne WORK_DiffDifferent cmp R1,#130000 blo WORK_DiffNoCross inc DiffSrcPage inc DiffDstPage mov DiffSrcPage,@#WIN120 mov DiffDstPage,@#WIN130 mov #120000,R1 mov #130000,R2 WORK_DiffNoCross: sob R0,WORK_DiffNextWord br WORK_DiffRowDone WORK_DiffDifferent: inc DiffCount mov #32.,R5 sub DiffRows,R5 cmp R5,#16. blo WORK_DiffMarkLow sub #16.,R5 mov #DiffMarksHi,R2 br WORK_DiffMarkWrite WORK_DiffMarkLow: mov #DiffMarksLo,R2 WORK_DiffMarkWrite: add R5,R2 movb #'*,(R2) WORK_DiffRowDone: add #MAP_RECORD_LEN,R4 cmp R4,#4096. blo WORK_DiffRowReady sub #4096.,R4 inc DiffSrcStart inc DiffDstStart WORK_DiffRowReady: dec DiffRows bne WORK_DiffNextRow WORK_DiffDone: mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 mov (SP)+,R0 rts PC ; WRITE line currently opens a read-only preview, not an apply dialog. APP_ShowWorkDiff: jsr PC,UI_ResetMarquee jsr PC,CLK_Stop jsr PC,KEY_FlushReleased jsr PC,WORK_CountDiff tst DiffCount bne APP_DiffNonempty jsr PC,UI_NoChanges rts PC APP_DiffNonempty: jsr PC,DL_Open tst R0 beq APP_DiffDraw jsr PC,CLK_Start mov #StrDialogDmaError,R3 jsr PC,UI_StatusText rts PC APP_DiffDraw: jsr PC,UI_DrawWorkDiffDialog APP_DiffKey: jsr PC,KEY_ReadOne cmp R0,#K_ESC beq APP_DiffClose cmp R0,#K_ENTER bne APP_DiffKey APP_DiffClose: jsr PC,APP_ConfirmRestore rts PC UI_DrawWorkDiffDialog: mov R1,-(SP) mov R3,-(SP) jsr PC,UI_DrawModalFrame mov #16.,UY mov #10.,UX tst WriteTarget beq UI_DiffIniTitle mov #StrApplyPreview,R3 br UI_DiffHaveTitle UI_DiffIniTitle:mov #StrDiffTitle,R3 UI_DiffHaveTitle: jsr PC,UI_PrintString mov #17.,UY mov #10.,UX mov #StrDiffCount,R3 jsr PC,UI_PrintString mov DiffCount,R1 jsr PC,UI_PrintDec2 mov #18.,UY mov #10.,UX mov #StrDiffLo,R3 jsr PC,UI_PrintString mov #DiffMarksLo,R3 jsr PC,UI_PrintString mov #19.,UY mov #10.,UX mov #StrDiffHi,R3 jsr PC,UI_PrintString mov #DiffMarksHi,R3 jsr PC,UI_PrintString mov (SP)+,R3 mov (SP)+,R1 rts PC ; ======================================================================== ; AZMNT_07 r05: LIVE CONTROLLER WRITE, guarded by two deliberate actions: ; WRITE target CONTROLLER -> read live map -> show physical diff -> Enter ; -> confirmation defaults NO -> RIGHT + ENTER = explicit authorization. ; Never modify AZ.INI. After an error STOP (no rollback), reread live map ; and report actual remaining differences. A failed reread = UNKNOWN. ; Scratch bank 2061..2064 is NOT one of the two WORK/SOURCE map banks. ; ======================================================================== AP_ControllerUI: jsr PC,UI_ResetMarquee jsr PC,CLK_Stop jsr PC,KEY_FlushReleased clr AP_Error clr AP_Stage clr AP_PostBad clr AP_Total clr AP_Verified clr AP_Remaining clr AP_FailedStage clr AP_FailedDisk clr AP_FailedCSR clr AP_Disk ; Fast local no-op: controller snapshot, no WORK edits. ; AZ.INI source always needs real physical comparison. cmp MapSource,#1 bne AP_UIReadLive tst WorkDirty bne AP_UIReadLive jsr PC,UI_NoChanges rts PC AP_UIReadLive: jsr PC,AP_ReadActual tst R0 beq AP_UIReadOK mov #1,AP_PostBad jmp AP_UIShowResult AP_UIReadOK: jsr PC,AP_CountChanges tst R0 beq AP_UICountOK mov #1,AP_PostBad jmp AP_UIShowResult AP_UICountOK: tst AP_Total bne AP_UIPreview ; Identical physical/WORK paths: no write and no mutation. ; Keep the loaded source and WORK untouched. jsr PC,UI_NoChanges rts PC AP_UIPreview: jsr PC,DL_Open tst R0 beq AP_UIDrawPreview jmp AP_UIAbortDMA AP_UIDrawPreview: jsr PC,UI_DrawWorkDiffDialog ; Keep preview strictly informational until an additional ; explicit ENTER. KT here cancels without any write. AP_UIPreviewKey: jsr PC,KEY_ReadOne cmp R0,#K_ESC beq AP_UIPreviewCancel cmp R0,#K_ENTER bne AP_UIPreviewKey jsr PC,DL_Close tst R0 beq AP_DonePreviewRestore jmp AP_UIAbortDMA AP_DonePreviewRestore: jsr PC,AP_ConfirmApply tst R0 bne AP_UIReturn ; Save background and SHOW busy modal before first write. ; No DMA backup = no physical write. jsr PC,AP_OpenWriteProgress tst R0 bne AP_UIAbortDMA jsr PC,AP_RunChanges ; Keep modal visible through mandatory full readback. jsr PC,DL_Close tst R0 beq AP_BusyClosed ; An overlay failure after a write makes UI state unsafe. ; Keep the first command error if already present. mov #1,AP_PostBad tst AP_Error bne AP_BusyClosed mov #ERR_MAP_STATUS,AP_Error AP_BusyClosed: jmp AP_UIShowResult AP_UIPreviewCancel: jsr PC,DL_Close tst R0 bne AP_UIAbortDMA AP_UIReturn: jsr PC,CLK_Start rts PC AP_UIAbortDMA: jsr PC,CLK_Start mov #StrDialogDmaError,R3 jsr PC,UI_StatusText rts PC ; Current live controller mapping -> SCRATCH bank (4 pages). ; This does NOT change MapActiveBase, WorkOriginalBase, WorkDirty. ; Return R0=0 success, nonzero failure; AP_Stage and AP_CSR for report. AP_ReadActual: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) tst AP_Stage bne AP_ReadStageKnown mov #1,AP_Stage AP_ReadStageKnown: jsr PC,API_Reset tst R0 bne AP_ReadError mov #11,@#AZCSR mov #15,@#AZCSR mov #AP_ACTUAL_BANK,R4 mov R4,@#WIN120 mov #120000,R3 mov #MAP_WORDS,R5 AP_ReadLoop: mov @#AZDR,(R3)+ cmp R3,#130000 blo AP_ReadNext inc R4 mov R4,@#WIN120 mov #120000,R3 AP_ReadNext: sob R5,AP_ReadLoop ; A full 6336-word transfer is not proof that STM32 ; finished the operation. Wait only AFTER all DR words: ; polling inside the stream breaks the legacy protocol. jsr PC,API_WaitReady mov @#AZCSR,AP_CSR tst R0 bne AP_ReadError ; bounded timeout, no partial accept bit #100000,AP_CSR beq AP_ReadValidate mov #ERR_MAP_STATUS,R0 br AP_ReadError AP_ReadValidate: mov #AP_ACTUAL_BANK,MapReadBase jsr PC,MAP_ValidateAll tst R0 bne AP_ReadError clr R0 br AP_ReadDone AP_ReadError: mov R0,AP_Error mov @#AZCSR,AP_CSR AP_ReadDone: ; Release controller to known READY state even after a read. ; Preserve an earlier read/validation error if present. mov R0,-(SP) jsr PC,API_Reset tst R0 beq AP_ReadResetDone tst (SP) bne AP_ReadResetDone mov R0,(SP) mov R0,AP_Error mov CSR_Reset,AP_CSR AP_ReadResetDone: mov (SP)+,R0 mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Read both paths into local 386-byte caches; physical vs WORK. ; R0=0 match, R0=1 mismatch, R0=2 bad record. ; AP_Disk=0..31, AP_OldLen/AP_NewLen and caches filled. AP_CompareOne: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov AP_Disk,R0 mov #AP_ACTUAL_BANK,MapReadBase jsr PC,MAP_ReadPath tst R0 bne AP_CompareBad mov R1,AP_OldLen mov #MapPathCache,R1 mov #AP_OldPath,R2 mov #193.,R3 AP_CopyOld: mov (R1)+,(R2)+ sob R3,AP_CopyOld mov AP_Disk,R0 mov MapActiveBase,MapReadBase jsr PC,MAP_ReadPath tst R0 bne AP_CompareBad mov R1,AP_NewLen mov #MapPathCache,R1 mov #AP_NewPath,R2 mov #193.,R3 AP_CopyNew: mov (R1)+,(R2)+ sob R3,AP_CopyNew mov AP_OldLen,R3 cmp R3,AP_NewLen bne AP_CompareDifferent tst R3 beq AP_CompareSame ; Only both 0:/ MicroSD paths compare ASCII case-insensitively. ; Keep the original bytes in both caches (especially NETWORK). clr AP_CaseFold cmpb @#AP_OldPath,#'0 bne AP_PathModeReady cmpb @#AP_NewPath,#'0 bne AP_PathModeReady cmpb @#AP_OldPath+1,#72 ; ASCII ':' (octal) bne AP_PathModeReady cmpb @#AP_NewPath+1,#72 bne AP_PathModeReady cmpb @#AP_OldPath+2,#'/ bne AP_PathModeReady cmpb @#AP_NewPath+2,#'/ bne AP_PathModeReady mov #1,AP_CaseFold AP_PathModeReady: mov #AP_OldPath,R1 mov #AP_NewPath,R2 AP_PathCmp: movb (R1)+,R0 movb (R2)+,R4 cmpb R0,R4 beq AP_PathNext tst AP_CaseFold beq AP_CompareDifferent ; Fold only ASCII a..z, not punctuation or non-ASCII. cmpb R0,#'a blo AP_FoldNew cmpb R0,#'z bhi AP_FoldNew bic #40,R0 AP_FoldNew: cmpb R4,#'a blo AP_FoldCompare cmpb R4,#'z bhi AP_FoldCompare bic #40,R4 AP_FoldCompare: cmpb R0,R4 bne AP_CompareDifferent AP_PathNext: sob R3,AP_PathCmp AP_CompareSame:clr R0 br AP_CompareDone AP_CompareDifferent: mov #1,R0 br AP_CompareDone AP_CompareBad: mov #2,R0 AP_CompareDone: mov #VRAM_PAGE,@#WIN120 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Diff MUST use CURRENT physical state, not original AZ.INI mapping. AP_CountChanges: clr AP_Total clr AP_Verified clr AP_Remaining clr DiffCount mov #DiffMarksLo,R1 mov #16.,R2 AP_ClrMarksLo: movb #'.,(R1)+ sob R2,AP_ClrMarksLo mov #DiffMarksHi,R1 mov #16.,R2 AP_ClrMarksHi: movb #'.,(R1)+ sob R2,AP_ClrMarksHi clr AP_Disk AP_DiffNext: jsr PC,AP_CompareOne cmp R0,#2 beq AP_DiffBad tst R0 beq AP_DiffAdvance inc AP_Total inc DiffCount mov AP_Disk,R1 cmp R1,#16. blo AP_MarkLo sub #16.,R1 mov #DiffMarksHi,R2 br AP_MarkNow AP_MarkLo: mov #DiffMarksLo,R2 AP_MarkNow: add R1,R2 movb #'*,(R2) AP_DiffAdvance: inc AP_Disk cmp AP_Disk,#32. blo AP_DiffNext clr R0 rts PC AP_DiffBad: mov #ERR_MAP_BAD,AP_Error mov #2,R0 rts PC ; Warning/approval dialog isolated by the proven DL save/clear/restore. ; NO is default; KT/NO always cancel. Only RIGHT+ENTER authorizes. AP_ConfirmApply: clr DiscardChoice jsr PC,KEY_FlushReleased jsr PC,DL_Open tst R0 bne AP_ConfirmNo jsr PC,UI_DrawModalFrame mov #16.,UY mov #10.,UX mov #StrApplyQuestion,R3 jsr PC,UI_PrintString mov #17.,UY mov #10.,UX mov #StrApplyWarning,R3 jsr PC,UI_PrintString mov #18.,UY mov #10.,UX mov #StrApplyChoices,R3 jsr PC,UI_PrintString mov #19.,UY mov #10.,UX mov #StrApplyKeys,R3 jsr PC,UI_PrintString jsr PC,UI_DiscardHighlight AP_ConfirmKey: jsr PC,KEY_ReadOne cmp R0,#K_ESC beq AP_ConfirmCancel cmp R0,#K_LEFT beq AP_ConfirmLeft cmp R0,#K_RIGHT beq AP_ConfirmRight cmp R0,#K_ENTER beq AP_ConfirmSelect br AP_ConfirmKey AP_ConfirmLeft:tst DiscardChoice beq AP_ConfirmKey jsr PC,UI_DiscardHighlight clr DiscardChoice jsr PC,UI_DiscardHighlight br AP_ConfirmKey AP_ConfirmRight: tst DiscardChoice bne AP_ConfirmKey jsr PC,UI_DiscardHighlight mov #1,DiscardChoice jsr PC,UI_DiscardHighlight br AP_ConfirmKey AP_ConfirmSelect: tst DiscardChoice beq AP_ConfirmCancel jsr PC,DL_Close tst R0 bne AP_ConfirmNo clr R0 rts PC AP_ConfirmCancel: jsr PC,DL_Close AP_ConfirmNo: mov #1,R0 rts PC ; After confirmation, sequentially apply only differing positions. ; 014 may fail if old path absent, so skip it for empty slot. ; Hard stop on first command failure. On all paths reread physical map. AP_RunChanges: mov #2,AP_Stage clr AP_Error clr AP_PostBad clr AP_Disk AP_ApplyNext: jsr PC,AP_CompareOne cmp R0,#2 beq AP_ApplyPathError tst R0 beq AP_ApplyAdvance tst AP_OldLen beq AP_SkipUnmnt jsr PC,AP_Unmount tst R0 bne AP_ApplyStopped AP_SkipUnmnt: tst AP_NewLen beq AP_ApplyAdvance jsr PC,AP_Mount tst R0 bne AP_ApplyStopped AP_ApplyAdvance: inc AP_Disk cmp AP_Disk,#32. blo AP_ApplyNext br AP_AfterApply AP_ApplyPathError: mov #ERR_MAP_BAD,AP_Error AP_ApplyStopped: ; No rollback. AP_Disk points at failed or partial slot. AP_AfterApply: tst AP_Error beq AP_SaveNoFailure mov AP_Disk,AP_FailedDisk mov AP_Stage,AP_FailedStage mov AP_CSR,AP_FailedCSR AP_SaveNoFailure: mov #5,AP_Stage jsr PC,AP_ReadActual tst R0 beq AP_PostReadOK mov #1,AP_PostBad rts PC AP_PostReadOK: ; After a successful readback preserve the first WRITE error. clr AP_Remaining clr AP_Verified clr AP_Disk AP_VerifyNext: jsr PC,AP_CompareOne cmp R0,#2 beq AP_VerifyBad tst R0 bne AP_VerifyMismatch mov AP_Disk,R1 cmp R1,#16. blo AP_VerifyMaskLo sub #16.,R1 mov #DiffMarksHi,R2 br AP_VerifyMaskReady AP_VerifyMaskLo: mov #DiffMarksLo,R2 AP_VerifyMaskReady: add R1,R2 cmpb (R2),#'* bne AP_VerifyAdvance inc AP_Verified br AP_VerifyAdvance AP_VerifyMismatch: inc AP_Remaining AP_VerifyAdvance: inc AP_Disk cmp AP_Disk,#32. blo AP_VerifyNext ; Preserve original write command error if any. tst AP_Remaining bne AP_KeepFailed tst AP_Error bne AP_KeepFailed jsr PC,AP_CommitPhysical rts PC AP_KeepFailed: tst AP_Error bne AP_VerifyReturn mov #12.,AP_Error AP_VerifyReturn: rts PC AP_VerifyBad: mov #1,AP_PostBad mov #ERR_MAP_BAD,AP_Error rts PC ; Physical test r02: numeric DR + CSR014 FAILED on an occupied drive. ; AZUMNT.MAC uses CSR016 + 40 words containing "Dnn" + CSR014. ; Try ONLY this legacy sequence; never auto-retry another unmount style. ; AP_MountText is a reusable local buffer; no AZ.INI file operation. AP_Unmount: mov #3,AP_Stage mov #AP_MountText,R1 mov #40.,R2 AP_UnmountZero: clr (R1)+ sob R2,AP_UnmountZero mov #AP_MountText,R1 movb #'D,(R1)+ mov AP_Disk,R2 clr R3 AP_UmTens: cmp R2,#10. blo AP_UmDigits sub #10.,R2 inc R3 br AP_UmTens AP_UmDigits: add #'0,R3 movb R3,(R1)+ add #'0,R2 movb R2,(R1)+ ; Trailing zero bytes already cleared (40 words). jsr PC,API_Reset tst R0 bne AP_CommandBad mov #16,@#AZCSR mov #AP_MountText,R2 mov #40.,R3 AP_UmSend: mov (R2)+,@#AZDR sob R3,AP_UmSend mov #14,@#AZCSR jsr PC,AP_WaitReady tst R0 bne AP_CommandBad mov @#AZCSR,AP_CSR bit #100000,AP_CSR bne AP_CommandStatus clr R0 rts PC ; Build NUL-terminated Dnn= with full zero word inside buffer. ; Longest path=384 bytes, <=196 words, less than 258-word IOBUF. AP_Mount: mov #4,AP_Stage ; clear 196 words, including guaranteed trailing NUL word mov #AP_MountText,R1 mov #196.,R2 AP_ZeroMount: clr (R1)+ sob R2,AP_ZeroMount mov #AP_MountText,R1 movb #'D,(R1)+ mov AP_Disk,R2 clr R3 AP_Tens: cmp R2,#10. blo AP_Digits sub #10.,R2 inc R3 br AP_Tens AP_Digits: add #'0,R3 movb R3,(R1)+ add #'0,R2 movb R2,(R1)+ movb #'=,(R1)+ mov #AP_NewPath,R2 mov AP_NewLen,R3 beq AP_CopyDone AP_CopyText: movb (R2)+,(R1)+ sob R3,AP_CopyText AP_CopyDone: ; One or two NUL bytes already initialized in AP_MountText. jsr PC,API_Reset tst R0 bne AP_CommandBad mov #16,@#AZCSR mov #AP_MountText,R2 mov AP_NewLen,R3 add #7.,R3 ; 4-char prefix + >=2 NUL + rounding asr R3 ; (prefix+length+3) / 2 words AP_SendMount: mov (R2)+,@#AZDR sob R3,AP_SendMount mov #4,@#AZCSR jsr PC,AP_WaitReady tst R0 bne AP_CommandBad mov @#AZCSR,AP_CSR bit #100000,AP_CSR bne AP_CommandStatus clr R0 rts PC ; Separate long but BOUNDED wait for potentially slow SD/network ops. AP_WaitReady: mov R1,-(SP) mov R2,-(SP) mov #40.,R2 AP_WaitOuter: mov #60000.,R1 AP_WaitInner: bit #200,@#AZCSR bne AP_WaitOK sob R1,AP_WaitInner sob R2,AP_WaitOuter mov #ERR_API_TIMEOUT,R0 br AP_WaitReturn AP_WaitOK: clr R0 AP_WaitReturn: mov (SP)+,R2 mov (SP)+,R1 rts PC AP_CommandStatus: mov #ERR_API_STATUS,R0 AP_CommandBad: mov R0,AP_Error mov @#AZCSR,AP_CSR rts PC ; On VERIFIED success, copy all metadata+paths from scratch to the WORK ; map bank, clear dirty; no loss of selected Dnn or screen snapshot. AP_CommitPhysical: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) bic #4000,@#WIN_RO mov #AP_ACTUAL_BANK,R4 mov MapActiveBase,R5 mov #4.,R3 AP_CommitPage: mov R4,@#WIN120 mov R5,@#WIN130 mov #120000,R1 mov #130000,R2 mov #2048.,R0 AP_CommitLoop: mov (R1)+,(R2)+ sob R0,AP_CommitLoop inc R4 inc R5 sob R3,AP_CommitPage bis #4000,@#WIN_RO mov #MON_FONT_PAGE,@#WIN130 mov #VRAM_PAGE,@#WIN120 clr WorkDirty clr WorkOriginalBase mov #1,MapSource clr R0 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Readback report must never label failed reread as success. AP_UIShowResult: jsr PC,DL_Open tst R0 beq AP_ResultBackupOK jmp AP_UIAbortDMA AP_ResultBackupOK: jsr PC,UI_DrawModalFrame mov #16.,UY mov #10.,UX tst AP_PostBad bne AP_ResultUnknown tst AP_Error bne AP_ResultPartial mov #StrApplyOK,R3 br AP_ResultTitle AP_ResultPartial: mov #StrApplyFailed,R3 br AP_ResultTitle AP_ResultUnknown: mov #StrApplyUnknown,R3 AP_ResultTitle: jsr PC,UI_PrintString mov #17.,UY mov #10.,UX mov #StrApplyStage,R3 jsr PC,UI_PrintString tst AP_FailedStage beq AP_ResultCurrentStage mov AP_FailedStage,R1 br AP_ResultStageReady AP_ResultCurrentStage: mov AP_Stage,R1 AP_ResultStageReady: jsr PC,UI_PrintDec2 mov #StrApplyDisk,R3 jsr PC,UI_PrintString mov AP_FailedDisk,R1 jsr PC,UI_PrintDec2 mov #18.,UY mov #10.,UX mov #StrApplyDone,R3 jsr PC,UI_PrintString mov AP_Verified,R1 jsr PC,UI_PrintDec2 mov #StrApplyRemain,R3 jsr PC,UI_PrintString mov AP_Remaining,R1 jsr PC,UI_PrintDec2 mov #StrApplyCsr,R3 jsr PC,UI_PrintString tst AP_FailedStage beq AP_ResultCurrentCSR mov AP_FailedCSR,R1 br AP_ResultCSRReady AP_ResultCurrentCSR: mov AP_CSR,R1 AP_ResultCSRReady: jsr PC,UI_PrintOct6 mov #StrApplyErr,R3 jsr PC,UI_PrintString mov AP_Error,R1 jsr PC,UI_PrintDec2 mov #19.,UY mov #10.,UX mov #StrApplyClose,R3 jsr PC,UI_PrintString AP_ResultKey: jsr PC,KEY_ReadOne cmp R0,#K_ENTER beq AP_ResultClose cmp R0,#K_ESC bne AP_ResultKey AP_ResultClose: jsr PC,DL_Close tst R0 beq AP_ResultRestored jmp AP_UIAbortDMA AP_ResultRestored: tst AP_Error bne AP_ResultDirty tst AP_PostBad bne AP_ResultDirty jsr PC,UI_RenderAll jsr PC,UI_DrawFocus jsr PC,UI_DrawStatus AP_ResultDirty: jsr PC,CLK_Start rts PC ; Generic NO CHANGES notification shared by WRITE:AZ.INI and WRITE:CTRL. ; Caller has already stopped CLK and released any held key. ; Any NEW key closes, with DMA-restored background and no list redraw. UI_NoChanges: jsr PC,DL_Open tst R0 bne UI_NoChangesDMAFail jsr PC,UI_DrawModalFrame mov #16.,UY mov #10.,UX mov #StrNoChanges,R3 jsr PC,UI_PrintString mov #17.,UY mov #10.,UX tst WriteTarget bne UI_NoChangesCtrl mov #StrNoChangesIni,R3 br UI_NoChangesTarget UI_NoChangesCtrl: mov #StrNoChangesController,R3 UI_NoChangesTarget: jsr PC,UI_PrintString mov #19.,UY mov #10.,UX mov #StrAnyKey,R3 jsr PC,UI_PrintString jsr PC,KEY_ReadOne jsr PC,APP_ConfirmRestore rts PC UI_NoChangesDMAFail: jsr PC,CLK_Start mov #StrDialogDmaError,R3 jsr PC,UI_StatusText rts PC ; Progress overlay is not interactive. Visible for the ENTIRE operation: ; sequential unmount/mount AND final controller reread/verification. ; The same drawing routine includes a future AZ.INI title (not enabled). ; Caller invokes DL_Close when operation has completed. AP_OpenWriteProgress: jsr PC,DL_Open tst R0 bne AP_ProgressNoBackup jsr PC,UI_DrawModalFrame mov #16.,UY mov #10.,UX tst WriteTarget beq AP_ProgressIniTitle mov #StrWritingController,R3 br AP_ProgressTitle AP_ProgressIniTitle: mov #StrWritingIni,R3 AP_ProgressTitle: jsr PC,UI_PrintString mov #17.,UY mov #10.,UX mov #StrWritingWarning,R3 jsr PC,UI_PrintString mov #18.,UY mov #10.,UX mov #StrWritingVerify,R3 jsr PC,UI_PrintString mov #19.,UY mov #10.,UX mov #StrWritingWait,R3 jsr PC,UI_PrintString clr R0 rts PC AP_ProgressNoBackup: mov #1,R0 rts PC ; Confirmation is only shown when WORK actually differs from SOURCE. ; NO (keep WORK) is selected initially. LEFT selects NO, RIGHT YES. ; ENTER on NO and KT both cancel and return to the mapping list. ; ENTER on YES confirms discard (or navigation requiring discard). ; R0=0 confirmed YES (or no changes); R0=1 cancelled/NO. ; This dialog draws over the list, then redraws the list exactly once on ; exit to restore all underlying pixels. No full redraw per LEFT/RIGHT. APP_ConfirmDiscard: tst WorkDirty beq APP_ConfirmYes jsr PC,UI_ResetMarquee jsr PC,CLK_Stop jsr PC,KEY_FlushReleased clr DiscardChoice ; 0=NO, 1=YES jsr PC,DL_Open tst R0 beq APP_ConfirmDraw ; No usable backup: NEVER draw an overlay that cannot be restored. jsr PC,CLK_Start mov #StrDialogDmaError,R3 jsr PC,UI_StatusText mov #1,R0 rts PC APP_ConfirmDraw: jsr PC,UI_DrawDiscardDialog APP_ConfirmKey: jsr PC,KEY_ReadOne cmp R0,#K_ESC beq APP_ConfirmCancel cmp R0,#K_LEFT beq APP_ConfirmSelectNo cmp R0,#K_RIGHT beq APP_ConfirmSelectYes cmp R0,#K_ENTER beq APP_ConfirmEnter br APP_ConfirmKey APP_ConfirmSelectNo: tst DiscardChoice beq APP_ConfirmKey jsr PC,UI_DiscardHighlight ; old YES off clr DiscardChoice jsr PC,UI_DiscardHighlight ; new NO on br APP_ConfirmKey APP_ConfirmSelectYes: tst DiscardChoice bne APP_ConfirmKey jsr PC,UI_DiscardHighlight ; old NO off mov #1,DiscardChoice jsr PC,UI_DiscardHighlight ; new YES on br APP_ConfirmKey APP_ConfirmEnter: tst DiscardChoice beq APP_ConfirmCancel ; default NO retains WORK jsr PC,APP_ConfirmRestore clr R0 ; YES: caller may discard WORK rts PC APP_ConfirmCancel: jsr PC,APP_ConfirmRestore mov #1,R0 ; KT/NO: keep WORK + source rts PC APP_ConfirmYes:clr R0 rts PC ; Restore exactly the saved 46x6 rectangle; no full-screen repaint. ; Fatal DMA restore errors fall back to a full recovery redraw only after ; the blitter has been quiesced. Normal cancel/YES does not repaint a pixel. APP_ConfirmRestore: jsr PC,DL_Close tst R0 beq APP_RestoreClean jsr PC,BJ_QuiesceDMA jsr PC,UI_RenderAll jsr PC,UI_DrawFocus jsr PC,UI_DrawStatus mov #StrDialogDmaError,R3 jsr PC,UI_StatusText APP_RestoreClean: jsr PC,CLK_Start rts PC ; Exact saved region has already been DMA-zeroed by DL_Open. ; No clearing of rows 15..20 outside the 46-column modal frame. UI_DrawDiscardDialog: mov R1,-(SP) mov R3,-(SP) mov R4,-(SP) jsr PC,UI_DrawModalFrame mov #16.,UY mov #10.,UX mov #StrDiscardChanges,R3 jsr PC,UI_PrintString mov #17.,UY mov #10.,UX mov #StrDiscardWarning,R3 jsr PC,UI_PrintString mov #18.,UY mov #10.,UX mov #StrDiscardOptions,R3 jsr PC,UI_PrintString mov #19.,UY mov #10.,UX mov #StrDiscardControls,R3 jsr PC,UI_PrintString jsr PC,UI_DiscardHighlight mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R1 rts PC ; ======================================================================== ; Discard confirmation overlay, precisely x8..53 / y15..20 text rows. ; Video rectangle is 23 WORDS x 60 PIXEL rows (2760 B), backup page2055. ; CMD042 saves framebuffer rectangle into linear 2055; CMD000 FILL ; clears ONLY this same rectangle; CMD011 restores 2055 -> framebuffer. ; Source 064000 is 32-word aligned for CMD011. No overlap with BR 2050..54. ; Return R0=0 success; 1 failure. Never leave BL_PACKET_REG remapped. ; ======================================================================== DL_Open: mov @#BL_PACKET_REG,DL_OldPacket mov BJ_CustomDMA,DL_OldCustom clr DL_HaveSaved mov #1,BJ_CustomDMA clr BJ_FullDMA clr BJ_Code mov #42,BJ_W4 jsr PC,DL_RunRect tst R0 bne DL_OpenFail mov #1,DL_HaveSaved clr BJ_W4 ; legacy CMD000 = FILL W8.LO=0 jsr PC,DL_RunRect tst R0 beq DL_OpenOK ; FILL failed after save. Attempt restore before leaving. mov #11,BJ_W4 jsr PC,DL_RunRect tst R0 beq DL_OpenFail ; Exceptional case: both FILL and RESTORE failed. ; Reconstruct display only AFTER the blitter is stopped. jsr PC,BJ_QuiesceDMA jsr PC,UI_RenderAll jsr PC,UI_DrawFocus mov #37.,UY jsr PC,UI_DrawStatus DL_OpenFail: jsr PC,DL_Tidy mov #1,R0 rts PC DL_OpenOK: jsr PC,DL_Tidy clr R0 rts PC DL_Close: tst DL_HaveSaved bne DL_Restore clr R0 rts PC DL_Restore: mov @#BL_PACKET_REG,DL_OldPacket mov BJ_CustomDMA,DL_OldCustom mov #1,BJ_CustomDMA clr BJ_FullDMA clr BJ_Code mov #11,BJ_W4 jsr PC,DL_RunRect mov R0,DL_Result jsr PC,DL_Tidy clr DL_HaveSaved mov DL_Result,R0 rts PC DL_RunRect: mov #020440,BJ_W1 mov #DL_BACK_LOW,BJ_W2 mov #DL_SCREEN_LOW,BJ_W3 mov #DL_W5,BJ_CustomW5 mov #DL_W6,BJ_CustomW6 jsr PC,BJ_RunDMA mov BJ_Code,R0 bne DL_RunFail mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 clr R0 rts PC DL_RunFail: mov #1,R0 rts PC DL_Tidy: jsr PC,BJ_QuiesceDMA mov DL_OldPacket,@#BL_PACKET_REG mov DL_OldCustom,BJ_CustomDMA mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 rts PC ; Startup/source chooser: no underlying WORK view, so clear exactly ; the same 46x6 rectangle without saving it. BL packet restored afterward. DL_ClearOnly: mov @#BL_PACKET_REG,DL_OldPacket mov BJ_CustomDMA,DL_OldCustom mov #1,BJ_CustomDMA clr BJ_FullDMA clr BJ_Code clr BJ_W4 jsr PC,DL_RunRect mov R0,DL_Result jsr PC,DL_Tidy mov DL_Result,R0 rts PC ; Invert only the selected token (NO or YES), not the whole frame. UI_DiscardHighlight: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov #10.,HighlightX mov #2.,HighlightWidth tst DiscardChoice beq UI_DiscardDoInvert mov #29.,HighlightX ; YES starts 19 chars after x10 mov #3.,HighlightWidth UI_DiscardDoInvert: mov #18.,R0 jsr PC,UI_InvertChoice mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Leave mapping list, but do not exit ANDOS from its KT command. APP_BackToSource: jsr PC,UI_ResetMarquee jsr PC,CLK_Stop jsr PC,WORK_Discard clr MapLoaded clr MapSource clr AppMain clr HeldArrow clr PendingCommand jsr PC,KEY_FlushReleased jsr PC,UI_Clear6Pages clr ModalSource jsr PC,UI_ModalStub rts PC ; ----- Controller handshake: bounded 000 RESET then 027 VERSION ----- ; AZSMNT.MAC GTSTMV and AZ Wiki both start 027 with 000 RESET. ; A previously busy/stale CSR is NOT necessarily recovered by waiting: ; RESET is reissued until the ready bit appears, as in original GTSTMV, ; with a hard limit. No DR access while CSR reports not-ready. ; RESET may abort an active disk transaction: launch on IDLE ANDOS. ; Version command 027 does not change disk mapping or AZ.INI. ; Return word0: (STM_major << 8) | HW_revision; word1: max disk. ; API_GetVersion: mov R1,-(SP) mov R2,-(SP) mov @#AZCSR,CSR_Pre mov #API_STAGE_RESET,APIStage clr CSR_Reset clr CSR_Cmd jsr PC,API_Reset tst R0 bne APIVersionEnd mov #API_STAGE_027,APIStage mov #27,@#AZCSR jsr PC,API_WaitReady mov @#AZCSR,CSR_Cmd tst R0 bne APIVersionEnd mov CSR_Cmd,R2 bit #100000,R2 beq APIVersionRead mov #ERR_API_STATUS,R0 br APIVersionEnd APIVersionRead: mov @#AZDR,R2 mov R2,STM_Word mov @#AZDR,MaxDiskNo mov R2,R1 swab R1 bic #177400,R1 mov R1,STM_Major bic #177400,R2 mov R2,HW_Revision clr R0 APIVersionEnd: mov (SP)+,R2 mov (SP)+,R1 rts PC ; Reset command (000): repeat WORD writes like GTSTMV; bounded attempt ; count prevents a permanent lock. Record the last CSR for diagnosis. API_Reset: mov R1,-(SP) clr NetIdleOn ; reset 000 always disables network service mov #5000.,R1 APIResetLoop: clr @#AZCSR mov @#AZCSR,CSR_Reset bit #200,CSR_Reset bne APIResetReady sob R1,APIResetLoop mov #ERR_API_TIMEOUT,R0 br APIResetEnd APIResetReady: bit #100000,CSR_Reset beq APIResetGood mov #ERR_API_STATUS,R0 br APIResetEnd APIResetGood: clr R0 APIResetEnd: mov (SP)+,R1 rts PC ; Wait for 027 only, with bounded polling. RT-11 GTSTMV expects 027 ; immediate; firmware that delays READY is handled without a trap. API_WaitReady: mov R1,-(SP) mov #50000.,R1 APIWaitLoop: bit #200,@#AZCSR bne APIWaitOK sob R1,APIWaitLoop mov #ERR_API_TIMEOUT,R0 br APIWaitEnd APIWaitOK: clr R0 APIWaitEnd: mov (SP)+,R1 rts PC ; ======================================================================== ; AZMNT_08 r02: transactional WORK -> canonical AZ2.INI generator. ; Source INI is IMMUTABLE. Output: AZ RAM 2110..2117 (32 KiB), ; parsed scratch map 2120..2123; readback: 2100..2107. ; The five standard sections are placed ROM,LOGO,DISKS,NETWORK,BOOT. ; Non-DISKS source lines are retained byte-exactly (CRLF required for ; this initial generator); unknown sections follow in their original order. ; Any ambiguous [DISKS] line, malformed section, output overflow, ; parser failure or WORK mismatch BLOCKS write before confirmation. ; ======================================================================== SG_Serialize: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) clr SG_Error clr SG_SrcPos clr SG_Current clr SG_UnknownCount mov #SG_StdStarts,R2 mov #5.,R3 SG_InitStarts: mov #177777,(R2)+ sob R3,SG_InitStarts jsr PC,SG_Scan tst R0 bne SG_Failure jsr PC,SG_Build tst R0 bne SG_Failure jsr PC,SG_Validate tst R0 bne SG_Failure clr R0 br SG_End SG_Failure: mov #1,R0 SG_End: bis #4000,@#WIN_RO mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; R0 is byte offset, returns unsigned byte in R0 from original INI. SG_GetByte: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov INI_ActiveBase,R1 mov R0,R2 SG_GetPage: cmp R2,#4096. blo SG_GetPageOK sub #4096.,R2 inc R1 br SG_GetPage SG_GetPageOK: mov R1,@#WIN120 add #120000,R2 movb (R2),R0 bic #177400,R0 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Read one CRLF-terminated line to existing 512-byte INI_Line buffer. ; R0=0 line, R0=1 clean EOF, R0=2 invalid or unsupported LF. SG_ReadLine: mov SG_SrcPos,SG_LineStart clr SG_LineLen mov #INI_Line,R3 SG_ReadChar: mov SG_SrcPos,R0 cmp R0,INI_ActiveLength bhis SG_AtEOF jsr PC,SG_GetByte tst R0 beq SG_AtEOF inc SG_SrcPos cmp R0,#12 beq SG_EndLine cmp SG_LineLen,#511. bhis SG_InvalidLine movb R0,(R3)+ inc SG_LineLen br SG_ReadChar SG_EndLine: tst SG_LineLen beq SG_InvalidLine cmpb -1(R3),#15 bne SG_InvalidLine dec R3 dec SG_LineLen clrb (R3) clr R0 rts PC SG_AtEOF: tst SG_LineLen bne SG_InvalidLine mov #1,R0 rts PC SG_InvalidLine: mov #2,R0 rts PC ; Classify a header in INI_Line; result 1..5 standard, 6 unknown, ; or 0 malformed. INI_MatchName preserves R2; R3 is temporary. SG_HeaderKind: mov #INI_Line,R2 mov #INI_ROM,R3 jsr PC,INI_MatchName tst R0 bne SG_IsROM mov #INI_LOGO,R3 jsr PC,INI_MatchName tst R0 bne SG_IsLOGO mov #INI_DISKS,R3 jsr PC,INI_MatchName tst R0 bne SG_IsDISKS mov #INI_NETWORK,R3 jsr PC,INI_MatchName tst R0 bne SG_IsNETWORK mov #INI_BOOT,R3 jsr PC,INI_MatchName tst R0 bne SG_IsBOOT cmp SG_LineLen,#3 blo SG_BadHeader mov #INI_Line,R2 add SG_LineLen,R2 dec R2 cmpb (R2),#'] bne SG_BadHeader mov #6,R0 rts PC SG_IsROM: mov #1,R0 rts PC SG_IsLOGO: mov #2,R0 rts PC SG_IsDISKS: mov #3,R0 rts PC SG_IsNETWORK: mov #4,R0 rts PC SG_IsBOOT: mov #5,R0 rts PC SG_BadHeader: clr R0 rts PC ; Store end offset for previous section at start of next header/EOF. SG_CloseSection: tst SG_Current beq SG_CloseDone cmp SG_Current,#6 bne SG_CloseKnown mov SG_UnknownEndPtr,R2 mov SG_LineStart,(R2) br SG_CloseDone SG_CloseKnown: mov SG_Current,R2 dec R2 asl R2 add #SG_StdEnds,R2 mov SG_LineStart,(R2) SG_CloseDone: rts PC SG_Scan: clr SG_Current SG_ScanNext: jsr PC,SG_ReadLine cmp R0,#1 beq SG_ScanEOF tst R0 bne SG_ScanInvalid cmpb @#INI_Line,#'[ beq SG_ScanHeader ; Do not misclassify indented [SECTIONS] as ordinary text. mov #INI_Line,R2 SG_IndentCheck: cmpb (R2),#40 beq SG_IndentNext cmpb (R2),#11 bne SG_IndentDone SG_IndentNext: inc R2 br SG_IndentCheck SG_IndentDone: cmpb (R2),#'[ beq SG_ScanInvalid tst SG_Current beq SG_ScanPreamble cmp SG_Current,#3 bne SG_ScanNext tst SG_LineLen beq SG_ScanNext jsr PC,SG_ValidateDiskLine tst R0 bne SG_ScanInvalid br SG_ScanNext SG_ScanPreamble: ; Any preamble, including blank lines, is not silently lost. br SG_ScanInvalid SG_ScanHeader: jsr PC,SG_HeaderKind tst R0 beq SG_ScanInvalid mov R0,SG_NewSection jsr PC,SG_CloseSection mov SG_NewSection,SG_Current cmp SG_Current,#6 beq SG_ScanUnknown mov SG_Current,R2 dec R2 asl R2 add #SG_StdStarts,R2 cmp (R2),#177777 bne SG_ScanInvalid mov SG_LineStart,(R2) br SG_ScanNext SG_ScanUnknown:cmp SG_UnknownCount,#32. bhis SG_ScanInvalid mov SG_UnknownCount,R2 asl R2 mov #SG_UnknownStarts,R3 add R2,R3 mov SG_LineStart,(R3) mov #SG_UnknownEnds,R3 add R2,R3 mov R3,SG_UnknownEndPtr inc SG_UnknownCount br SG_ScanNext SG_ScanEOF: mov SG_SrcPos,SG_TextEnd mov SG_TextEnd,SG_LineStart jsr PC,SG_CloseSection mov #SG_StdStarts,R2 mov #5.,R3 SG_CheckSeen: cmp (R2)+,#177777 beq SG_ScanInvalid sob R3,SG_CheckSeen clr R0 rts PC SG_ScanInvalid:mov #1,SG_Error mov #1,R0 rts PC ; Strict [DISKS] line syntax. Any comment, unknown key or ambiguous ; record blocks saving; the original loader already checks path length, ; character validity and duplicate Dn/Dnn definitions. SG_ValidateDiskLine: mov #INI_Line,R2 movb (R2)+,R0 cmpb R0,#'D beq SG_DPrefix cmpb R0,#'d bne SG_DInvalid SG_DPrefix: movb (R2)+,R4 cmpb R4,#'0 blo SG_DInvalid cmpb R4,#'9 bhi SG_DInvalid sub #'0,R4 cmpb (R2),#'= beq SG_DHaveEq movb (R2)+,R0 cmpb R0,#'0 blo SG_DInvalid cmpb R0,#'9 bhi SG_DInvalid sub #'0,R0 mov R4,R1 asl R4 asl R1 asl R1 asl R1 add R1,R4 add R0,R4 SG_DHaveEq: cmpb (R2)+,#'= bne SG_DInvalid cmp R4,#31. bhi SG_DInvalid tstb (R2) beq SG_DInvalid clr R0 rts PC SG_DInvalid: mov #1,R0 rts PC ; Output byte writer. Entire output buffer is zeroed first, permitting ; safe padding to 512 bytes without copying source's old NUL tail. ; R0=input byte; R0=0 success / 1 overflow. WIN130 must be writable. SG_PutByte: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) cmp SG_OutLen,#INI_MAX_BYTES bhis SG_PutOverflow mov #SG_OUTPUT_BANK,R1 mov SG_OutLen,R2 SG_PutPage: cmp R2,#4096. blo SG_PutHere sub #4096.,R2 inc R1 br SG_PutPage SG_PutHere: mov R1,@#WIN130 add #130000,R2 movb R0,(R2) inc SG_OutLen clr R0 br SG_PutEnd SG_PutOverflow:mov #3,SG_Error mov #1,R0 SG_PutEnd: mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Copy source span [SG_From,SG_To) with exact bytes/CRLF, no writes to it. SG_CopySpan: mov SG_From,R0 cmp R0,SG_To bhis SG_CopyOK SG_CopyLoop: jsr PC,SG_GetByte jsr PC,SG_PutByte tst R0 bne SG_CopyReturn inc SG_From mov SG_From,R0 cmp R0,SG_To blo SG_CopyLoop SG_CopyOK: clr R0 SG_CopyReturn: rts PC ; R2 -> NUL terminated literal in BK memory. SG_EmitCString: SG_StringNext: movb (R2)+,R0 bic #177400,R0 tst R0 beq SG_StringOK jsr PC,SG_PutByte tst R0 bne SG_StringReturn br SG_StringNext SG_StringOK: clr R0 SG_StringReturn:rts PC SG_EmitCRLF: mov #15,R0 jsr PC,SG_PutByte tst R0 bne SG_CRLFEnd mov #12,R0 jsr PC,SG_PutByte SG_CRLFEnd: rts PC SG_EmitDisks: mov #INI_DISKS,R2 jsr PC,SG_EmitCString tst R0 bne SG_DisksEnd jsr PC,SG_EmitCRLF tst R0 bne SG_DisksEnd clr SG_DiskIndex SG_DiskNext: mov SG_DiskIndex,R0 mov MapActiveBase,MapReadBase jsr PC,MAP_ReadPath tst R0 bne SG_DiskBad mov R1,SG_DiskLen tst R1 beq SG_DiskSkip mov #'D,R0 jsr PC,SG_PutByte tst R0 bne SG_DisksEnd mov SG_DiskIndex,R4 cmp R4,#10. blo SG_DSingle clr R5 SG_DTen: sub #10.,R4 inc R5 cmp R4,#10. bhis SG_DTen mov R4,-(SP) mov R5,R0 add #'0,R0 jsr PC,SG_PutByte mov (SP)+,R4 tst R0 bne SG_DisksEnd SG_DSingle: mov R4,R0 add #'0,R0 jsr PC,SG_PutByte tst R0 bne SG_DisksEnd mov #'=,R0 jsr PC,SG_PutByte tst R0 bne SG_DisksEnd mov #MapPathCache,R2 mov SG_DiskLen,R4 SG_DPathNext: movb (R2)+,R0 bic #177400,R0 jsr PC,SG_PutByte tst R0 bne SG_DisksEnd sob R4,SG_DPathNext jsr PC,SG_EmitCRLF tst R0 bne SG_DisksEnd SG_DiskSkip: inc SG_DiskIndex cmp SG_DiskIndex,#32. blo SG_DiskNext clr R0 SG_DisksEnd: rts PC SG_DiskBad: mov #4,SG_Error mov #1,R0 rts PC SG_Build: clr SG_OutLen bic #4000,@#WIN_RO mov #SG_OUTPUT_BANK,R1 mov #8.,R4 SG_ClearPage: mov R1,@#WIN130 mov #130000,R2 mov #2048.,R3 SG_ClearWords: clr (R2)+ sob R3,SG_ClearWords inc R1 sob R4,SG_ClearPage mov #1,SG_SectionIndex SG_CopyStandard: cmp SG_SectionIndex,#3 beq SG_StandardDisks mov SG_SectionIndex,R1 dec R1 asl R1 mov #SG_StdStarts,R2 add R1,R2 mov (R2),SG_From mov #SG_StdEnds,R2 add R1,R2 mov (R2),SG_To jsr PC,SG_CopySpan tst R0 bne SG_BuildFailure br SG_NextStandard SG_StandardDisks: jsr PC,SG_EmitDisks tst R0 bne SG_BuildFailure SG_NextStandard: inc SG_SectionIndex cmp SG_SectionIndex,#5 blos SG_CopyStandard clr SG_UnknownIndex SG_CopyUnknown: mov SG_UnknownIndex,R0 cmp R0,SG_UnknownCount bhis SG_Padding asl R0 mov #SG_UnknownStarts,R2 add R0,R2 mov (R2),SG_From mov #SG_UnknownEnds,R2 add R0,R2 mov (R2),SG_To jsr PC,SG_CopySpan tst R0 bne SG_BuildFailure inc SG_UnknownIndex br SG_CopyUnknown SG_Padding: clr R0 jsr PC,SG_PutByte ; zero terminator tst R0 bne SG_BuildFailure mov SG_OutLen,R0 add #777,R0 ; 511 decimal, round to 512 bytes bic #777,R0 cmp R0,#INI_MAX_BYTES bhi SG_BuildFailure mov R0,SG_OutLen ; rest is already cleared to zero bis #4000,@#WIN_RO mov #MON_FONT_PAGE,@#WIN130 clr R0 rts PC SG_BuildFailure: bis #4000,@#WIN_RO mov #MON_FONT_PAGE,@#WIN130 mov #1,R0 rts PC ; Parse newly serialized INI in isolated MAP scratch pages. Verify ; all 32 decoded paths against WORK before allowing any WRITE command. SG_Validate: mov INI_StageBase,SG_OldStage mov INI_Length,SG_OldLength mov MapStageBase,SG_OldMapStage mov #SG_OUTPUT_BANK,INI_StageBase mov SG_OutLen,INI_Length mov #SG_CHECK_BANK,MapStageBase jsr PC,INI_Parse tst R0 beq SG_Parsed mov #4,SG_Error br SG_ValidateBad SG_Parsed: clr SG_DiskIndex SG_VerifyNext: mov SG_DiskIndex,R0 mov MapActiveBase,MapReadBase jsr PC,MAP_ReadPath tst R0 bne SG_VerifyBad mov R1,SG_DiskLen mov #MapPathCache,R1 mov #SG_SavedPath,R2 mov #193.,R3 SG_SaveMap: mov (R1)+,(R2)+ sob R3,SG_SaveMap mov SG_DiskIndex,R0 mov #SG_CHECK_BANK,MapReadBase jsr PC,MAP_ReadPath tst R0 bne SG_VerifyBad cmp R1,SG_DiskLen bne SG_VerifyBad mov R1,R4 beq SG_VerifyNextRow mov #MapPathCache,R1 mov #SG_SavedPath,R2 SG_VerifyBytes: cmpb (R1)+,(R2)+ bne SG_VerifyBad sob R4,SG_VerifyBytes SG_VerifyNextRow: inc SG_DiskIndex cmp SG_DiskIndex,#32. blo SG_VerifyNext clr R0 br SG_ValidateEnd SG_VerifyBad: mov #5,SG_Error SG_ValidateBad:mov #1,R0 SG_ValidateEnd:mov SG_OldStage,INI_StageBase mov SG_OldLength,INI_Length mov SG_OldMapStage,MapStageBase mov MapActiveBase,MapReadBase mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 rts PC ; ======================================================================== ; AZMNT_08 r09: guarded BACKUP + MAIN AZ.INI save + full AZ/BK restart. ; 1) Check source=AZ.INI and dirty WORK, prevalidate serialized output. ; 2) Freshly reread on-disk AZ.INI into AB_FRESH and compare ALL bytes with ; the originally loaded INI. A changed original is NEVER overwritten. ; 3) Ask default-NO confirmation BEFORE ANY write. Explicit YES authorizes ; replacement of existing AZINI.BAK and full AZ/BK reboot (037). ; 4) Fresh original -> AZINI.BAK (create or refresh) + full byte readback. ; Any BAK read/write/verify error blocks MAIN; directory ERROR != absent. ; 5) Regenerate WORK (BAK source preparation used output pages 2110..2117). ; 6) Write MAIN, verify byte-for-byte, reload/parse, then RESET+037. ; No 037 on error, cancellation, or unverified state. No implicit rollback. ; ======================================================================== AM_MainSaveUI: jsr PC,UI_ResetMarquee jsr PC,CLK_Stop clr AM_BackupReady clr AM_BackupSize clr AM_BakAction clr AM_MainSize clr AM_WriteStarted clr AW_Result clr AW_Error clr AW_CSR clr AW_ReadCode clr AW_ReadStage clr AW_BadOffset mov #2,AW_Mode cmp MapSource,#2 beq AM_Allowed1 jmp AM_Unsupported AM_Allowed1: tst INI_ActiveBase bne AM_Allowed2 jmp AM_Unsupported AM_Allowed2: tst INI_ActiveLength bne AM_Allowed3 jmp AM_Unsupported AM_Allowed3: tst WorkDirty bne AM_Allowed4 jmp AM_NoChanges AM_Allowed4: ; Fail fast on unsupported/ambiguous INI BEFORE touching disk. jsr PC,SG_Serialize tst R0 beq AM_PrebuildOK jmp AM_BuildFail AM_PrebuildOK: ; One explicit YES covers BAK refresh + MAIN + hard reboot. ; NO/KT must not write or restart the controller. mov #2,AW_Mode jsr PC,AW_Confirm tst R0 beq AM_UserConfirmed jmp AM_UIEnd AM_UserConfirmed: jsr PC,AW_ShowProgress tst R0 beq AM_ProgressOK jmp AM_DmaFail AM_ProgressOK: mov #StrAMFreshPhase,R3 jsr PC,AB_ShowPhase jsr PC,AB_StageSource tst R0 bne AM_PreflightFail ; SG_OUTPUT_BANK now contains *fresh original*, not WORK. mov INI_ActiveLength,R0 cmp R0,AW_ExpectedLen bne AM_Stale mov #AB_FRESH_BANK,AM_CheckBankA mov INI_ActiveBase,AM_CheckBankB mov AW_ExpectedLen,AM_CheckLength jsr PC,AM_CompareBanks tst R0 bne AM_Stale jsr PC,AM_CheckOrCreateBak tst R0 bne AM_BackupBad ; BAK is now verified and must NOT be overwritten by MAIN. mov #StrAMBuildPhase,R3 jsr PC,AB_ShowPhase jsr PC,SG_Serialize tst R0 bne AM_BuildBeforeMain mov SG_OutLen,AW_ExpectedLen mov SG_OutLen,AM_MainSize ; keep exact size for final report mov #2,AW_Mode mov #StrAMWritingMain,R3 jsr PC,AB_ShowPhase mov #INI_BaseName,AW_TargetBasePtr mov #INI_FileName,AW_TargetFilePtr mov #1,AM_WriteStarted ; THIS is the only direct MAIN write call site. jsr PC,AW_TransferAndVerify mov R0,AW_Result tst R0 bne AM_FinalDisplay ; Refresh parser's original/snapshot only AFTER byte-verified ; file write. A failed reload keeps WORK dirty and reports FAIL. mov #9.,AW_Stage mov #StrAMReloadPhase,R3 jsr PC,AB_ShowPhase jsr PC,INI_LoadMapping tst R0 bne AM_ReloadFail clr WorkDirty clr WorkOriginalBase ; r10: show BOTH verified files and wait up to 10 real seconds. ; The progress DMA backup remains active; no second SAVE. jsr PC,AM_ShowVerifiedCountdown tst R0 bne AM_ReportFailed ; Only success reaches command 037; the report remains visible. jsr PC,AM_RebootAfterVerified ; Returns only if reboot DID NOT take effect. mov #1,AW_Result br AM_FinalDisplay AM_ReportFailed: mov #31.,AW_Error ; report/clock setup failed; no reboot mov #1,AW_Result br AM_FinalDisplay AM_ReloadFail: mov #25.,AW_Error mov #1,AW_Result br AM_FinalDisplay AM_Stale: mov #21.,AW_Error mov #16.,AW_Stage br AM_PreflightError AM_BackupBad: tst AW_Error bne AM_PreflightError mov #22.,AW_Error br AM_PreflightError AM_BuildBeforeMain: mov #23.,AW_Error mov #17.,AW_Stage br AM_PreflightError AM_PreflightFail: tst AW_Error bne AM_PreflightError mov #24.,AW_Error AM_PreflightError: mov #2,AW_Mode ; BAK transport may have changed mode to 1 mov #1,AW_Result br AM_FinalDisplay AM_FinalDisplay: mov #2,AW_Mode ; all MAIN errors render as MAIN, not BAK jsr PC,DL_Close tst R0 bne AM_DmaFail jsr PC,NET_EnableIdle jsr PC,AW_ShowResult tst WorkDirty bne AM_UIEnd jsr PC,UI_DrawStatus AM_UIEnd: jsr PC,NET_EnableIdle jsr PC,CLK_Start rts PC AM_Unsupported: clr SG_Error mov #StrAWUnsupported,R3 jmp AW_UIMessage AM_NoChanges: jsr PC,KEY_FlushReleased jsr PC,UI_NoChanges br AM_UIEnd AM_BuildFail: mov #StrAWBuildError,R3 jmp AW_UIMessage AM_DmaFail: mov #StrDialogDmaError,R3 jsr PC,UI_StatusText br AM_UIEnd ; ======================================================================== ; r10: success-only report in the ALREADY saved 46x6 DMA modal. ; 10 seconds measured by 200 verified 50-ms BK hardware-timer ticks. ; Any fresh key (not held YES, flushed first) ends the wait early. ; No controller operation and NO reboot while drawing/waiting. ; ======================================================================== AM_ShowVerifiedCountdown: tst AM_BackupReady bne AM_ReportReady mov #1,R0 ; impossible to assert unverified BAK rts PC AM_ReportReady: jsr PC,NET_EnableIdle jsr PC,DL_ClearOnly ; fills only dialog; keeps saved background tst R0 beq AM_ReportDraw mov #1,R0 rts PC AM_ReportDraw: jsr PC,UI_DrawModalFrame mov #16.,UY mov #10.,UX mov #StrAMReportBak,R3 jsr PC,UI_PrintString mov AM_BackupSize,R1 jsr PC,UI_PrintDec5 mov #StrAMReportBytes,R3 jsr PC,UI_PrintString mov #StrAMReportReused,R3 tst AM_BakAction beq AM_ReportBakSuffix mov #StrAMReportCreated,R3 cmp AM_BakAction,#1 beq AM_ReportBakSuffix mov #StrAMReportUpdated,R3 AM_ReportBakSuffix: jsr PC,UI_PrintString mov #17.,UY mov #10.,UX mov #StrAMReportMain,R3 jsr PC,UI_PrintString mov AM_MainSize,R1 jsr PC,UI_PrintDec5 mov #StrAMReportBytes,R3 jsr PC,UI_PrintString mov #18.,UY mov #10.,UX mov #StrAMReportChecks,R3 jsr PC,UI_PrintString mov #19.,UY mov #10.,UX mov #StrAMReportWait,R3 jsr PC,UI_PrintString mov #10.,AM_SecondsLeft mov #20.,AM_TicksLeft jsr PC,AM_PrintCountdown jsr PC,KEY_FlushReleased ; confirmation YES already released jsr PC,CLK_Start ; BK timer 50ms hardware tick AM_ReportPoll: bit #200,@#KEYCSR ; ANY key: reboot immediately bne AM_ReportDone bit #200,@#177712 ; BK timer event, not CPU-loop timing beq AM_ReportPoll mov #KEY_TIMER_PRESET,@#177706 mov #34,@#177712 dec AM_TicksLeft bne AM_ReportPoll mov #20.,AM_TicksLeft dec AM_SecondsLeft beq AM_ReportDone jsr PC,AM_PrintCountdown br AM_ReportPoll AM_ReportDone: bit #200,@#KEYCSR beq AM_ReportTimerDone mov @#KEYDATA,R0 ; consume early key, no release wait AM_ReportTimerDone: jsr PC,CLK_Stop ; restore original BK timer state clr R0 rts PC AM_PrintCountdown: mov #19.,UY mov #37.,UX ; 27-character prefix at x10 mov AM_SecondsLeft,R1 jsr PC,UI_PrintDec2 rts PC ; Hardware AZ+BK reboot only AFTER report countdown or any key. ; Failure leaves verified AZ.INI intact and reports restart failure. AM_RebootAfterVerified: mov #20.,AW_Stage jsr PC,API_Reset tst R0 beq AM_RebootResetOK mov #29.,AW_Error rts PC AM_RebootResetOK: mov #37,@#AZCSR ; restart STM32 + BK, reload AZ.INI mov #50000.,R5 ; bounded fallback if 037 is ignored AM_RebootWait: sob R5,AM_RebootWait mov #21.,AW_Stage mov #30.,AW_Error rts PC ; Compare exact byte content of two AZ RAM banks; final odd byte HIGH ; is ignored; 32768 supported. No write to either bank. R0=0 identical, ; R0=1 different; AW_BadOffset is the first differing byte position. ; Preserve all caller general registers and restore both video/ROM mappings. AM_CompareBanks: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov AM_CheckBankA,R3 mov AM_CheckBankB,R4 mov R3,@#WIN120 mov R4,@#WIN130 mov #120000,R1 mov #130000,R2 mov AM_CheckLength,R5 clc ror R5 bit #1,AM_CheckLength beq AM_CompareCountOK inc R5 AM_CompareCountOK: clr AW_BadOffset tst R5 beq AM_CompareOK AM_CompareNext: mov (R1)+,R0 mov (R2)+,AM_CompareTemp cmp R5,#1 bne AM_CompareWords bit #1,AM_CheckLength beq AM_CompareWords bic #177400,R0 bic #177400,AM_CompareTemp AM_CompareWords: cmp R0,AM_CompareTemp bne AM_CompareFail add #2,AW_BadOffset cmp R1,#130000 blo AM_CompareFirstOK inc R3 mov R3,@#WIN120 mov #120000,R1 AM_CompareFirstOK: cmp R2,#140000 blo AM_CompareSecondOK inc R4 mov R4,@#WIN130 mov #130000,R2 AM_CompareSecondOK: sob R5,AM_CompareNext AM_CompareOK: clr R0 br AM_CompareExit AM_CompareFail: mov #1,R0 AM_CompareExit: mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; After explicit compound confirmation, verify or refresh AZINI.BAK. ; Existing identical BAK is reused; existing different BAK is replaced with ; the FRESH current AZ.INI. No MAIN write if BAK refresh/readback fails. ; Directory error is never treated as BAK absence. Caller loaded-state kept. ; R0=0 BAK verified, R0=1 abort. Original parser pointers restored. AM_CheckOrCreateBak: mov INI_DirNamePtr,AM_RestoreDirPtr mov INI_FileNamePtr,AM_RestoreFilePtr mov INI_StageBase,AM_RestoreOldBase mov INI_Length,AM_RestoreOldLen mov INI_DirLength,AM_RestoreOldDir mov #StrAMBackupPhase,R3 jsr PC,AB_ShowPhase mov #AB_BaseName,INI_DirNamePtr mov #AB_FileName,INI_FileNamePtr jsr PC,INI_DirExactLength tst R0 beq AM_BakFound cmp INI_DirOutcome,#2 bne AM_BakLookupBad ; Missing: create a NEW backup. Never do this when BAK exists. mov #1,AM_BakAction ; newly created backup mov #StrAMNewBackup,R3 jsr PC,AB_ShowPhase mov #1,AW_Mode mov #AB_BaseName,AW_TargetBasePtr mov #AB_FileName,AW_TargetFilePtr jsr PC,AW_TransferAndVerify tst R0 bne AM_BakWriteBad br AM_BakVerified AM_BakFound: mov INI_DirLength,R0 cmp R0,AW_ExpectedLen bne AM_BakDifferent mov #AW_READBACK_BANK,INI_StageBase jsr PC,INI_ReadFile tst R0 bne AM_BakReadBad cmp INI_Length,AW_ExpectedLen bne AM_BakDifferent ; Fresh original is in SG_OUTPUT; readback BAK in 2100. mov #SG_OUTPUT_BANK,AM_CheckBankA mov #AW_READBACK_BANK,AM_CheckBankB mov AW_ExpectedLen,AM_CheckLength jsr PC,AM_CompareBanks tst R0 bne AM_BakDifferent AM_BakVerified: mov AW_ExpectedLen,AM_BackupSize mov #1,AM_BackupReady ; only after verified readback clr AW_Error clr R0 br AM_BakFinish AM_BakDifferent: mov #2,AM_BakAction ; refreshed outdated backup ; Old BAK belongs to a previous AZ.INI revision. The user ; already authorized replacing it in the compound YES dialog. ; SG_OUTPUT still holds a fresh, byte-exact original. mov #StrAMRefreshBackup,R3 jsr PC,AB_ShowPhase mov #1,AW_Mode mov #AB_BaseName,AW_TargetBasePtr mov #AB_FileName,AW_TargetFilePtr jsr PC,AW_TransferAndVerify tst R0 bne AM_BakWriteBad br AM_BakVerified AM_BakReadBad: mov #27.,AW_Error mov #18.,AW_Stage br AM_BakFail AM_BakLookupBad: mov #28.,AW_Error mov #18.,AW_Stage br AM_BakFail AM_BakWriteBad: ; AW_TransferAndVerify reported original transfer error. mov #19.,AW_Stage AM_BakFail: mov #1,R0 AM_BakFinish: mov R0,-(SP) mov AM_RestoreDirPtr,INI_DirNamePtr mov AM_RestoreFilePtr,INI_FileNamePtr mov AM_RestoreOldBase,INI_StageBase mov AM_RestoreOldLen,INI_Length mov AM_RestoreOldDir,INI_DirLength jsr PC,API_Reset tst (SP) bne AM_BakFinishKeep tst R0 beq AM_BakFinishKeep mov #10.,AW_Error mov #1,(SP) AM_BakFinishKeep: mov (SP)+,R0 rts PC AW_UIMessage: mov R3,-(SP) jsr PC,DL_Open tst R0 bne AW_UIMessageFail jsr PC,UI_DrawModalFrame mov (SP)+,R3 mov #17.,UY mov #10.,UX jsr PC,UI_PrintString tst SG_Error beq AW_UIMessageSkipCode mov #18.,UY mov #10.,UX mov #StrAWBuildCode,R3 jsr PC,UI_PrintString mov SG_Error,R1 jsr PC,UI_PrintDec2 AW_UIMessageSkipCode: mov #19.,UY mov #10.,UX mov #StrAnyKey,R3 jsr PC,UI_PrintString jsr PC,KEY_FlushReleased jsr PC,KEY_ReadOne jsr PC,DL_Close br AW_MessageDone AW_UIMessageFail: mov (SP)+,R3 jsr PC,UI_StatusText AW_MessageDone: jsr PC,CLK_Start rts PC ; Source is fresh on-card AZ.INI, NEVER a copy of the older cached INI. ; Source read in 2130..2137; transfer output in 2110..2117. ; Every exit restores original parser/window state including on errors. ; Error code 11 = fresh source file read failed before any WRITE. AB_StageSource:mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov @#WIN_RO,AB_SavedWinRO ; preserve complete hardware protection state mov INI_StageBase,AB_OldStage mov INI_Length,AB_OldLen mov INI_DirLength,AB_OldDirLen mov INI_DirNamePtr,AB_OldDirPtr mov INI_FileNamePtr,AB_OldFilePtr mov #INI_BaseName,INI_DirNamePtr mov #INI_FileName,INI_FileNamePtr mov #11.,AW_Stage mov #StrABPhaseRoot,R3 jsr PC,AB_ShowPhase jsr PC,INI_DirExactLength tst R0 bne AB_SourceError mov INI_DirLength,AW_ExpectedLen mov #AB_FRESH_BANK,INI_StageBase mov #12.,AW_Stage mov #StrABPhaseRead,R3 jsr PC,AB_ShowPhase jsr PC,INI_ReadFile tst R0 bne AB_SourceError cmp INI_Length,AW_ExpectedLen bne AB_SourceBadSize mov #13.,AW_Stage mov #StrABPhaseCopy,R3 jsr PC,AB_ShowPhase ; WIN130 is read-only for the monitor font in normal UI. ; BAK RAM copy must explicitly permit writes before MOV (R1)+,(R2)+. bic #4000,@#WIN_RO mov #AB_FRESH_BANK,R3 mov #SG_OUTPUT_BANK,R4 mov R3,@#WIN120 mov R4,@#WIN130 mov #120000,R1 mov #130000,R2 mov AW_ExpectedLen,R5 clc ror R5 ; logical /2: supports full 32768 bytes bit #1,AW_ExpectedLen beq AB_CopyEven inc R5 AB_CopyEven: tst R5 beq AB_CopyDone AB_CopyLoop: mov (R1)+,(R2)+ cmp R1,#130000 blo AB_CopySrcOK inc R3 mov R3,@#WIN120 mov #120000,R1 AB_CopySrcOK: cmp R2,#140000 blo AB_CopyDstOK inc R4 mov R4,@#WIN130 mov #130000,R2 AB_CopyDstOK: sob R5,AB_CopyLoop AB_CopyDone: mov AB_SavedWinRO,@#WIN_RO ; restore ROM write protection BEFORE UI mov #14.,AW_Stage mov #StrABPhaseReset,R3 jsr PC,AB_ShowPhase ; distinguish RAM copy from final API RESET clr AW_Error clr R0 br AB_SourceCleanup AB_SourceBadSize: mov #8.,AW_Error mov #1,R0 br AB_SourceCleanup AB_SourceError: mov INI_Stage,AW_ReadStage mov R0,AW_ReadCode mov @#AZCSR,AW_CSR mov #11.,AW_Error mov #1,R0 AB_SourceCleanup: mov R0,-(SP) ; Restore original WIN130 protection on ALL success/failure exits. mov AB_SavedWinRO,@#WIN_RO ; On all source-read failure paths, file interface reset. jsr PC,API_Reset tst (SP) bne AB_ResetDone tst R0 beq AB_ResetDone mov #10.,AW_Error mov #1,(SP) AB_ResetDone: mov AB_OldStage,INI_StageBase mov AB_OldLen,INI_Length mov AB_OldDirLen,INI_DirLength mov AB_OldDirPtr,INI_DirNamePtr mov AB_OldFilePtr,INI_FileNamePtr mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R0 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Diagnostic phase message in existing modal row 19. No controller access. ; Restores ordinary video/font bank mapping and caller's R0..R5. AB_ShowPhase: mov R0,-(SP) mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov #19.,UY mov #10.,UX mov #StrABPhaseBlank,R3 jsr PC,UI_PrintString mov #19.,UY mov #10.,UX mov 4.(SP),R3 ; caller R3 beneath saved R5/R4 jsr PC,UI_PrintString mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 mov (SP)+,R0 rts PC ; Popup confirmation: NO by default; only RIGHT+ENTER permits write. AW_Confirm: clr DiscardChoice jsr PC,KEY_FlushReleased jsr PC,DL_Open tst R0 bne AW_ConfirmNo jsr PC,UI_DrawModalFrame mov #16.,UY mov #10.,UX mov #StrAWQuestion,R3 tst AW_Mode beq AW_ConfirmTitleReady cmp AW_Mode,#2 beq AW_ConfirmMainTitle mov #StrABQuestion,R3 br AW_ConfirmTitleReady AW_ConfirmMainTitle: mov #StrAMQuestion,R3 AW_ConfirmTitleReady: jsr PC,UI_PrintString mov #17.,UY mov #10.,UX mov #StrAWWarning,R3 tst AW_Mode beq AW_ConfirmWarningReady cmp AW_Mode,#2 beq AW_ConfirmMainWarn mov #StrABWarning,R3 br AW_ConfirmWarningReady AW_ConfirmMainWarn: mov #StrAMWarning,R3 AW_ConfirmWarningReady: jsr PC,UI_PrintString mov #18.,UY mov #10.,UX mov #StrApplyChoices,R3 jsr PC,UI_PrintString mov #19.,UY mov #10.,UX mov #StrApplyKeys,R3 jsr PC,UI_PrintString jsr PC,UI_DiscardHighlight AW_ConfirmKey: jsr PC,KEY_ReadOne cmp R0,#K_ESC beq AW_ConfirmCancel cmp R0,#K_LEFT beq AW_ConfirmLeft cmp R0,#K_RIGHT beq AW_ConfirmRight cmp R0,#K_ENTER beq AW_ConfirmEnter br AW_ConfirmKey AW_ConfirmLeft:tst DiscardChoice beq AW_ConfirmKey jsr PC,UI_DiscardHighlight clr DiscardChoice jsr PC,UI_DiscardHighlight br AW_ConfirmKey AW_ConfirmRight: tst DiscardChoice bne AW_ConfirmKey jsr PC,UI_DiscardHighlight mov #1,DiscardChoice jsr PC,UI_DiscardHighlight br AW_ConfirmKey AW_ConfirmEnter: tst DiscardChoice beq AW_ConfirmCancel jsr PC,DL_Close tst R0 bne AW_ConfirmNo clr R0 rts PC AW_ConfirmCancel: jsr PC,DL_Close AW_ConfirmNo: mov #1,R0 rts PC AW_ShowProgress: jsr PC,DL_Open tst R0 bne AW_ProgressBad jsr PC,UI_DrawModalFrame mov #16.,UY mov #10.,UX mov #StrAWProgress,R3 tst AW_Mode beq AW_ProgressTitleReady cmp AW_Mode,#2 beq AW_ProgressMainTitle mov #StrABProgress,R3 br AW_ProgressTitleReady AW_ProgressMainTitle: mov #StrAMProgress,R3 AW_ProgressTitleReady: jsr PC,UI_PrintString mov #17.,UY mov #10.,UX mov #StrWritingWarning,R3 tst AW_Mode beq AW_ProgressWarningReady mov #StrABSafeWarning,R3 AW_ProgressWarningReady: jsr PC,UI_PrintString mov #18.,UY mov #10.,UX mov #StrAWReadback,R3 tst AW_Mode beq AW_ProgressDetailReady mov #StrABSafeDetail,R3 AW_ProgressDetailReady: jsr PC,UI_PrintString mov #19.,UY mov #10.,UX mov #StrWritingWait,R3 jsr PC,UI_PrintString clr R0 rts PC AW_ProgressBad: mov #1,R0 rts PC ; Transaction top-level. Save original read-state pointers and restore all ; of them on both verified and failed paths. No mutation of MapActiveBase. AW_TransferAndVerify: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) clr AW_Error clr AW_Stage clr AW_BadOffset clr AW_ReadStage clr AW_ReadCode mov INI_StageBase,AW_OldStageBase mov INI_Length,AW_OldLength mov INI_DirLength,AW_OldDirLength jsr PC,AW_WriteFile tst R0 bne AW_TransferCleanup mov #7,AW_Stage jsr PC,API_Reset tst R0 beq AW_AfterWriteReset mov #10.,AW_Error br AW_TransferCleanup AW_AfterWriteReset: mov AW_TargetBasePtr,INI_DirNamePtr mov AW_TargetFilePtr,INI_FileNamePtr jsr PC,INI_DirExactLength tst R0 bne AW_TransferReadError mov INI_DirLength,R1 cmp R1,AW_ExpectedLen bne AW_TransferSizeError mov #AW_READBACK_BANK,INI_StageBase jsr PC,INI_ReadFile tst R0 bne AW_TransferReadError mov INI_Length,R1 cmp R1,AW_ExpectedLen bne AW_TransferSizeError mov #8.,AW_Stage jsr PC,AW_CompareData tst R0 bne AW_TransferMismatch br AW_TransferCleanup AW_TransferReadError: mov INI_Stage,AW_ReadStage mov R0,AW_ReadCode mov @#AZCSR,AW_CSR mov #7,AW_Stage mov #7,AW_Error br AW_TransferCleanup AW_TransferSizeError: mov #7,AW_Stage mov #8.,AW_Error br AW_TransferCleanup AW_TransferMismatch: mov #8.,AW_Stage mov #9.,AW_Error AW_TransferCleanup: mov #INI_BaseName,INI_DirNamePtr mov #INI_FileName,INI_FileNamePtr mov AW_OldStageBase,INI_StageBase mov AW_OldLength,INI_Length mov AW_OldDirLength,INI_DirLength mov AW_Error,-(SP) jsr PC,API_Reset tst (SP) bne AW_KeepOriginal tst R0 beq AW_KeepOriginal mov #10.,AW_Stage mov #10.,(SP) AW_KeepOriginal: mov (SP)+,AW_Error mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 mov AW_Error,R0 rts PC ; Controller file write: 023 name, 053 open, 051 status, 054 exact ; size, then (023 load IOBUF, 055 commit) for each ceil(bytes/512) block. AW_WriteFile: mov #1,AW_Stage jsr PC,API_Reset tst R0 beq AW_ResetOK jmp AW_ResetFailed AW_ResetOK: mov #2,AW_Stage mov #23,@#AZCSR jsr PC,AW_WaitStatus tst R0 beq AW_NameReady jmp AW_WriteReturn AW_NameReady: mov AW_TargetFilePtr,R2 AW_NameLoop: mov (R2)+,R0 mov R0,@#AZDR tstb R0 beq AW_NameDone bic #377,R0 tst R0 bne AW_NameLoop AW_NameDone: mov #3,AW_Stage mov #53,@#AZCSR jsr PC,AW_WaitStatus tst R0 bne AW_WriteReturn mov #4,AW_Stage mov #51,@#AZCSR jsr PC,AW_WaitStatus tst R0 bne AW_WriteReturn mov @#AZDR,R0 mov @#AZDR,R1 bis R1,R0 beq AW_StatusGood mov #4,AW_Error br AW_WriteReturn AW_StatusGood: mov #5,AW_Stage mov #54,@#AZCSR jsr PC,AW_WaitStatus tst R0 bne AW_WriteReturn mov AW_ExpectedLen,@#AZDR clr @#AZDR ; exact byte length high word mov AW_ExpectedLen,AW_Remain mov #SG_OUTPUT_BANK,AW_Page mov AW_Page,@#WIN120 mov #120000,AW_Ptr AW_WriteNext: tst AW_Remain beq AW_WriteSuccess mov #6,AW_Stage mov AW_Remain,R4 cmp R4,#512. blos AW_LastBlock mov #512.,R4 AW_LastBlock: mov R4,AW_BlockBytes mov R4,R5 inc R5 asr R5 ; ceil(block bytes / 2) mov #23,@#AZCSR jsr PC,AW_WaitStatus tst R0 bne AW_WriteReturn AW_WordLoop: mov AW_Ptr,R2 mov (R2)+,R0 mov R2,AW_Ptr ; At final odd byte: clear HIGH transport byte. cmp R5,#1 bne AW_WordReady bit #1,AW_BlockBytes beq AW_WordReady bic #177400,R0 AW_WordReady: mov R0,@#AZDR cmp R2,#130000 blo AW_NoCross inc AW_Page mov AW_Page,@#WIN120 mov #120000,AW_Ptr AW_NoCross: sob R5,AW_WordLoop mov #55,@#AZCSR jsr PC,AW_WaitStatus tst R0 bne AW_WriteReturn sub AW_BlockBytes,AW_Remain br AW_WriteNext AW_WriteSuccess: clr R0 AW_WriteReturn: rts PC AW_ResetFailed: mov #1,AW_Error rts PC ; Every 053/051/054/023/055 operation waits READY, then checks ERROR. ; Stage points to exact failed operation. Wait is bounded, no retries. AW_WaitStatus: jsr PC,AP_WaitReady tst R0 beq AW_Ready mov #2,AW_Error rts PC AW_Ready: mov @#AZCSR,AW_CSR bit #100000,AW_CSR beq AW_ReadyOK mov #3,AW_Error mov #3,R0 rts PC AW_ReadyOK: clr R0 rts PC ; Compare ceil(bytes/2) words of original and reread AZ2.INI, with ; high byte of final odd-length word masked. Save mismatch BYTE offset. AW_CompareData: mov #SG_OUTPUT_BANK,@#WIN120 mov #AW_READBACK_BANK,@#WIN130 mov #SG_OUTPUT_BANK,AW_Page mov #AW_READBACK_BANK,AW_VerifyPage mov #120000,R1 mov #130000,R2 mov AW_ExpectedLen,R5 clc ror R5 ; logical right shift via clear carry (32768-safe) bit #1,AW_ExpectedLen beq AW_CountEven inc R5 AW_CountEven: clr AW_BadOffset AW_CompareLoop:mov (R1)+,R3 mov (R2)+,R4 cmp R5,#1 bne AW_CompareWord bit #1,AW_ExpectedLen beq AW_CompareWord bic #177400,R3 bic #177400,R4 AW_CompareWord: cmp R3,R4 bne AW_CompareFailed add #2,AW_BadOffset cmp R1,#130000 blo AW_SourcePageOK inc AW_Page mov AW_Page,@#WIN120 mov #120000,R1 AW_SourcePageOK: cmp R2,#140000 blo AW_ReadbackPageOK inc AW_VerifyPage mov AW_VerifyPage,@#WIN130 mov #130000,R2 AW_ReadbackPageOK: sob R5,AW_CompareLoop clr R0 rts PC AW_CompareFailed: cmpb R3,R4 bne AW_CompareLowBad inc AW_BadOffset AW_CompareLowBad: mov #1,R0 rts PC AW_ShowResult: jsr PC,DL_Open tst R0 beq AW_ResultOpenOK jmp AW_ResultAbort AW_ResultOpenOK: jsr PC,UI_DrawModalFrame mov #16.,UY mov #10.,UX tst AW_Result bne AW_FailedTitle mov #StrAWVerified,R3 tst AW_Mode beq AW_TitleReady cmp AW_Mode,#2 beq AW_MainSuccessTitle mov #StrABVerified,R3 br AW_TitleReady AW_MainSuccessTitle: mov #StrAMVerified,R3 br AW_TitleReady AW_FailedTitle: mov #StrAWFailed,R3 tst AW_Mode beq AW_TitleReady cmp AW_Mode,#2 beq AW_MainFailedTitle mov #StrABFailed,R3 br AW_TitleReady AW_MainFailedTitle: cmp AW_Error,#29. beq AW_MainRebootError cmp AW_Error,#30. beq AW_MainRebootError tst AM_WriteStarted bne AW_MainWriteFailedTitle mov #StrAMBlocked,R3 br AW_TitleReady AW_MainRebootError: mov #StrAMRebootFailed,R3 br AW_TitleReady AW_MainWriteFailedTitle: mov #StrAMFailed,R3 AW_TitleReady: jsr PC,UI_PrintString mov #17.,UY mov #10.,UX mov #StrAWStage,R3 jsr PC,UI_PrintString mov AW_Stage,R1 jsr PC,UI_PrintDec2 mov #StrAWError,R3 jsr PC,UI_PrintString mov AW_Error,R1 jsr PC,UI_PrintDec2 mov #StrAWCSR,R3 jsr PC,UI_PrintString mov AW_CSR,R1 jsr PC,UI_PrintOct6 mov #StrAWReadStage,R3 jsr PC,UI_PrintString mov AW_ReadStage,R1 jsr PC,UI_PrintDec2 mov #StrAWReadCode,R3 jsr PC,UI_PrintString mov AW_ReadCode,R1 jsr PC,UI_PrintDec2 mov #18.,UY mov #10.,UX mov #StrAWLength,R3 jsr PC,UI_PrintString mov AW_ExpectedLen,R1 jsr PC,UI_PrintDec5 mov #StrAWOffset,R3 jsr PC,UI_PrintString mov AW_BadOffset,R1 jsr PC,UI_PrintDec5 mov #19.,UY mov #10.,UX mov #StrAnyKey,R3 ; r05: show recovery status ONLY on MAIN failure. No ; controller commands or retries are issued here. tst AW_Result beq AW_FooterReady cmp AW_Mode,#2 bne AW_FooterReady cmp AW_Error,#29. beq AW_FooterSaved cmp AW_Error,#30. beq AW_FooterSaved cmp AW_Error,#25. beq AW_FooterWritten cmp AW_Error,#31. beq AW_FooterWritten tst AM_WriteStarted beq AW_FooterBlocked mov #StrAWPotentialPartial,R3 br AW_FooterReady AW_FooterBlocked: mov #StrAWNotWritten,R3 br AW_FooterReady AW_FooterWritten: mov #StrAWCheckAndRestart,R3 br AW_FooterReady AW_FooterSaved: mov #StrAWSavedManual,R3 AW_FooterReady: jsr PC,UI_PrintString jsr PC,KEY_FlushReleased jsr PC,KEY_ReadOne jsr PC,DL_Close AW_ResultAbort: rts PC ; ======================================================================== ; AZMNT_05: 32-KiB bounded MicroSD AZ.INI reader and conservative parser. ; Two AZ RAM file images A/B, one inactive MAP bank; commit both only ; after the whole file and all 5 required sections + Dnn lines validate. ; The INI reader is read-only; guarded r08 MAIN save is a distinct explicit path. ; Load: 023 name, 050 open, 051 size, 052 block fetch, 022 stream. ; ======================================================================== INI_LoadMapping: clr INI_HeadWord clr INI_Length clr INI_NulOffset clr INI_BadByte mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) clr INI_Error clr INI_DiskCount clr INI_LineNo clr INI_LastCSR mov #INI_FILE_BANK_A,INI_StageBase cmp INI_ActiveBase,#INI_FILE_BANK_A bne INI_ChooseMap mov #INI_FILE_BANK_B,INI_StageBase INI_ChooseMap: mov #MAP_BANK_A,MapStageBase cmp MapActiveBase,#MAP_BANK_A bne INI_ReadNow mov #MAP_BANK_B,MapStageBase ; AZMNT_09 r02: one initial transaction + up to FIVE full retries ; for transport faults only (root SD I/O / file timeout or CSR / cleanup). ; Each next transaction starts with a controller RESET; no partial file ; image or mapping table can become active during unsuccessful attempts. INI_ReadNow: clr INI_RetryCount INI_ReadAttempt: jsr PC,INI_DirExactLength tst R0 bne INI_LoadBad jsr PC,INI_ReadFile tst R0 bne INI_LoadBad jsr PC,NET_EnableIdle ; INI transfer ended + RESET, parse is CPU-only jsr PC,INI_Parse tst R0 bne INI_LoadBad mov INI_StageBase,INI_ActiveBase mov INI_Length,INI_ActiveLength mov MapStageBase,MapActiveBase mov #1,MapLoaded mov #2,MapSource clr MapErrorCode clr R0 br INI_LoadReturn INI_LoadBad: mov R0,INI_Error ; The root-directory iterator may still own a firmware ; stream after a failed AZ.INI lookup. Close it even on ; error, preserving the ORIGINAL error in R0. mov R0,-(SP) jsr PC,API_Reset mov (SP)+,R0 ; Retry only a FAILED read transaction with a transport ; error. Parser errors, missing/empty file, size, syntax, ; or an exhausted directory limit never trigger retries. cmp R0,#11. ; SD/root directory transport error beq INI_RetryMaybe cmp R0,#1 ; read timeout beq INI_RetryMaybe cmp R0,#2 ; read CSR error beq INI_RetryMaybe cmp R0,#13. ; final RESET/cleanup failed bne INI_LoadReturn INI_RetryMaybe: cmp INI_RetryCount,#5. bhis INI_LoadReturn ; 1 initial + 5 retry transactions inc INI_RetryCount clr INI_Length clr INI_DiskCount clr INI_LineNo jmp INI_ReadAttempt INI_LoadReturn: mov #VRAM_PAGE,@#WIN120 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Read exact AZ.INI length from the ROOT directory 22-byte FSIZE ; (offsets 0..3). Command 051 is padded to 512 bytes on hardware. ; The independent bounded root search is read-only. Distinguish: ; 11=SD/dir command error, 14=file truly absent at EOF, 15=guard exhausted; ; 4=existing zero-length file; 3=too large; 12=reported length mismatch. ; No assumed absence on I/O failure and NO guess/fallback. INI_DirExactLength: clr INI_DirOutcome ; 0=error, 1=found, 2=definite EOF/not found mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov #7.,INI_Stage clr INI_DirLength jsr PC,API_Reset tst R0 bne INI_DirError mov #16,@#AZCSR mov #INI_RootName,R2 mov #3.,R3 INI_DirNameLoop: mov (R2)+,@#AZDR sob R3,INI_DirNameLoop mov #3,@#AZCSR jsr PC,INI_CheckReady tst R0 bne INI_DirError jsr PC,API_Reset tst R0 bne INI_DirError mov #BR_MAX_ENTRIES,R5 INI_DirNext: mov #13,@#AZCSR jsr PC,INI_CheckReady tst R0 bne INI_DirError mov #15,@#AZCSR mov #BR_Record,R2 mov #11.,R3 INI_DirRead: mov @#AZDR,(R2)+ sob R3,INI_DirRead tstb BR_Record+9. beq INI_DirNotFound bitb #20,BR_Record+8. bne INI_DirContinue ; 8.3 filename comparison case-insensitive. mov #BR_Record+9.,R2 mov INI_DirNamePtr,R3 ; FILINFO has only 13 bytes for the filename. Reject a ; non-NUL-terminated record without reading adjacent RAM. mov #13.,R4 INI_DirCompare: tst R4 beq INI_DirContinue dec R4 movb (R2)+,R0 cmpb R0,#'a blo INI_DirUpperDone cmpb R0,#'z bhi INI_DirUpperDone sub #40,R0 INI_DirUpperDone: cmpb R0,(R3)+ bne INI_DirContinue tstb R0 bne INI_DirCompare tst BR_Record+2. bne INI_DirTooLarge mov BR_Record,INI_DirLength tst INI_DirLength beq INI_DirZeroSize cmp INI_DirLength,#100000 bhi INI_DirTooLarge mov #1,INI_DirOutcome clr R0 br INI_DirReturn INI_DirContinue: ; SOB is limited to 63 backward words (126 bytes). ; The directory iteration body is longer: use DEC + JMP. dec R5 beq INI_DirLimit jmp INI_DirNext INI_DirLimit: ; Reaching the finite directory bound is not EOF. mov #15.,R0 br INI_DirReturn INI_DirNotFound: mov #2,INI_DirOutcome mov #14.,R0 ; genuine directory EOF: file absent br INI_DirReturn INI_DirZeroSize: mov #3,INI_DirOutcome ; file exists but has zero size mov #4.,R0 br INI_DirReturn INI_DirError: mov #11.,R0 ; transport / SD directory failure br INI_DirReturn INI_DirTooLarge: mov #3,R0 INI_DirReturn: mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; R0 0 success, or error 1 timeout, 2 CSR status, 3 file too large, ; 4 empty file; INI_Stage disambiguates step. INI_Length stays staged. INI_ReadFile: mov #1,INI_Stage jsr PC,API_Reset tst R0 beq INI_FileResetOK mov #1,R0 jmp INI_FileReturn INI_FileResetOK: mov #2,INI_Stage mov #23,@#AZCSR jsr PC,INI_CheckReady tst R0 beq INI_FileNameOK jmp INI_FileReturn INI_FileNameOK: mov INI_FileNamePtr,R2 ; A NUL BYTE terminates the name; a NUL WORD is NOT required. ; Old r03 sent adjacent [ROM] and more data after odd-length filename. INI_SendName: mov (R2)+,R0 mov R0,@#AZDR tstb R0 ; low byte NUL? beq INI_NameDone bic #377,R0 ; high byte NUL? tst R0 bne INI_SendName INI_NameDone: mov #3,INI_Stage mov #50,@#AZCSR jsr PC,INI_CheckReady tst R0 bne INI_FileReturn mov #4,INI_Stage mov #51,@#AZCSR jsr PC,INI_CheckReady tst R0 bne INI_FileReturn mov @#AZDR,INI_Length mov @#AZDR,INI_SizeHigh tst INI_SizeHigh bne INI_SizeTooLarge tst INI_Length beq INI_SizeEmpty cmp INI_Length,#100000 ; unsigned 32768 decimal bhi INI_SizeTooLarge ; 051 may report BLOCK-ROUNDED size. Directory FSIZE is ; exact; require enough bytes, then parse only FSIZE. cmp INI_Length,INI_DirLength blo INI_DirSizeMismatch mov INI_Length,INI_BlockReported mov INI_DirLength,INI_Length mov INI_Length,INI_Remain mov INI_StageBase,INI_StageBasePage mov INI_StageBase,@#WIN120 mov #120000,R3 INI_NextBlock: tst INI_Remain beq INI_FileSuccess mov #5,INI_Stage mov #52,@#AZCSR jsr PC,INI_CheckReady tst R0 bne INI_FileReturn mov #22,@#AZCSR jsr PC,INI_CheckReady tst R0 bne INI_FileReturn mov INI_Remain,R4 cmp R4,#512. blos INI_BlockShort mov #512.,R4 INI_BlockShort: mov R4,INI_BlockSize inc R4 ; ceil(EXACT byte_count/2) words asr R4 ; R4: words to KEEP in AZ RAM mov #256.,R5 ; R5: FULL 512-byte DR block to DRAIN ; The controller exposes a 256-WORD block after each 052/022 pair. ; An exact FSIZE is ONLY a bound for STORING and PARSING the file; ; it must NOT truncate the DR stream on the last partial block. INI_GetWords: mov @#AZDR,R0 ; read EVERY word, even padding tst R4 beq INI_DrainOnly ; remaining block words are discarded mov R0,(R3)+ dec R4 cmp R3,#130000 blo INI_DrainOnly inc INI_StageBasePage mov INI_StageBasePage,@#WIN120 mov #120000,R3 INI_DrainOnly: sob R5,INI_GetWords mov @#AZCSR,INI_LastCSR bit #100000,INI_LastCSR bne INI_BadCSR sub INI_BlockSize,INI_Remain br INI_NextBlock INI_FileSuccess: ; Read-only snapshot, shown if the subsequent parser fails. mov INI_StageBase,@#WIN120 mov @#120000,INI_HeadWord clr R0 ; ALWAYS finish a file transaction with 000 BEFORE INI_Parse, even if ; it stopped early. Keep the original read error; report cleanup failure ; as C:13 / S:08 only when the read itself had succeeded. INI_FileReturn: mov R0,-(SP) jsr PC,API_Reset tst (SP) bne INI_KeepFirstError tst R0 beq INI_KeepFirstError mov #8.,INI_Stage mov #13.,(SP) INI_KeepFirstError: mov (SP)+,R0 rts PC INI_DirSizeMismatch: mov #12.,R0 br INI_FileReturn INI_SizeTooLarge: mov #3,R0 br INI_FileReturn INI_SizeEmpty: mov #4,R0 br INI_FileReturn INI_CheckReady: jsr PC,API_WaitReady mov @#AZCSR,INI_LastCSR tst R0 bne INI_Timeout bit #100000,INI_LastCSR bne INI_BadCSR clr R0 rts PC INI_Timeout: mov #1,R0 rts PC INI_BadCSR: mov #2,R0 rts PC ; Clear inactive 16KiB disk table. Inactive file image is mapped later. INI_Parse: mov #6,INI_Stage mov MapStageBase,R1 mov #4.,R4 INI_ClearPage: mov R1,@#WIN120 mov #120000,R2 mov #2048.,R3 INI_ClearWord: clr (R2)+ sob R3,INI_ClearWord inc R1 sob R4,INI_ClearPage clr INI_Seen clr INI_Section clr INI_DiskSeenLo clr INI_DiskSeenHi clr INI_DiskCount clr INI_LineNo mov INI_Length,INI_ParseRemaining mov INI_StageBase,INI_ParsePage mov INI_ParsePage,@#WIN120 mov #120000,INI_ParsePtr INI_ParseLoop: tst INI_ParseRemaining beq INI_ParseCheckSections jsr PC,INI_ReadLine tst R0 bne INI_ParseReturn jsr PC,INI_ProcessLine tst R0 bne INI_ParseReturn br INI_ParseLoop INI_ParseCheckSections: cmp INI_Seen,#37 ; five required: 1|2|4|010|020 beq INI_ParseGood mov #7,R0 br INI_ParseReturn INI_ParseGood: clr R0 INI_ParseReturn:rts PC ; Read physical line, cap 511 bytes; preserve file bytes in AZ RAM. ; R0 error 5 embedded NUL, 6 long line; CRLF or LF accepted on READ. INI_ReadLine: inc INI_LineNo mov #INI_Line,R3 clr INI_LineLen INI_ReadChar: tst INI_ParseRemaining beq INI_LineFinished mov INI_ParsePtr,R2 movb (R2)+,R0 bic #177400,R0 mov R2,INI_ParsePtr dec INI_ParseRemaining cmp R2,#130000 blo INI_CharPageOK inc INI_ParsePage mov INI_ParsePage,@#WIN120 mov #120000,INI_ParsePtr INI_CharPageOK: tst R0 beq INI_LineNul cmp R0,#12 ; LF terminator (octal) beq INI_LineFinished cmp INI_LineLen,#INI_LINE_LIMIT bhis INI_LineTooLong movb R0,(R3)+ inc INI_LineLen br INI_ReadChar INI_LineFinished: cmp INI_LineLen,#0 beq INI_LineEndNull cmpb -1(R3),#15 ; remove CR before end of line bne INI_LineEndNull dec R3 dec INI_LineLen INI_LineEndNull:clrb (R3) clr R0 rts PC ; Firmware may report an AZ.INI padded with zero bytes to a 512-byte ; boundary (real hardware: 2560 bytes, line 58). This is only accepted ; if ALL remaining bytes after the first NUL are also zero. A nonzero ; suffix is a hard error 5; no partial mapping is ever committed. INI_LineNul: mov INI_Length,INI_NulOffset sub INI_ParseRemaining,INI_NulOffset dec INI_NulOffset ; first NUL byte offset (zero-based) INI_NulTailLoop: tst INI_ParseRemaining beq INI_NulTailOK mov INI_ParsePtr,R2 movb (R2)+,R0 bic #177400,R0 mov R2,INI_ParsePtr dec INI_ParseRemaining cmp R2,#130000 blo INI_NulPageOK inc INI_ParsePage mov INI_ParsePage,@#WIN120 mov #120000,INI_ParsePtr INI_NulPageOK: tst R0 beq INI_NulTailLoop mov R0,INI_BadByte INI_BadTail: mov #5,R0 rts PC INI_NulTailOK: br INI_LineFinished INI_LineTooLong: mov #6,R0 rts PC ; Section names ASCII case-insensitive, path values byte-preserving. INI_ProcessLine: mov #INI_Line,R2 INI_SkipBlank: cmpb (R2),#40 beq INI_SkipChar cmpb (R2),#11 bne INI_CheckContent INI_SkipChar: inc R2 br INI_SkipBlank INI_CheckContent: tstb (R2) beq INI_LineOK cmpb (R2),#'; beq INI_LineOK cmpb (R2),#'# beq INI_LineOK cmpb (R2),#'[ bne INI_CheckDisk jsr PC,INI_ParseSection rts PC INI_CheckDisk: cmp INI_Section,#3 bne INI_LineOK jsr PC,INI_ParseDisk rts PC INI_LineOK: clr R0 rts PC INI_ParseSection: mov #INI_ROM,R3 mov #1,R4 mov #1,R5 jsr PC,INI_MatchName tst R0 bne INI_SectionSet mov #INI_LOGO,R3 mov #2,R4 mov #2,R5 jsr PC,INI_MatchName tst R0 bne INI_SectionSet mov #INI_DISKS,R3 mov #3,R4 mov #4,R5 jsr PC,INI_MatchName tst R0 bne INI_SectionSet mov #INI_NETWORK,R3 mov #4,R4 mov #10,R5 jsr PC,INI_MatchName tst R0 bne INI_SectionSet mov #INI_BOOT,R3 mov #5,R4 mov #20,R5 jsr PC,INI_MatchName tst R0 bne INI_SectionSet ; Unknown section accepted if syntactically bracket-closed. mov R2,R1 INI_UnknownLoop:movb (R1)+,R0 beq INI_BadSection cmpb R0,#'] bne INI_UnknownLoop clr INI_Section clr R0 rts PC INI_SectionSet: bit R5,INI_Seen bne INI_DuplicateSection bis R5,INI_Seen mov R4,INI_Section clr R0 rts PC INI_DuplicateSection: mov #8.,R0 rts PC INI_BadSection: mov #9.,R0 rts PC ; 1 if token equals R3 NUL-terminated, otherwise 0. R2 unchanged. INI_MatchName: mov R2,-(SP) INI_MatchLoop: movb (R2)+,R0 bic #177400,R0 cmp R0,#'a blo INI_MatchCaseDone cmp R0,#'z bhi INI_MatchCaseDone sub #40,R0 INI_MatchCaseDone: cmpb R0,(R3)+ bne INI_MatchNo tstb (R3) bne INI_MatchLoop ; token must end exactly, allowing trailing spaces. INI_MatchTrailing: tstb (R2) beq INI_MatchYes cmpb (R2)+,#40 beq INI_MatchTrailing INI_MatchNo: clr R0 br INI_MatchReturn INI_MatchYes: mov #1,R0 INI_MatchReturn:mov (SP)+,R2 rts PC ; D0..D31=[path] within [DISKS]. All other section contents preserved in ; AZ RAM untouched, and never modified by this read-only stage. INI_ParseDisk: movb (R2)+,R0 bic #177400,R0 cmp R0,#'d beq INI_DiskPrefixOK cmp R0,#'D bne INI_DiskSkipUnknown INI_DiskPrefixOK: movb (R2)+,R4 bic #177400,R4 cmp R4,#'0 blo INI_DiskBad cmp R4,#'9 bhi INI_DiskBad sub #'0,R4 movb (R2),R0 cmp R0,#'= beq INI_DiskHaveEq cmp R0,#'0 blo INI_DiskBad cmp R0,#'9 bhi INI_DiskBad sub #'0,R0 mov R4,R1 asl R4 asl R1 asl R1 asl R1 add R1,R4 add R0,R4 inc R2 INI_DiskHaveEq: cmpb (R2)+,#'= bne INI_DiskBad cmp R4,#31. bhi INI_DiskBad mov R2,R3 ; path chars, not recoded clr R5 INI_DiskMeasure: movb (R3)+,R0 beq INI_DiskMeasured bic #177400,R0 cmp R0,#40 blo INI_DiskBad inc R5 cmp R5,#384. bhi INI_DiskBad br INI_DiskMeasure INI_DiskMeasured: jsr PC,INI_MarkDisk tst R0 bne INI_DiskBad inc INI_DiskCount ; Physical stage offset Dnn*396+10. Map records cleared. mov #10.,R0 mov R4,R1 beq INI_DiskStartCopy INI_DiskOffset: add #MAP_RECORD_LEN,R0 sob R1,INI_DiskOffset INI_DiskStartCopy: mov R2,R3 INI_DiskCopy: tst R5 beq INI_DiskOK movb (R3)+,R1 bic #177400,R1 jsr PC,INI_StageByte inc R0 dec R5 br INI_DiskCopy INI_DiskOK: clr R0 rts PC INI_DiskSkipUnknown: clr R0 rts PC INI_DiskBad: mov #10.,R0 rts PC ; Seen bitmap (2 x16 bits) detects duplicate disk definitions. INI_MarkDisk: mov R2,-(SP) mov R3,-(SP) mov #1,R1 mov R4,R3 cmp R3,#16. blo INI_DiskLow sub #16.,R3 mov #INI_DiskSeenHi,R2 br INI_MaskLoopTest INI_DiskLow: mov #INI_DiskSeenLo,R2 INI_MaskLoopTest: tst R3 beq INI_MaskReady INI_MaskLoop: asl R1 sob R3,INI_MaskLoop INI_MaskReady: bit R1,(R2) bne INI_DiskDuplicate bis R1,(R2) clr R0 br INI_MarkDone INI_DiskDuplicate: mov #1,R0 INI_MarkDone: mov (SP)+,R3 mov (SP)+,R2 rts PC ; R0 physical byte offset (0..12671), R1 byte; preserves R0,R1,R3-R5. INI_StageByte: mov R2,-(SP) mov R3,-(SP) mov R0,R2 mov R0,R3 asr R3 asr R3 asr R3 asr R3 asr R3 asr R3 asr R3 asr R3 asr R3 asr R3 asr R3 asr R3 add MapStageBase,R3 mov R3,@#WIN120 bic #170000,R2 add #120000,R2 movb R1,(R2) ; restore active original INI page for next input line mov INI_ParsePage,@#WIN120 mov (SP)+,R3 mov (SP)+,R2 rts PC ; ----- Read-only controller map (AZSMNT.MAC protocol) ----- ; Reset 000 is also used during startup version probing. 011 selects ; the 32-disk table; 015 starts a 6336-word DR stream. These are READ ; commands. Keep the original reference's 011 -> 015 ordering. No ; CSR polling inside the streaming window: original AZSMNT.MAC reads ; DR consecutively without intervening CSR accesses. ; Transfer to INACTIVE 4-page bank; commit only after entire stream ; and all 32 path fields validate. On error, old map remains visible. MAP_LoadController: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov #MAP_BANK_A,MapStageBase cmp MapActiveBase,#MAP_BANK_A bne MAP_StageOK mov #MAP_BANK_B,MapStageBase MAP_StageOK: clr MapBadDisk clr MapLastCSR jsr PC,API_Reset tst R0 beq MAP_ResetReady mov CSR_Reset,MapLastCSR br MAP_LoadEnd MAP_ResetReady: mov #11,@#AZCSR mov #15,@#AZCSR mov MapStageBase,R4 mov R4,@#WIN120 mov #120000,R3 mov #MAP_WORDS,R5 MAP_StreamWord: mov @#AZDR,(R3)+ cmp R3,#130000 blo MAP_StreamNext inc R4 mov R4,@#WIN120 mov #120000,R3 MAP_StreamNext: sob R5,MAP_StreamWord ; Preserve 011 -> 015 -> 6336 DR words, then wait for ; final READY before checking CSR and committing stage. jsr PC,API_WaitReady mov @#AZCSR,MapLastCSR tst R0 beq MAP_StreamReady mov #ERR_API_TIMEOUT,R0 br MAP_FailCleanup MAP_StreamReady: bit #100000,MapLastCSR beq MAP_ValidateNow mov #ERR_MAP_STATUS,R0 br MAP_FailCleanup MAP_ValidateNow: mov MapStageBase,MapReadBase jsr PC,MAP_ValidateAll tst R0 bne MAP_FailCleanup mov MapStageBase,MapActiveBase mov #1,MapLoaded br MAP_LoadEnd MAP_FailCleanup: ; A failed stream/validation leaves staged data invalid. ; RESET aborts unfinished controller work; preserve the ; FIRST error code and CSR snapshot for the UI report. mov R0,-(SP) jsr PC,API_Reset mov (SP)+,R0 MAP_LoadEnd: mov R0,MapErrorCode mov #VRAM_PAGE,@#WIN120 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Firmware record: size4/date2/time2/flags1/attrs1/fname386. ; Per-record size 396 is even, but a record can cross a 4096-byte ; boundary. Path maximum is 384 bytes plus two terminating NUL bytes. ; This deliberately validates every record before switching banks. MAP_ValidateAll: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) clr R4 MAP_ValidateNext: mov R4,R0 jsr PC,MAP_ReadMeta tst R0 bne MAP_ValidateBad mov R4,R0 jsr PC,MAP_ReadPath tst R0 bne MAP_ValidateBad mov #MapPathCache,R2 mov R1,R3 MAP_CheckChar: tst R3 beq MAP_CheckNext movb (R2)+,R0 bic #177400,R0 cmp R0,#40 blo MAP_ValidateBad dec R3 br MAP_CheckChar MAP_CheckNext: inc R4 cmp R4,#32. blo MAP_ValidateNext clr R0 br MAP_ValidateDone MAP_ValidateBad: mov R4,MapBadDisk mov #ERR_MAP_BAD,R0 MAP_ValidateDone: mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Accessor for the 10-byte per-slot metadata header, retained as raw ; little-endian fields. BK cache: size[4], date[2], time[2], ; flags[1], attributes[1]. Firmware data are not edited or inferred. MAP_ReadMeta: mov R1,-(SP) mov R2,-(SP) mov R4,-(SP) mov R5,-(SP) cmp R0,#32. bcc MAP_MetaBad tst MapReadBase beq MAP_MetaBad clr R2 mov R0,R4 beq MAP_MetaOffsetDone MAP_MetaOffset: add #MAP_RECORD_LEN,R2 sob R4,MAP_MetaOffset MAP_MetaOffsetDone: mov MapReadBase,R4 MAP_MetaPage: cmp R2,#4096. blo MAP_MetaPageOK sub #4096.,R2 inc R4 br MAP_MetaPage MAP_MetaPageOK: mov R4,@#WIN120 add #120000,R2 mov #MapHeaderCache,R5 mov #10.,R1 MAP_MetaByte: movb (R2)+,(R5)+ cmp R2,#130000 blo MAP_MetaNext inc R4 mov R4,@#WIN120 mov #120000,R2 MAP_MetaNext: sob R1,MAP_MetaByte clr R0 br MAP_MetaDone MAP_MetaBad: mov #ERR_MAP_BAD,R0 MAP_MetaDone: mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R2 mov (SP)+,R1 rts PC ; R0 = disk index 0..31, MapReadBase=physical bank. ; Outputs R3=local BK cache pointer, R1=path byte length; R0=0 OK. ; 386-byte path copied across AZ RAM page boundaries into BK RAM. ; Video rendering remaps 120000, so it must never stream directly ; from a banked pointer while UI_PutChar runs. MAP_ReadPath: mov R2,-(SP) mov R4,-(SP) mov R5,-(SP) clr R3 clr R1 cmp R0,#32. bcc MAP_PathBad tst MapReadBase beq MAP_PathBad mov #MAP_PATH_OFFSET,R2 mov R0,R4 beq MAP_OffsetDone MAP_OffsetLoop: add #MAP_RECORD_LEN,R2 sob R4,MAP_OffsetLoop MAP_OffsetDone: mov MapReadBase,R4 MAP_FindPage: cmp R2,#4096. blo MAP_PageReady sub #4096.,R2 inc R4 br MAP_FindPage MAP_PageReady: mov R4,@#WIN120 add #120000,R2 mov #MapPathCache,R5 mov #MAP_PATH_BYTES,R1 MAP_CopyByte: movb (R2)+,(R5)+ cmp R2,#130000 blo MAP_CopyNext inc R4 mov R4,@#WIN120 mov #120000,R2 MAP_CopyNext: sob R1,MAP_CopyByte tstb MapPathCache+384. bne MAP_PathBad tstb MapPathCache+385. bne MAP_PathBad mov #MapPathCache,R3 mov R3,R2 clr R1 MAP_PathLength: cmp R1,#385. bhis MAP_PathBad tstb (R2)+ beq MAP_PathOK inc R1 br MAP_PathLength MAP_PathOK: clr R0 br MAP_PathDone MAP_PathBad: mov #ERR_MAP_BAD,R0 MAP_PathDone: mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R2 rts PC ; Display / marquee API. Never exposes a banked pointer to callers. ; It reads the ACTIVE bank, not a partially downloaded stage. MAP_GetPath: tst MapLoaded beq MAP_EmptyPath mov MapActiveBase,MapReadBase jsr PC,MAP_ReadPath tst R0 bne MAP_EmptyPath rts PC MAP_EmptyPath: clr R3 clr R1 clr R0 rts PC ; ----- Set memory + 512x384 mono; all writes are to AZ video/config ----- ; User 2026-10-15 explicitly permits AZ physical pages 1000..4000. ; The r1 framebuffer overlap heuristic was incorrectly written and is ; removed, not merely inverted. VRAM 2000..2005 remains dedicated here. HW_EnterMono: mov R1,-(SP) bis #100,@#KEYCSR ; mask keyboard IRQ while polling mov #14020,@#SYSCTRL716 ; AZVIDT24 BK11M access path ; The upper ROM/ANDOS window is borrowed only while AZMNT runs. ; Page 2140 is disjoint from VRAM, blitter, maps and INI banks. mov #AZ_DATA_PAGE,@#WIN170 bis #WIN170_MASK,@#WIN_ENABLE bic #WIN170_MASK,@#WIN_DENY bic #WIN170_MASK,@#WIN_RO ; Verify two different values round-trip through mapped RAM. ; Restore pre-existing contents of the probe word in all cases. ; No data-buffer access happens before this test. mov @#AZ_DATA_PROBE,R1 mov #052345,@#AZ_DATA_PROBE cmp @#AZ_DATA_PROBE,#052345 bne HW_170Fail mov #012345,@#AZ_DATA_PROBE cmp @#AZ_DATA_PROBE,#012345 bne HW_170Fail mov R1,@#AZ_DATA_PROBE br HW_170OK HW_170Fail: mov R1,@#AZ_DATA_PROBE ; Restore native upper ROM for pre-video Monitor EMT 16. ; Final HW_Exit will restore the exact old mapper masks/page. bic #WIN170_MASK,@#WIN_ENABLE bis #WIN170_MASK,@#WIN_DENY mov #2,R0 mov (SP)+,R1 rts PC HW_170OK: bis #6000,@#WIN_ENABLE ; enable 120000 and 130000 bic #6000,@#WIN_DENY ; allow mapping of both bic #2000,@#WIN_RO ; allow VRAM writes at 120000 bis #4000,@#WIN_RO ; protect ROM read at 130000 mov #MON_FONT_PAGE,@#WIN130 ; ROM 100 / word +000006, read from live installed ROM. jsr PC,HW_ReadAZBoot clr @#VSCROLL clr @#HSCROLL mov #VRAM_PAGE,@#VIDBASE_REG mov #VIDMODE,@#VIDMODE_REG mov #VRAM_PAGE,@#WIN120 ; Read back registers for on-screen diagnosis (not a proof ; that a connected display is showing this resolution). mov @#VIDMODE_REG,VideoModeReadback mov @#VIDBASE_REG,VideoPageReadback clr R0 mov (SP)+,R1 rts PC ; On invalid ROM layout: display N/A, never claim supplied build 331. ; The ROM's offset +4 is zero in supplied azboot.asm; flag invalid ; layouts conservatively. ROM access needs HW test on BK0010/0011M. HW_ReadAZBoot: mov R1,-(SP) mov #AZBOOT_PAGE,@#WIN130 mov @#130004,R1 bne HWBootInvalid mov @#130006,R1 beq HWBootInvalid cmp R1,#177777 beq HWBootInvalid mov R1,AZBootBuild mov #1,AZBootValid br HWBootDone HWBootInvalid: clr AZBootValid HWBootDone: mov #MON_FONT_PAGE,@#WIN130 clr R0 mov (SP)+,R1 rts PC ; ----- UI 64 columns x 38 COMPLETE text rows (y 0..37) ----- UI_RenderAll: mov R1,-(SP) mov R3,-(SP) mov R4,-(SP) jsr PC,UI_Clear6Pages clr UX clr UY mov #StrHead0,R3 jsr PC,UI_PrintString mov FPGAValue,R1 jsr PC,UI_PrintDec6 ; fixed six-digit decimal firmware version mov #StrHead1,R3 jsr PC,UI_PrintString mov STM_Major,R1 jsr PC,UI_PrintDec3 ; STM byte from 027: DECIMAL, never PrintOct mov #StrHead2,R3 jsr PC,UI_PrintString mov HW_Revision,R1 jsr PC,UI_PrintDec3 mov #StrHead3,R3 jsr PC,UI_PrintString tst AZBootValid beq UI_BootNA mov AZBootBuild,R1 jsr PC,UI_PrintDec5 br UI_HeadDone UI_BootNA: mov #StrNA,R3 jsr PC,UI_PrintString UI_HeadDone: clr UX mov #1,UY mov #64.,R4 UI_DivLoop: mov #BOX_H,R0 jsr PC,UI_PutChar sob R4,UI_DivLoop clr R4 UI_DisksLoop: mov R4,UY add #2,UY clr UX jsr PC,UI_PrintDiskLabel mov R4,R0 jsr PC,MAP_GetPath tst R3 beq UI_DisksNext jsr PC,UI_PrintString UI_DisksNext: inc R4 cmp R4,#32. blo UI_DisksLoop clr UX mov #34.,UY mov #StrMenuRead,R3 jsr PC,UI_PrintString clr UX mov #35.,UY mov #StrMenuWrite,R3 jsr PC,UI_PrintString clr UX mov #36.,UY mov #StrMenuExit,R3 jsr PC,UI_PrintString clr UX mov #37.,UY mov #StrStatus2,R3 jsr PC,UI_PrintString mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R1 clr R0 rts PC ; D00-D31 display as ASCII 0101..0140: A..Z [ \ ] ^ _ `. ; R4 is disk index 0..31; UX and UY are established by caller. ; Dnn is the controller identity; prefix glyph is UI only. UI_PrintDiskLabel: mov R4,R0 add #'A,R0 jsr PC,UI_PutChar mov #StrDiskPrefix,R3 jsr PC,UI_PrintString mov R4,R1 jsr PC,UI_PrintDec2 mov #StrDiskEmpty,R3 jsr PC,UI_PrintString rts PC ; Repaint ONLY the changed Dnn line after a browser popup is closed. ; BR already DMA-restored the underlying frame; frame/header remain intact. ; Selected line was inverted in the background, so clear to zero, draw ; glyphs, and invert once. Screen y=(FocusIndex+2)*10, 32words x10. UI_RedrawSelectedDisk: mov R1,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov FocusIndex,R4 cmp R4,#32. bhis UI_RedrawDone mov R4,R0 add #2,R0 mov R0,UY ; word offset for pixel y=(text row)*10 is row*320. ; 0500 octal = 320 decimal, not 0240 (160 decimal). mov UY,R0 clr R1 UI_RedrawMul: add #0500,R1 sob R0,UI_RedrawMul mov R1,BJ_W3 mov #020440,BJ_W1 clr BJ_W2 clr BJ_W4 mov #005037,BJ_CustomW5 ; 10 rows x 32words, W5.HI actual=10 mov #1,BJ_CustomW6 mov #1,BJ_CustomDMA clr BJ_FullDMA clr BJ_Code jsr PC,BJ_RunDMA tst BJ_Code bne UI_RedrawCpuFallback br UI_RedrawText UI_RedrawCpuFallback: ; If DMA fails, clear only this single physical text row. jsr PC,BJ_QuiesceDMA mov UY,R5 mov R5,R0 asl R5 asl R5 add R0,R5 asl R5 ; R5=(FocusIndex+2)*10 pixels mov #10.,R3 UI_RedrawScan: mov R5,R0 jsr PC,UI_MapScanline mov #32.,R1 UI_RedrawWord: clr (R2)+ sob R1,UI_RedrawWord inc R5 sob R3,UI_RedrawScan UI_RedrawText: mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 clr UX mov R4,UY add #2,UY jsr PC,UI_PrintDiskLabel mov R4,R0 jsr PC,MAP_GetPath tst R3 beq UI_RedrawFocus jsr PC,UI_PrintString UI_RedrawFocus: jsr PC,UI_DrawFocus UI_RedrawDone: mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R1 rts PC UI_Clear6Pages: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov #VRAM_PAGE,R1 mov #VRAM_NPAGES,R3 UI_ClearPage: mov R1,@#WIN120 mov #120000,R2 UI_ClearWord: clr (R2)+ cmp R2,#130000 blo UI_ClearWord inc R1 sob R3,UI_ClearPage mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 clr R0 rts PC ; Startup modal is drawn on BLANK framebuffer (no D00-D31 rows yet). ; After a successful read, UI_RenderAll replaces it with the main list. UI_ModalStub: mov R1,-(SP) mov R3,-(SP) mov R4,-(SP) jsr PC,DL_ClearOnly tst R0 beq UI_ModalClearDone ; Emergency fallback: only x8..53 and y15..20. mov #15.,R4 UI_ModalClear: mov #8.,UX mov R4,UY mov #46.,R1 UI_ModalSpace: mov #40,R0 jsr PC,UI_PutChar sob R1,UI_ModalSpace inc R4 cmp R4,#21. blo UI_ModalClear UI_ModalClearDone: jsr PC,UI_DrawModalFrame mov #16.,UY mov #10.,UX mov #StrDlgTitle,R3 jsr PC,UI_PrintString mov #17.,UY mov #10.,UX mov #StrDlgDefault,R3 jsr PC,UI_PrintString mov #18.,UY mov #10.,UX tst ModalSource bne UI_ModalIniSelected mov #StrDlgController,R3 br UI_ModalSelectedText UI_ModalIniSelected: mov #StrDlgIniSelected,R3 UI_ModalSelectedText: jsr PC,UI_PrintString mov #19.,UY mov #10.,UX mov #StrDlgContinue,R3 jsr PC,UI_PrintString jsr PC,UI_ModalHighlight mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R1 clr R0 rts PC ; XOR the selected token on the EXISTING pixels, x10..29 or x32..37. ; Clobbers R0-R4 via UI_InvertChoice; restore mapper for font/CPU users. UI_ModalHighlight: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov #10.,HighlightX mov #20.,HighlightWidth tst ModalSource beq UI_ModalHighlightDo mov #32.,HighlightX mov #6.,HighlightWidth UI_ModalHighlightDo: mov #17.,R0 jsr PC,UI_InvertChoice mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; On arrows repaint ONLY status line, never modal border/title/options. UI_ModalRefresh: mov R1,-(SP) mov R3,-(SP) mov #18.,UY mov #10.,UX mov #StrDlgBlank,R3 jsr PC,UI_PrintString mov #18.,UY mov #10.,UX tst ModalSource bne UI_ModalRefreshIni mov #StrDlgController,R3 br UI_ModalRefreshPrint UI_ModalRefreshIni: mov #StrDlgIniSelected,R3 UI_ModalRefreshPrint: jsr PC,UI_PrintString mov #16.,UY mov #30.,UX mov #StrDlgDiagBlank,R3 jsr PC,UI_PrintString mov #19.,UY mov #10.,UX mov #StrDlgContinue,R3 jsr PC,UI_PrintString mov (SP)+,R3 mov (SP)+,R1 rts PC ; Framed modal box: x=8..53, y=15..20, inner width 44 chars. UI_DrawModalFrame: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) ; top border mov #8.,UX mov #15.,UY mov #BOX_TL,R0 jsr PC,UI_PutChar mov #44.,R4 UI_BoxTopLoop: mov #BOX_H,R0 jsr PC,UI_PutChar sob R4,UI_BoxTopLoop mov #BOX_TR,R0 jsr PC,UI_PutChar ; side borders rows 16..19 mov #16.,R3 UI_BoxSides: mov #8.,UX mov R3,UY mov #BOX_V,R0 jsr PC,UI_PutChar mov #53.,UX mov R3,UY mov #BOX_V,R0 jsr PC,UI_PutChar inc R3 cmp R3,#20. blo UI_BoxSides ; bottom border mov #8.,UX mov #20.,UY mov #BOX_BL,R0 jsr PC,UI_PutChar mov #44.,R4 UI_BoxBotLoop: mov #BOX_H,R0 jsr PC,UI_PutChar sob R4,UI_BoxBotLoop mov #BOX_BR,R0 jsr PC,UI_PutChar mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 clr R0 rts PC ; ASCII string pointed by R3; advance 8-pixel column; fixed viewport. UI_PrintString: mov R3,-(SP) UI_StrLoop: cmp UX,#64. bcc UI_StrEnd movb (R3)+,R0 beq UI_StrEnd jsr PC,UI_PutChar br UI_StrLoop UI_StrEnd: mov (SP)+,R3 clr R0 rts PC ; BK-0010 Monitor 8x10 glyph table, ROM page 135 mapped at 130000. ; The glyph stream skips codes 0200..0237 (display-control codes). ; Thus ASCII 040..0177 uses the original AZVIDT24 offset 131576+10*code, ; but valid glyphs 0240..0377 use offset 131576+10*(code-040). ; 0200..0237 are NOT glyphs, and are ignored (UX still advances). ; The correction is performed here, not in UI_DrawModalFrame, so that ; every future high-bit ROM glyph uses the same correct address contract. ; Since y in 0..37, scanline max=379 (<384), page max=2005. ; At 512x1: VRAM offset = 64*(pixel_y MOD 64) + column. ; No writes in font window. No 4K cross-boundary write. UI_PutChar: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) cmp R0,#40 blo UI_CharDone cmp UX,#64. bcc UI_CharDone cmp UY,#38. bcc UI_CharDone mov R0,R5 cmp R5,#200 ; 040..0177: contiguous ASCII ROM blo UI_FontIndexOK cmp R5,#240 ; 0200..0237: no stored glyphs blo UI_CharDone sub #40,R5 ; 0240..0377: skip 040 missing slots UI_FontIndexOK: asl R5 mov R5,R1 asl R5 asl R5 add R1,R5 ; 10*adjusted_code add #FONT130_BASE,R5 mov UY,R4 asl R4 mov R4,R1 asl R4 asl R4 add R1,R4 ; 10*row mov #10.,R3 UI_CharScan: mov R4,R2 bic #177700,R2 ; scanline % 64 asl R2 asl R2 asl R2 asl R2 asl R2 asl R2 ; *64 bytes add UX,R2 add #120000,R2 mov R4,R1 asr R1 asr R1 asr R1 asr R1 asr R1 asr R1 ; scanline // 64 add #VRAM_PAGE,R1 mov R1,@#WIN120 movb (R5)+,(R2) inc R4 sob R3,UI_CharScan UI_CharDone: inc UX mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 clr R0 rts PC ; Print unsigned octal 6 digits (from AZVIDT24). UI_PrintOct6: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov #OctBuffer+6,R2 clrb (R2) mov #6,R3 UI_OctDigit: mov R1,R0 bic #177770,R0 add #'0,R0 movb R0,-(R2) clc ror R1 clc ror R1 clc ror R1 sob R3,UI_OctDigit mov #OctBuffer,R3 jsr PC,UI_PrintString mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 clr R0 rts PC ; Decimal formatting: 2/3/5 digits, LEADING ZEROS (no DIV dependency). ; cmp R1,R4 ; blo => remaining < factor, stop subtracting. ; R1 input unsigned, sizes enforced by caller (max 31 or 255 or 65535). UI_PrintDec6: mov #'0,R0 jsr PC,UI_PutChar jmp UI_PrintDec5 UI_PrintDec2: mov #2.,DecWidth br UI_PrintDecimal UI_PrintDec3: mov #3.,DecWidth br UI_PrintDecimal UI_PrintDec5: mov #5.,DecWidth UI_PrintDecimal: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov #DecFactors,R2 mov #DecBuffer,R3 mov #5.,R5 UI_DecOuter: mov (R2)+,R4 mov #'0,R0 UI_DecSub: cmp R1,R4 blo UI_DecStore sub R4,R1 inc R0 br UI_DecSub UI_DecStore: movb R0,(R3)+ sob R5,UI_DecOuter clrb (R3) mov #DecBuffer+5,R3 sub DecWidth,R3 jsr PC,UI_PrintString mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 clr R0 rts PC ; DMA sessions restore A from a verified backup; no RORB repaint needed. UI_ResetMarquee:clr MarqueeOffset rts PC UI_DrawFocus: mov R0,-(SP) mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov FocusIndex,R0 cmp R0,#32. bhis UI_FocusMenu add #2,R0 jsr PC,UI_InvertTextRow br UI_FocusEnd UI_FocusMenu: cmp R0,#34. bhis UI_FocusExit add #2,R0 mov #10.,HighlightX mov #6.,HighlightWidth cmp FocusIndex,#32. bne UI_WriteTarget tst ReadTarget beq UI_HaveTarget br UI_SetRightTarget UI_WriteTarget: tst WriteTarget beq UI_HaveTarget UI_SetRightTarget: mov #19.,HighlightX mov #10.,HighlightWidth UI_HaveTarget: jsr PC,UI_InvertChoice br UI_FocusEnd UI_FocusExit: mov #36.,R0 cmp FocusIndex,#35. beq UI_FocusHelp clr HighlightX mov #13.,HighlightWidth ; EXIT TO ANDOS br UI_FocusBottom UI_FocusHelp: mov #24.,HighlightX mov #4.,HighlightWidth ; HELP UI_FocusBottom: jsr PC,UI_InvertChoice UI_FocusEnd: mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 mov (SP)+,R0 rts PC ; R0=text row (0..37), invert exactly 64 bytes x 10 scanlines. ; No writes outside the selected row, incl. page edges. UI_InvertTextRow: mov R0,R4 mov R4,R1 asl R4 asl R4 add R1,R4 asl R4 ; 10*row mov #10.,R3 UI_InvScan: mov R4,R0 jsr PC,UI_MapScanline mov #64.,R1 UI_InvByte: comb (R2)+ sob R1,UI_InvByte inc R4 sob R3,UI_InvScan rts PC ; Input R0=text row, HighlightX + width: invert focused word only. UI_InvertChoice: mov R0,R4 mov R4,R1 asl R4 asl R4 add R1,R4 asl R4 mov #10.,R3 UI_ChoiceScan: mov R4,R0 jsr PC,UI_MapScanline add HighlightX,R2 mov HighlightWidth,R1 UI_ChoiceByte: comb (R2)+ sob R1,UI_ChoiceByte inc R4 sob R3,UI_ChoiceScan rts PC ; Pixel scanline R0=0..383 -> R2 points to the first byte in WIN120. ; The mapping changes only window 120000; ROM remains mapped at 130000. UI_MapScanline: mov R0,R2 bic #177700,R2 asl R2 asl R2 asl R2 asl R2 asl R2 asl R2 add #120000,R2 asr R0 asr R0 asr R0 asr R0 asr R0 asr R0 add #VRAM_PAGE,R0 mov R0,@#WIN120 rts PC ; Called on BK timer 50ms expiration, NOT from an IRQ. ; The DMA session is cancellable by navigation keys. UI_TickMarquee: mov R0,-(SP) mov R1,-(SP) mov R3,-(SP) cmp FocusIndex,#32. bhis UI_TickDone tst MarqueeDone bne UI_TickDone mov FocusIndex,R0 jsr PC,MAP_GetPath tst R3 beq UI_TickDone cmp R1,#PATH_VIEW blos UI_TickDone inc MarqueeAge cmp MarqueeAge,#20. blo UI_TickDone mov #1,MarqueeDone ; prevent replay until next selection jsr PC,BJ_SelectedRun mov BJ_Code,R0 beq UI_TickDone jsr PC,UI_ShowScrollError UI_TickDone: mov (SP)+,R3 mov (SP)+,R1 mov (SP)+,R0 rts PC UI_ROMGlyphByte: mov R2,-(SP) mov R3,-(SP) cmp R0,#40 blo UI_GlyphEmpty cmp R0,#200 blo UI_GlyphValid cmp R0,#240 blo UI_GlyphEmpty sub #40,R0 UI_GlyphValid: mov R0,R2 asl R2 mov R2,R3 asl R2 asl R2 add R3,R2 add #FONT130_BASE,R2 add R1,R2 movb (R2),R0 bic #177400,R0 br UI_GlyphDone UI_GlyphEmpty: clr R0 UI_GlyphDone: mov (SP)+,R3 mov (SP)+,R2 rts PC ; All user-facing BK strings are in English. ; Context/status footer. Never reports unverified success. UI_DrawStatus: mov R1,-(SP) mov R3,-(SP) mov #37.,UY clr UX mov #Str64Spaces,R3 jsr PC,UI_PrintString clr UX tst DebugMode beq UI_StatusNormal mov #StrDebugOn,R3 br UI_StatusRender UI_StatusNormal:tst MapLoaded beq UI_StatusEmpty tst WorkDirty bne UI_StatusDirty mov #StrStatusMap,R3 cmp MapSource,#2 bne UI_StatusRender mov #StrStatusIni,R3 br UI_StatusRender UI_StatusDirty: mov #StrWorkDirty,R3 br UI_StatusRender UI_StatusEmpty: mov #StrStatusNoop,R3 UI_StatusRender:jsr PC,UI_PrintString mov (SP)+,R3 mov (SP)+,R1 rts PC ; IND SU toggles debug without touching WORK, disk mappings or controller. ; Keyboard command is non-repeating: KEY_Poll waits for key release. APP_ToggleDebug: tst DebugMode beq APP_DebugEnable clr DebugMode br APP_DebugDisplay APP_DebugEnable:mov #1,DebugMode APP_DebugDisplay:jsr PC,UI_DrawStatus rts PC ; R3=English one-line message, shown within row 37. UI_StatusText: mov R1,-(SP) mov R3,-(SP) mov #37.,UY clr UX mov #Str64Spaces,R3 jsr PC,UI_PrintString clr UX mov (SP),R3 jsr PC,UI_PrintString mov (SP)+,R3 mov (SP)+,R1 rts PC UI_ShowMapError: mov R1,-(SP) mov R3,-(SP) mov #StrMapReadError,R3 jsr PC,UI_StatusText mov #14.,UX mov MapErrorCode,R1 jsr PC,UI_PrintDec2 mov #21.,UX mov MapLastCSR,R1 jsr PC,UI_PrintOct6 mov #30.,UX mov MapBadDisk,R1 jsr PC,UI_PrintDec2 mov (SP)+,R3 mov (SP)+,R1 rts PC ; Failed INI must leave MapActiveBase and the visible disk list intact. UI_ShowIniError: mov R1,-(SP) mov R3,-(SP) ; Same fixed-width diagnostics as r14, with a readable ; reason in the prefix. Errors NEVER replace the active map. mov #StrIniReadError,R3 cmp INI_Error,#15. bne UI_IniNotLimit mov #StrIniDirLimit,R3 br UI_IniTextReady UI_IniNotLimit: cmp INI_Error,#11. bne UI_IniNotSD mov #StrIniSDRead,R3 br UI_IniTextReady UI_IniNotSD: UI_IniTextReady:jsr PC,UI_StatusText ; Match the digit placeholders in StrIni* exactly. mov #12.,UX mov INI_Error,R1 jsr PC,UI_PrintDec2 mov #17.,UX mov INI_Stage,R1 jsr PC,UI_PrintDec2 mov #22.,UX mov INI_LastCSR,R1 jsr PC,UI_PrintOct6 mov #31.,UX mov INI_LineNo,R1 jsr PC,UI_PrintDec5 mov #39.,UX mov INI_DiskCount,R1 jsr PC,UI_PrintDec2 mov (SP)+,R3 mov (SP)+,R1 rts PC UI_ModalReadError: mov R1,-(SP) mov R3,-(SP) mov #18.,UY mov #10.,UX mov #StrDlgBlank,R3 jsr PC,UI_PrintString mov #10.,UX mov #StrDlgReadFail,R3 tst ModalSource beq UI_ModalFailTitle cmp INI_Error,#11. bne UI_ModalNotDir mov #StrDlgIniSD,R3 br UI_ModalFailTitle UI_ModalNotDir: cmp INI_Error,#15. bne UI_ModalFailTitle mov #StrDlgIniLimit,R3 UI_ModalFailTitle: jsr PC,UI_PrintString mov #18.,UX mov MapErrorCode,R1 jsr PC,UI_PrintDec2 mov #25.,UX mov MapLastCSR,R1 jsr PC,UI_PrintOct6 mov #19.,UY mov #10.,UX mov #StrDlgBlank,R3 jsr PC,UI_PrintString mov #10.,UX mov #StrDlgRetry,R3 jsr PC,UI_PrintString tst ModalSource beq UI_ModalErrorDone ; S=read/parser stage, L=parser physical line, ; N=reported byte length, H=first word of staged file. mov #16.,UY mov #30.,UX mov #StrDlgIniDiag,R3 jsr PC,UI_PrintString mov #32.,UX mov INI_Stage,R1 jsr PC,UI_PrintDec2 mov #37.,UX mov INI_LineNo,R1 jsr PC,UI_PrintDec5 mov #45.,UX mov INI_Length,R1 jsr PC,UI_PrintDec5 mov #19.,UY mov #34.,UX mov #StrDlgHead,R3 jsr PC,UI_PrintString mov INI_HeadWord,R1 jsr PC,UI_PrintOct6 mov #43.,UX mov #StrDlgNulOffset,R3 jsr PC,UI_PrintString mov INI_NulOffset,R1 jsr PC,UI_PrintDec5 UI_ModalErrorDone: mov (SP)+,R3 mov (SP)+,R1 rts PC UI_ShowScrollError: mov R1,-(SP) mov R3,-(SP) mov #37.,UY clr UX mov #Str64Spaces,R3 jsr PC,UI_PrintString clr UX mov #StrScrollError,R3 jsr PC,UI_PrintString mov BJ_Code,R1 jsr PC,UI_PrintDec2 mov (SP)+,R3 mov (SP)+,R1 rts PC CLK_Start: mov @#177706,ClockOldPreset mov @#177712,ClockOldControl mov #1,ClockActive mov #KEY_TIMER_PRESET,@#177706 mov #34,@#177712 rts PC CLK_Stop: tst ClockActive beq CLK_StopDone mov ClockOldPreset,@#177706 mov ClockOldControl,R0 bic #200,R0 ; status bit is not a command mov R0,@#177712 clr ClockActive CLK_StopDone: rts PC ; Network availability contract for AZ STM32 V19+: RESET 000 inhibits ; network service; CSR 110 permits it between controller transactions. ; This routine is used ONLY after a transaction or when keyboard UI is idle. ; Do not invoke between commands in an active controller exchange. ; No-AZ/probe failures never touch controller CSR (NetReadyToUse=0). ; Idempotent per RESET: no repeated CSR110 writes during key polling. ; A stuck/not-ready controller is not force-reset here: leave error handling ; to the owning API routine instead of touching an incomplete transfer. NET_EnableIdle: tst NetReadyToUse beq NET_IdleReturn tst NetIdleOn bne NET_IdleReturn bit #200,@#AZCSR beq NET_IdleReturn bit #100000,@#AZCSR ; do not conceal a failed controller op bne NET_IdleReturn mov #NET_ENABLE_CMD,@#AZCSR mov #1,NetIdleOn NET_IdleReturn: rts PC ; NONBLOCKING poll: return R0=0 when no command, otherwise key code. ; For held arrows use the verified AZVIDT24 timer protocol: first ; event immediately; second after 500ms; remaining at 50ms intervals. ; When released, return to background 50ms ticks for pixel marquee. KEY_Poll: mov R1,-(SP) jsr PC,NET_EnableIdle ; executed at UI idle boundary, not during AZ commands tst ClockActive beq KEY_PollScan bit #200,@#177712 beq KEY_PollScan tst HeldArrow bne KEY_RepeatTick ; Background marquee tick. mov #KEY_TIMER_PRESET,@#177706 mov #34,@#177712 jsr PC,UI_TickMarquee br KEY_PollScan KEY_RepeatTick: bit #100,@#SYSCTRL716 bne KEY_ArrowReleased mov #KEY_TIMER_PRESET,@#177706 mov #34,@#177712 mov HeldArrow,R0 br KEY_PollReturn KEY_ArrowReleased: clr HeldArrow jsr PC,KEY_RestartBackground jsr PC,KEY_FlushReleased KEY_PollScan: tst PendingCommand bne KEY_PendingRelease tst HeldArrow beq KEY_CheckFresh bit #100,@#SYSCTRL716 beq KEY_PollNone clr HeldArrow jsr PC,KEY_RestartBackground jsr PC,KEY_FlushReleased KEY_CheckFresh: bit #200,@#KEYCSR beq KEY_PollNone mov @#KEYDATA,R0 bic #177600,R0 cmp R0,#K_LEFT beq KEY_BeginArrow cmp R0,#K_RIGHT beq KEY_BeginArrow cmp R0,#K_UP beq KEY_BeginArrow cmp R0,#K_DOWN beq KEY_BeginArrow mov R0,PendingCommand br KEY_PendingRelease KEY_BeginArrow: mov R0,HeldArrow mov #KEY_TIMER_FIRST,@#177706 mov #34,@#177712 br KEY_PollReturn KEY_PendingRelease: bit #100,@#SYSCTRL716 beq KEY_PollNone mov PendingCommand,-(SP) clr PendingCommand jsr PC,KEY_FlushReleased mov (SP)+,R0 br KEY_PollReturn KEY_PollNone: clr R0 KEY_PollReturn: mov (SP)+,R1 rts PC KEY_RestartBackground: mov #KEY_TIMER_PRESET,@#177706 mov #34,@#177712 rts PC ; ----- Keyboard: ONE event per physical press/release, no timer ----- ; Ported from AZVIDT24 ReadKeySingle / FlushReleasedKeys. In this ; keyboard helper emits one event per physical press. KEY_ReadOne: mov R1,-(SP) jsr PC,NET_EnableIdle ; modal waits, guarded against NoAZ probe failure KEY_OldRelease: bit #100,@#SYSCTRL716 beq KEY_OldRelease jsr PC,KEY_FlushReleased KEY_WaitFresh: bit #200,@#KEYCSR beq KEY_WaitFresh mov @#KEYDATA,R0 bic #177600,R0 mov R0,-(SP) KEY_WaitRelease: bit #100,@#SYSCTRL716 beq KEY_WaitRelease jsr PC,KEY_FlushReleased mov (SP)+,R0 mov (SP)+,R1 rts PC KEY_FlushReleased: mov R1,-(SP) mov #32.,R1 KEY_FlushLoop: bit #100,@#SYSCTRL716 beq KEY_FlushDone bit #200,@#KEYCSR beq KEY_FlushDone mov @#KEYDATA,R0 sob R1,KEY_FlushLoop KEY_FlushDone: mov (SP)+,R1 rts PC ; ----- Monitor diagnostic for pre-video failures; no RT-11 .PRINT ----- MON_Print: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) MON_PrintLoop: movb (R3)+,R0 beq MON_PrintDone EMT 16 br MON_PrintLoop MON_PrintDone: mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 clr R0 rts PC ; Pre-video OCTAL diagnostic from Monitor console, R1=word. ; Does NOT require video mode, FONT window or integer division. MON_PrintOct6: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov #DiagOctBuf+6,R2 clrb (R2) mov #6,R3 MON_OctLoop: mov R1,R0 bic #177770,R0 add #'0,R0 movb R0,-(R2) clc ror R1 clc ror R1 clc ror R1 sob R3,MON_OctLoop mov #DiagOctBuf,R3 jsr PC,MON_Print mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 clr R0 rts PC BH_Wait: mov #KEY_TIMER_PRESET,@#177706 mov #34,@#177712 mov #120.,R3 ; 6-second independent watchdog mov #177777,R4 BH_WaitLoop: tst BH_WaitMode bne BH_WaitFrames tst BH_Pending beq BH_WaitOK br BH_WaitTimer BH_WaitFrames: cmp #120.,BH_FrameTicks bcc BH_WaitOK BH_WaitTimer: bit #200,@#177712 beq BH_WaitSpin mov #KEY_TIMER_PRESET,@#177706 mov #34,@#177712 dec R3 beq BH_WaitFail mov #177777,R4 br BH_WaitLoop BH_WaitSpin: sob R4,BH_WaitLoop BH_WaitFail: mov #1,R0 rts PC BH_WaitOK: clr R0 rts PC BH_ISR: tst BH_Pending beq BH_IRQTicks mov BH_NewBase,@#VIDBASE_REG inc BH_FlipCount clr BH_FrameTicks clr BH_Pending rti BH_IRQTicks: cmp BH_FrameTicks,#177777 beq BH_IRQExit inc BH_FrameTicks BH_IRQExit: rti ; =================================================================== ; Selected-row DMA session. Only one row is ever changed per frame. ; A=2000..2005, B=2010..2015, packet=2056, stage=2057, ; raster=2062, backup=2064, guard=2016. No real disk mapping I/O. ; =================================================================== BJ_SelectedRun: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) clr BJ_Code clr BJ_DmaCount clr BJ_ErrOffset clr BJ_Expected clr BJ_Actual clr BJ_IrqOn clr BJ_HaveBackup clr BJ_FullDMA mov @#BL_PACKET_REG,BJ_OldPacket mov FocusIndex,R0 jsr PC,MAP_GetPath tst R3 beq BJ_SessionExit cmp R1,#PATH_VIEW blos BJ_SessionExit mov R3,BJ_Path mov R1,BJ_Len mov #1,BJ_Inverse ; selected screen row is inverted jsr PC,BJ_SelectRect jsr PC,BJ_CloneRapid tst BJ_Code bne BJ_SessionExit mov #VRAM_PAGE,BJ_DrawBase jsr PC,BJ_SaveA tst BJ_Code bne BJ_SessionExit mov #1,BJ_HaveBackup jsr PC,BN_Start BJ_SessionTidy: jsr PC,BJ_QuiesceDMA jsr PC,BJ_RemoveIRQ tst BJ_HaveBackup beq BJ_SessionExit tst BJ_AIsClean bne BJ_SessionExit jsr PC,BJ_RestoreA BJ_SessionExit: jsr PC,BJ_QuiesceDMA mov BJ_OldPacket,@#BL_PACKET_REG mov #MON_FONT_PAGE,@#WIN130 mov #VRAM_PAGE,@#WIN120 mov #KEY_TIMER_PRESET,@#177706 mov #34,@#177712 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 mov BJ_Code,R0 rts PC ; DMA fail-closed: never return to UI while the blitter is busy. ; On a persistent hardware fault this deliberately waits for hardware ; recovery/reset rather than risk ANDOS state or overwrite disk/video. BJ_QuiesceDMA: tst BL_Unstopped beq BJ_QuiesceCheck clr @#BL_REG BJ_QuiesceCheck: bit #100000,@#BL_REG beq BJ_QuiesceOK clr @#BL_REG br BJ_QuiesceCheck BJ_QuiesceOK: clr BL_Unstopped rts PC ; Build 10x56-byte source at x8 once; one pixel shift per frame. BN_Start: clr BN_Pos clr BN_EarlyStop mov #1,BN_BitMask mov #PATH_VIEW,BN_NextChar mov BJ_Len,R0 sub #PATH_VIEW,R0 asl R0 asl R0 asl R0 mov R0,BN_Max jsr PC,BN_Build mov #2010,BJ_DrawBase jsr PC,BN_DrawOne tst BJ_Code beq BN_Good1 jmp BN_Return BN_Good1: jsr PC,BN_Verify tst BJ_Code beq BN_Good2 jmp BN_Return BN_Good2: jsr PC,BJ_InstallIRQ mov #2010,BH_NewBase mov #1,BH_Pending clr BH_WaitMode jsr PC,BH_Wait tst R0 beq BN_FirstCheck mov #5.,BJ_Code jmp BN_Return BN_FirstCheck: cmp @#VIDBASE_REG,#2010 beq BN_NextPixel mov #5.,BJ_Code jmp BN_Return BN_NextPixel: jsr PC,BN_CheckAbort tst BN_EarlyStop bne BN_EndNow cmp BN_Pos,BN_Max bhis BN_EndNow inc BN_Pos jsr PC,BN_ShiftSource asl BN_BitMask cmp BN_BitMask,#400 bne BN_BitReady mov #1,BN_BitMask inc BN_NextChar BN_BitReady: cmp @#VIDBASE_REG,#2010 bne BN_DrawB mov #VRAM_PAGE,BJ_DrawBase br BN_DrawReady BN_DrawB: mov #2010,BJ_DrawBase BN_DrawReady: jsr PC,BN_DrawOne tst BJ_Code beq BN_Good3 jmp BN_Return BN_Good3: mov BJ_DrawBase,BH_NewBase mov #1,BH_Pending clr BH_WaitMode jsr PC,BH_Wait tst R0 beq BN_CheckFlip mov #7.,BJ_Code jmp BN_Return BN_CheckFlip: cmp @#VIDBASE_REG,BJ_DrawBase beq BN_NextPixel mov #7.,BJ_Code jmp BN_Return ; Session end: B visible, restore A from packed backup while hidden. BN_EndNow: tst BN_EarlyStop bne BN_EnsureB ; No 2-second diagnostic dwell: end on completed pixel. BN_EnsureB: cmp @#VIDBASE_REG,#2010 beq BN_Restore mov #2010,BJ_DrawBase jsr PC,BN_DrawOne tst BJ_Code beq BN_Good4 jmp BN_Return BN_Good4: jsr PC,BN_Verify tst BJ_Code beq BN_Good5 jmp BN_Return BN_Good5: mov #2010,BH_NewBase mov #1,BH_Pending clr BH_WaitMode jsr PC,BH_Wait tst R0 beq BN_Restore mov #8.,BJ_Code jmp BN_Return BN_Restore: jsr PC,BJ_RestoreA tst BJ_Code beq BN_Good6 jmp BN_Return BN_Good6: mov #VRAM_PAGE,BH_NewBase mov #1,BH_Pending clr BH_WaitMode jsr PC,BH_Wait tst R0 beq BN_CheckReturn mov #8.,BJ_Code jmp BN_Return BN_CheckReturn: cmp @#VIDBASE_REG,#VRAM_PAGE beq BN_Return mov #8.,BJ_Code BN_Return: rts PC ; Nonblocking navigation during animation. The keyboard event is queued ; for the main loop and replayed after safe A restoration. BN_CheckAbort: bit #200,@#KEYCSR beq BN_AbortDone mov @#KEYDATA,R0 bic #177600,R0 cmp R0,#K_UP beq BN_AbortQueue cmp R0,#K_DOWN beq BN_AbortQueue cmp R0,#K_LEFT beq BN_AbortQueue cmp R0,#K_RIGHT beq BN_AbortQueue cmp R0,#K_ESC bne BN_AbortDone BN_AbortQueue: mov R0,PendingCommand mov #1,BN_EarlyStop BN_AbortDone: rts PC ; Build source raster for selected path in page2062; space x8 + 55 glyphs. BN_Build: mov #2062,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov #120000,R5 mov #BN_Prefix,BN_PrefixPtr clr BJ_Line BN_BuildScan: mov #40,R0 ; fixed space before path at x8 mov BJ_Line,R1 jsr PC,UI_ROMGlyphByte tst BJ_Inverse beq BN_PrefixPlain com R0 BN_PrefixPlain: mov BN_PrefixPtr,R1 movb R0,(R1)+ mov R1,BN_PrefixPtr movb R0,(R5)+ clr BJ_Char mov #PATH_VIEW,BJ_Remain BN_BuildGlyph: mov BJ_Char,R3 jsr PC,BJ_GetByte tst BJ_Inverse beq BN_StoreGlyph com R0 BN_StoreGlyph: movb R0,(R5)+ inc BJ_Char dec BJ_Remain bne BN_BuildGlyph inc BJ_Line cmp BJ_Line,#10. blo BN_BuildScan mov #MON_FONT_PAGE,@#WIN130 mov #VRAM_PAGE,@#WIN120 rts PC BN_ShiftSource: mov #BN_Prefix,BN_PrefixPtr mov #2062,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov #120070,R4 ; end of row0, 56 bytes mov #10.,BN_RowRemain clr BJ_Line BN_ShiftScan: mov BN_NextChar,R3 jsr PC,BJ_GetByte tst BJ_Inverse beq BN_ShiftNormal com R0 BN_ShiftNormal: mov #28.,R2 mov R4,R5 bit BN_BitMask,R0 beq BN_ShiftZero sec br BN_ShiftWord BN_ShiftZero: clc BN_ShiftWord: ror -(R5) sob R2,BN_ShiftWord mov BN_PrefixPtr,R1 movb (R1)+,(R5) ; restore unchanged space at x8 mov R1,BN_PrefixPtr add #70,R4 ; +56 bytes (octal 70) inc BJ_Line dec BN_RowRemain bne BN_ShiftScan rts PC ; One DMA011 per scroll step to hidden framebuffer. BN_DrawOne: mov #3,BJ_Stage mov #020440,BJ_W1 mov #0110000,BJ_W2 ; source page2062 word low mov BJ_RectLow,R0 cmp BJ_DrawBase,#2010 bne BN_DestReady add #040000,R0 BN_DestReady: mov R0,BJ_W3 mov #11,BJ_W4 jsr PC,BJ_RunDMA tst BJ_Code bne BN_DrawDone cmp BJ_DrawBase,#VRAM_PAGE bne BN_DrawDone clr BJ_AIsClean BN_DrawDone: rts PC ; Initial and last frame: compare packed raster with DMA destination. ; Works across 4KiB framebuffer page boundary, unlike r15 check. BN_Verify: mov #2062,BJ_ComparePage mov #12.,BJ_CompareError jsr PC,BJ_CompareRect rts PC BJ_CloneRapid: mov #0,BJ_Stage cmp @#VIDMODE_REG,#VIDMODE bne BJ_CloneError cmp @#VIDBASE_REG,#VRAM_PAGE bne BJ_CloneError tst @#BL_REG bne BJ_CloneError mov #2016,@#WIN120 mov #120000,R1 mov #2048.,R3 BJ_CGuardInit: mov #BL_POISON,(R1)+ sob R3,BJ_CGuardInit mov #1,BJ_FullDMA clr BJ_ClonePage clr BJ_CloneALow mov #040000,BJ_CloneBLow BJ_CPage: mov #020440,BJ_W1 mov #074000,BJ_W2 ; linear staging 2057 mov BJ_CloneALow,BJ_W3 mov #42,BJ_W4 jsr PC,BJ_RunDMA tst BJ_Code bne BJ_CloneDone mov BJ_CloneBLow,BJ_W3 mov #11,BJ_W4 jsr PC,BJ_RunDMA tst BJ_Code bne BJ_CloneDone mov BJ_ClonePage,R0 add #2000,R0 mov R0,@#WIN120 mov BJ_ClonePage,R0 add #2010,R0 mov R0,@#WIN130 mov #120000,R1 mov #130000,R2 mov #2048.,R3 BJ_CCmpWord: cmp (R1)+,(R2)+ bne BJ_CloneError sob R3,BJ_CCmpWord inc BJ_ClonePage add #04000,BJ_CloneALow add #04000,BJ_CloneBLow cmp BJ_ClonePage,#6. blo BJ_CPage mov #2016,@#WIN120 mov #120000,R1 mov #2048.,R3 BJ_CGuardScan: cmp (R1)+,#BL_POISON bne BJ_CloneError sob R3,BJ_CGuardScan br BJ_CloneDone BJ_CloneError: mov #1,BJ_Code BJ_CloneDone: clr BJ_FullDMA mov #MON_FONT_PAGE,@#WIN130 mov #VRAM_PAGE,@#WIN120 rts PC ; Save and restore the selected A rectangle only, not both rows. BJ_SaveA: mov #1,BJ_Stage mov #1,BJ_AIsClean mov #020440,BJ_W1 mov BJ_BackLow,BJ_W2 mov BJ_RectLow,BJ_W3 mov #42,BJ_W4 jsr PC,BJ_RunDMA tst BJ_Code bne BJ_SaveEnd jsr PC,BJ_VerifyBackup BJ_SaveEnd: rts PC ; R0 = disk row index 0..31. Physical A offset in 16-bit words: ; 32 * ((index+2)*10) + 4. 8-byte x origin preserves 'A: Dnn = '. ; y=10*(index+2); one logical text row contains 10 scanlines. BJ_SelectRect: mov FocusIndex,R0 add #2.,R0 mov R0,R1 asl R0 asl R0 add R1,R0 asl R0 ; y=10*(index+2) mov R0,R1 asl R0 asl R0 asl R0 asl R0 asl R0 ; y*32 words add #4,R0 ; x=8 bytes mov R0,BJ_RectLow mov #0120000,BJ_BackLow mov #2064,BJ_BackPage mov R1,R0 bic #177700,R0 ; scanline within 64-line page asl R0 asl R0 asl R0 asl R0 asl R0 asl R0 ; *64 bytes add #130010,R0 mov R0,BJ_VisiblePtr mov R1,R0 asr R0 asr R0 asr R0 asr R0 asr R0 asr R0 add #2000,R0 mov R0,BJ_VisiblePage rts PC BJ_VerifyBackup: mov BJ_BackPage,BJ_ComparePage mov #2,BJ_CompareError jsr PC,BJ_CompareRect rts PC ; Compare packed rectangle to A/B video, page-map EACH scanline. ; Source page is always 2062 or 2064, 560 bytes, contiguous. ; Preserve original r15 first-frame/restore verification semantics. BJ_CompareRect: mov BJ_ComparePage,@#WIN120 mov BJ_VisiblePage,R0 cmp BJ_DrawBase,#2010 bne BJ_CompareMap add #10,R0 BJ_CompareMap: mov R0,BJ_WorkPage mov R0,@#WIN130 mov #120000,R1 mov BJ_VisiblePtr,R2 mov #10.,R3 BJ_CompareScan:mov #28.,R4 BJ_CompareWord:cmp (R1)+,(R2)+ bne BJ_CompareBad sob R4,BJ_CompareWord add #10,R2 ; 4 untouched words / next scanline cmp R2,#140000 blo BJ_CompareNext mov #130010,R2 inc BJ_WorkPage mov BJ_WorkPage,@#WIN130 BJ_CompareNext:sob R3,BJ_CompareScan br BJ_CompareDone BJ_CompareBad: mov BJ_CompareError,BJ_Code mov -2(R1),BJ_Expected mov -2(R2),BJ_Actual BJ_CompareDone: mov #MON_FONT_PAGE,@#WIN130 mov #VRAM_PAGE,@#WIN120 rts PC BJ_GetByte: cmp R3,BJ_Len bhis BJ_EmptyGlyph mov BJ_Path,R2 add R3,R2 movb (R2),R0 bic #177400,R0 mov BJ_Line,R1 jsr PC,UI_ROMGlyphByte rts PC BJ_EmptyGlyph: clr R0 rts PC BJ_RestoreA: mov #4,BJ_Stage mov #020440,BJ_W1 mov BJ_BackLow,BJ_W2 mov BJ_RectLow,BJ_W3 mov #11,BJ_W4 jsr PC,BJ_RunDMA tst BJ_Code bne BJ_RestoreFail mov #VRAM_PAGE,BJ_DrawBase jsr PC,BJ_VerifyBackup tst BJ_Code bne BJ_RestoreFail mov #1,BJ_AIsClean rts PC BJ_RestoreFail:mov #9.,BJ_Code rts PC BJ_RunDMA: tst @#BL_REG beq BJ_WritePacket mov #11.,BJ_Code rts PC BJ_WritePacket: mov #2056,@#WIN120 mov BJ_W1,@#120000 mov BJ_W2,@#120002 mov BJ_W3,@#120004 mov BJ_W4,@#120006 tst BJ_FullDMA bne BJ_DMAFullSize tst BJ_CustomDMA beq BJ_DMANormal mov BJ_CustomW5,@#120010 mov BJ_CustomW6,@#120012 br BJ_DMASizeDone BJ_DMANormal: mov #05033,@#120010 ; 10 scanlines x 28 words (56 bytes) mov #5,@#120012 ; 32-(28-1) = 5 words stride br BJ_DMASizeDone BJ_DMAFullSize: mov #040037,@#120010 mov #1,@#120012 BJ_DMASizeDone: clr @#120014 clr @#120016 mov #2056,@#BL_PACKET_REG mov #40001,@#BL_REG bis #10000,@#BL_REG mov #1000.,R2 BJ_DmaDelay: sob R2,BJ_DmaDelay mov #60000.,R2 BJ_DmaBusy: bit #100000,@#BL_REG beq BJ_DmaIdle sob R2,BJ_DmaBusy mov #4,BJ_Code clr @#BL_REG mov #60000.,R2 BJ_DmaAbort: bit #100000,@#BL_REG beq BJ_DmaDone sob R2,BJ_DmaAbort mov #1,BL_Unstopped rts PC BJ_DmaIdle: mov #1000.,R2 BJ_DmaSettle: sob R2,BJ_DmaSettle mov @#BL_REG,BJ_DmaStatus bit #100000,BJ_DmaStatus beq BJ_DmaStop mov #4,BJ_Code BJ_DmaStop: clr @#BL_REG inc BJ_DmaCount BJ_DmaDone: rts PC BJ_InstallIRQ: mov @#SYSCTRL,BH_OldSYS bic #10,@#SYSCTRL mov @#100,BH_OldPC mov @#102,BH_OldPSW clr BH_FlipCount clr BH_FrameTicks clr BH_Pending mov #VRAM_PAGE,BH_NewBase mov #BH_ISR,@#100 mov #340,@#102 mov #1,BJ_IrqOn bic #4,@#SYSCTRL bis #10,@#SYSCTRL rts PC BJ_RemoveIRQ: tst BJ_IrqOn beq BJ_NoIRQ bic #10,@#SYSCTRL mov #VRAM_PAGE,@#VIDBASE_REG mov BH_OldPC,@#100 mov BH_OldPSW,@#102 mov BH_OldSYS,@#SYSCTRL clr BH_Pending clr BJ_IrqOn BJ_NoIRQ: rts PC ; ======================================================================== ; AZMNT_08 r12: HELP uses existing 48x25 browser DMA save/restore geometry ; and backup pages 2050..2052, only when browser is closed. No AZCSR. ; The single main-screen focus row remains highlighted under the overlay. ; ======================================================================== HL_Show: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) clr HL_Page clr BR_Restore mov MarqueeDone,HL_OldMarquee mov #1,MarqueeDone jsr PC,CLK_Stop jsr PC,KEY_FlushReleased mov @#BL_PACKET_REG,HL_OldPacket mov BJ_CustomDMA,HL_OldCustom ; Full popup requires the canonical framebuffer page. cmp @#VIDBASE_REG,#VRAM_PAGE bne HL_FailNoSave mov #1,BJ_CustomDMA clr BJ_FullDMA clr BJ_Code jsr PC,BR_SaveRestore tst R0 bne HL_FailNoSave HL_DrawNow: jsr PC,HL_Paint tst R0 bne HL_CloseSaved jsr PC,KEY_FlushReleased HL_KeyLoop: jsr PC,KEY_ReadOne cmp R0,#K_ESC beq HL_CloseSaved cmp R0,#K_ENTER beq HL_CloseSaved cmp R0,#K_RIGHT beq HL_Next cmp R0,#K_LEFT bne HL_KeyLoop tst HL_Page beq HL_KeyLoop clr HL_Page br HL_DrawNow HL_Next: tst HL_Page bne HL_KeyLoop mov #1,HL_Page br HL_DrawNow HL_CloseSaved: mov #1,BR_Restore mov #1,BJ_CustomDMA clr BJ_FullDMA clr BJ_Code jsr PC,BR_SaveRestore tst R0 beq HL_CleanUp ; Recover the normal screen only on a verified DMA fault. jsr PC,BJ_QuiesceDMA jsr PC,UI_RenderAll jsr PC,UI_DrawFocus jsr PC,UI_DrawStatus br HL_CleanUp HL_FailNoSave: mov #StrHLFailure,R3 jsr PC,UI_StatusText HL_CleanUp: jsr PC,BJ_QuiesceDMA mov HL_OldPacket,@#BL_PACKET_REG mov HL_OldCustom,BJ_CustomDMA mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov HL_OldMarquee,MarqueeDone clr HeldArrow clr PendingCommand jsr PC,KEY_FlushReleased jsr PC,CLK_Start mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC HL_Paint: jsr PC,BR_ClearWindowDMA tst R0 bne HL_PaintEnd jsr PC,BR_Frame mov #10.,UX mov #8.,UY mov #StrHLTitle,R3 jsr PC,BR_PrintClipped mov #10.,UX mov #9.,UY tst HL_Page bne HL_P2Title mov #StrHLP1Title,R3 br HL_DrawTitle HL_P2Title: mov #StrHLP2Title,R3 HL_DrawTitle: jsr PC,BR_PrintClipped mov #HL_P1Lines,R5 tst HL_Page beq HL_DrawRows mov #HL_P2Lines,R5 HL_DrawRows: mov #11.,R4 HL_RowLoop: mov #10.,UX mov R4,UY mov (R5)+,R3 jsr PC,BR_PrintClipped inc R4 cmp R4,#29. blo HL_RowLoop mov #10.,UX mov #30.,UY mov #StrHLFooter,R3 jsr PC,BR_PrintClipped clr R0 HL_PaintEnd: rts PC ; ======================================================================== ; AZMNT_04 r01: LOCAL MicroSD directory BROWSER (VIEW/SELECT PREVIEW). ; 0:/DISKS/ by default; if missing, attempts 0:/; no writes to mapping. ; API command 016 sends an even-padded NUL terminated path, 003 OPEN, ; 013 NEXT, 015 consumes 11 words (FILINFO: size4/date2/time2/attr1/name13). ; 18 visible rows; sliding 64-entry BK cache. Only cache misses rescan. ; ======================================================================== BR_Run: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) clr BR_HasSelection clr BR_Backed clr BR_Restore clr BR_Banner clr BR_Error clr BR_RootFallback clr BR_PathMode clr BR_BothEmpty clr BR_FailStage clr BR_VerifyLine clr BR_VerifyWord clr BR_VerifySaved clr BR_VerifyScreen clr BR_DmaCode clr BR_BlRegister clr BR_DmaStatus clr BR_ScrollFault clr BR_CacheStart clr BR_TraceActive clr BR_Stage clr BR_FirstError clr BR_FirstStage clr BR_Retries clr BR_WaitCalls clr BR_WaitMax clr BR_WaitBlocks clr BR_WaitTimeouts mov MarqueeDone,BR_OldMarquee mov #1,MarqueeDone jsr PC,CLK_Stop jsr PC,KEY_FlushReleased mov @#BL_PACKET_REG,BR_OldPacket cmp @#VIDBASE_REG,#VRAM_PAGE beq BR_PageOK mov #10.,BR_Error jmp BR_NoPopup BR_PageOK: mov #1,BJ_CustomDMA clr BJ_FullDMA clr BJ_Code jsr PC,BR_SaveRestore ; BR_Restore=0: SAVE only tst R0 beq BR_BackupOK ; One bounded warm retry on first SAVE, no VRAM writes. ; First-use DMA startup can be slower than subsequent calls. jsr PC,BJ_QuiesceDMA mov #1,BJ_CustomDMA clr BJ_FullDMA clr BJ_Code jsr PC,BR_SaveRestore tst R0 beq BR_BackupOK mov #11.,BR_Error jmp BR_NoPopup BR_BackupOK: mov #1,BR_Backed mov #BR_StartPath,R3 mov #BR_Path,R4 BR_InitialCopy: movb (R3)+,(R4)+ bne BR_InitialCopy ; Previous browse may have left a longer pathname. ; Clear the FULL trailing zero WORD for CMD016. clrb @#BR_Path+10. clrb @#BR_Path+11. clrb @#BR_Path+12. mov #9.,BR_PathLen clr BR_Cursor clr BR_Top ; Live stage trace only in explicitly requested debug mode. mov DebugMode,BR_TraceActive ; Loading/stage overlay is a DEBUG-only feature. ; In normal mode leave saved video untouched until BR_Paint. tst BR_TraceActive beq BR_NoLoadingPopup jsr PC,BR_DrawLoading BR_NoLoadingPopup: jsr PC,BR_LoadDir tst R0 beq BR_Display ; Only an OPEN failure permits fallback; a broken NEXT ; stream must be reported rather than hidden. cmp BR_ErrorStage,#1 beq BR_TryRoot br BR_Display BR_TryRoot: inc BR_Retries tst BR_FirstError bne BR_RootSavedFirst mov BR_Error,BR_FirstError mov BR_Stage,BR_FirstStage BR_RootSavedFirst: mov #1,BR_RootFallback mov #3.,BR_PathLen clrb @#BR_Path+3 clrb @#BR_Path+4 clrb @#BR_Path+5 clr BR_Cursor clr BR_Top jsr PC,BR_LoadDir BR_Display: mov #6.,R0 mov #StrBRStagePaint,R3 jsr PC,BR_TracePhase jsr PC,BR_Paint tst DebugMode beq BR_InitNoDebug jsr PC,BR_ShowInitDiag BR_InitNoDebug: clr BR_TraceActive clr HeldArrow clr PendingCommand jsr PC,KEY_FlushReleased jsr PC,CLK_Start BR_KeyLoop: jsr PC,KEY_Poll tst R0 beq BR_KeyLoop cmp R0,#K_DEBUG bne BR_KeyNotStep jsr PC,APP_ToggleDebug jsr PC,BR_RefreshDebugFooter jmp BR_KeyLoop BR_KeyNotStep: cmp R0,#K_ESC bne BR_KeyNotEsc jmp BR_Close BR_KeyNotEsc: ; On a failed directory scan the cursor/cache is not ; trustworthy. KT and DEBUG are still handled above; ; never rescan or activate a partial listing here. tst BR_Error beq BR_KeyAllowed jmp BR_KeyLoop BR_KeyAllowed: cmp R0,#K_LEFT beq BR_PageUpKey cmp R0,#K_RIGHT beq BR_PageDownKey cmp R0,#K_UP beq BR_GoUp cmp R0,#K_DOWN beq BR_GoDown cmp R0,#K_ENTER beq BR_JumpActivate br BR_KeyLoop BR_JumpActivate: jmp BR_Activate BR_GoUp: tst BR_Cursor beq BR_KeyLoop jsr PC,BR_HideCursor dec BR_Cursor br BR_Reposition BR_GoDown: mov BR_Cursor,R1 inc R1 cmp R1,BR_Count bhis BR_KeyLoop jsr PC,BR_HideCursor inc BR_Cursor BR_Reposition: mov BR_Cursor,R1 cmp R1,BR_Top bhis BR_TestLast mov R1,BR_Top mov #1,BR_ScrollDir br BR_ScrollOne BR_TestLast: mov BR_Top,R2 add #BR_ROWS,R2 cmp R1,R2 blo BR_SameWindow inc BR_Top clr BR_ScrollDir BR_ScrollOne: jsr PC,BR_EnsureCache tst R0 bne BR_RescanError tst BR_ScrollFault bne BR_RescanFallback jsr PC,BR_ScrollDMA tst R0 bne BR_RescanFallback tst BR_ScrollDir beq BR_ScrollDownEdge mov #11.,R0 clr R1 br BR_PaintNewEdge BR_ScrollDownEdge: mov #28.,R0 mov #17.,R1 BR_PaintNewEdge: jsr PC,BR_DrawEdgeRow jsr PC,BR_ShowCursor jmp BR_KeyLoop BR_RescanFallback: jsr PC,BR_PaintListOnly tst BR_ScrollFault beq BR_RescanFallbackDone mov #10.,UX mov #30.,UY mov #StrBRScrollFault,R3 jsr PC,BR_PrintClipped BR_RescanFallbackDone: jmp BR_KeyLoop BR_RescanError: jsr PC,BR_Paint jmp BR_KeyLoop BR_SameWindow: jsr PC,BR_ShowCursor jmp BR_KeyLoop ; Page jumps move by BR_ROWS (18) and redraw only list interior; ; a page jump isn't a one-row DMA operation. '..' is parent navigation. BR_PageUpKey: tst BR_Cursor beq BR_PageNoop jsr PC,BR_HideCursor mov BR_Cursor,R0 sub #BR_ROWS,R0 bcc BR_PageUpOK clr R0 BR_PageUpOK: mov R0,BR_Cursor br BR_PagePosition BR_PageDownKey: mov BR_Count,R1 beq BR_PageNoop dec R1 cmp BR_Cursor,R1 bhis BR_PageNoop jsr PC,BR_HideCursor mov BR_Cursor,R0 add #BR_ROWS,R0 cmp R0,R1 blos BR_PageDownOK mov R1,R0 BR_PageDownOK: mov R0,BR_Cursor BR_PagePosition: ; Clamp BR_Top to [0, max(count-18,0)], with cursor visible. mov BR_Cursor,R0 mov BR_Count,R1 sub #BR_ROWS,R1 bcc BR_PageTopCap clr R1 BR_PageTopCap: cmp R0,R1 blos BR_PageTopOK mov R1,R0 BR_PageTopOK: mov R0,BR_Top jsr PC,BR_EnsureCache tst R0 bne BR_PageReadError jsr PC,BR_PaintListOnly jmp BR_KeyLoop BR_PageReadError: jsr PC,BR_Paint jmp BR_KeyLoop BR_PageNoop: jmp BR_KeyLoop BR_Activate: tst BR_Error beq BR_ActAllowed jmp BR_KeyLoop BR_ActAllowed: mov BR_Cursor,R0 sub BR_CacheStart,R0 cmp R0,BR_Cached blo BR_ActivateCached jmp BR_KeyLoop BR_ActivateCached: ; Virtual '..' record at index 0 in nonroot directories. cmp BR_PathLen,#3. blos BR_ActivateReal tst BR_Cursor bne BR_ActivateReal jsr PC,BR_Parent jsr PC,BR_LoadDir jsr PC,BR_Paint jmp BR_KeyLoop BR_ActivateReal:jsr PC,BR_EntryPtr movb 8.(R2),R0 bit #20,R0 beq BR_File jsr PC,BR_EnterDir jsr PC,BR_Paint jmp BR_KeyLoop BR_File: jsr PC,BR_ChooseFile tst R0 bne BR_ChooseError br BR_Close BR_ChooseError: jsr PC,BR_Paint jmp BR_KeyLoop BR_Close: jsr PC,CLK_Stop tst BR_Backed beq BR_NoPopup mov #1,BR_Restore jsr PC,BR_SaveRestore tst R0 beq BR_NoPopup mov #12.,BR_Error ; Last resort after DMA fault: reconstruct the full UI. jsr PC,BJ_QuiesceDMA jsr PC,UI_RenderAll jsr PC,UI_DrawFocus jsr PC,UI_DrawStatus BR_NoPopup: jsr PC,BJ_QuiesceDMA clr BJ_CustomDMA mov BR_OldPacket,@#BL_PACKET_REG mov #MON_FONT_PAGE,@#WIN130 mov #VRAM_PAGE,@#WIN120 clr HeldArrow clr PendingCommand jsr PC,KEY_FlushReleased mov BR_OldMarquee,MarqueeDone jsr PC,CLK_Start mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Two SAVE042 / COPY011 packets. Source field points to 2050..2052 ; and dest field to the 2000..2005 framebuffer A. Source is 32-word ; aligned, incl at the 192-line boundary (4608 words). BR_SaveRestore: mov #1.,BR_FailStage ; SAVE packet 1 mov #020440,BJ_W1 mov #BR_BACK1_LOW,BJ_W2 mov #BR_SCREEN1_LOW,BJ_W3 mov #BR_PAGE1_W5,BJ_CustomW5 mov #BR_WIDTH_STEP,BJ_CustomW6 mov #42,BJ_W4 tst BR_Restore beq BR_DMAPacket1 mov #4.,BR_FailStage ; RESTORE packet 1 mov #11,BJ_W4 BR_DMAPacket1: jsr PC,BJ_RunDMA tst BJ_Code bne BR_DMAFail mov #2.,BR_FailStage ; SAVE packet 2 tst BR_Restore beq BR_Packet2Set mov #5.,BR_FailStage ; RESTORE packet 2 BR_Packet2Set: mov #BR_BACK2_LOW,BJ_W2 mov #BR_SCREEN2_LOW,BJ_W3 mov #BR_PAGE2_W5,BJ_CustomW5 jsr PC,BJ_RunDMA tst BJ_Code bne BR_DMAFail mov #3.,BR_FailStage ; VERIFY SAVE tst BR_Restore beq BR_VerifyNow mov #6.,BR_FailStage ; VERIFY RESTORE BR_VerifyNow: jsr PC,BR_VerifyCopy tst R0 bne BR_DMAFail clr R0 rts PC BR_DMAFail: mov BJ_Code,BR_DmaCode mov BJ_DmaStatus,BR_DmaStatus mov @#BL_REG,BR_BlRegister mov #1,R0 rts PC ; Verifies all 6000 transferred 16-bit words. Backup crosses a page ; mid-scanline, so test each WORD for a rollover, not each scanline. BR_VerifyCopy: clr BR_VerifyLine clr BR_VerifyWord mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov #BR_BACKUP_PAGE,R5 mov R5,@#WIN120 mov #2001,@#WIN130 mov #120000,R1 mov #130610,R2 ; y=70, x=8 bytes mov #250.,R3 BR_CompareLine: mov #24.,R4 BR_CompareWord: cmp (R1)+,(R2)+ bne BR_CompareBad inc BR_VerifyWord cmp R1,#130000 blo BR_BackPageOK inc R5 mov R5,@#WIN120 mov #120000,R1 BR_BackPageOK: sob R4,BR_CompareWord add #20,R2 ; 16-byte gap: screen pitch 64, popup 48 cmp R2,#140000 blo BR_ScreenPageOK mov @#WIN130,R0 inc R0 mov R0,@#WIN130 mov #130010,R2 BR_ScreenPageOK:clr BR_VerifyWord inc BR_VerifyLine sob R3,BR_CompareLine clr R0 br BR_CompareEnd BR_CompareBad: mov -2(R1),BR_VerifySaved mov -2(R2),BR_VerifyScreen mov #1,R0 BR_CompareEnd: mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Only called after the modal is CLOSED and video window is restored. ; All diagnostic fields fit the existing 64-column status line. ; S=1/2 SAVE DMA, 3 verify SAVE, 4/5 RESTORE DMA, 6 verify RESTORE. ; J=BJ_Code; for verify errors L/W are zero-based line/word offsets. ; P=backed-up pixel WORD, V=video pixel WORD (six-digit octal). ; On DMA errors Q=BL_REG, T=last sampled DMA status (six-digit octal). BR_PrintDmaDiag: mov #StrBRDiagStage,R3 jsr PC,UI_PrintString mov BR_FailStage,R1 jsr PC,UI_PrintDec2 mov #StrBRDiagCode,R3 jsr PC,UI_PrintString mov BR_DmaCode,R1 jsr PC,UI_PrintDec2 cmp BR_FailStage,#3. beq BR_PrintMismatch cmp BR_FailStage,#6. beq BR_PrintMismatch mov #StrBRDiagRegister,R3 jsr PC,UI_PrintString mov BR_BlRegister,R1 jsr PC,UI_PrintOct6 mov #StrBRDiagLast,R3 jsr PC,UI_PrintString mov BR_DmaStatus,R1 jsr PC,UI_PrintOct6 rts PC BR_PrintMismatch: mov #StrBRDiagLine,R3 jsr PC,UI_PrintString mov BR_VerifyLine,R1 jsr PC,UI_PrintDec3 mov #StrBRDiagWord,R3 jsr PC,UI_PrintString mov BR_VerifyWord,R1 jsr PC,UI_PrintDec2 mov #StrBRDiagBackup,R3 jsr PC,UI_PrintString mov BR_VerifySaved,R1 jsr PC,UI_PrintOct6 mov #StrBRDiagVideo,R3 jsr PC,UI_PrintString mov BR_VerifyScreen,R1 jsr PC,UI_PrintOct6 rts PC ; r07 diagnostic experiment: first OPEN with final '/' OMITTED for ; non-root directories; on error or virtual '..' only, retry with '/'. ; The visible path buffer is preserved. Root '0:/' is NEVER trimmed. ; BR_PathMode=1: wire no slash; BR_PathMode=0: original wire path. ; Both forms are read-only. BR_LoadDir: clr BR_CacheStart mov #1,BR_PathMode ; first OPEN: no trailing '/' (wire only) clr BR_BothEmpty jsr PC,BR_Enumerate cmp BR_PathLen,#3. blos BR_LoadDone ; Probe WITH-slash form if either OPEN/NEXT failed OR ; enumeration produced only the virtual parent row. tst R0 bne BR_TryWithSlash cmp BR_Count,#1 ; only synthetic '..' bne BR_LoadDone BR_TryWithSlash: inc BR_Retries tst BR_FirstError bne BR_SlashSavedFirst mov BR_Error,BR_FirstError mov BR_Stage,BR_FirstStage BR_SlashSavedFirst: clr BR_PathMode ; fallback: original path WITH trailing '/' jsr PC,BR_Enumerate tst R0 beq BR_LoadAltOK ; Alternate form also failed: leave its actual error code ; and stage visible. The first attempt did not provide a ; reliable listing; never silently call it an empty dir. br BR_LoadDone BR_LoadAltOK: cmp BR_Count,#1 bne BR_LoadDone mov #1,BR_BothEmpty BR_LoadDone: rts PC ; Directory iterator. No live map writes. Reopen for each new window. ; Error codes 3=timeout, 4=CSR status, 8=invalid entry/path, ; 9=too many entries. Status is shown inside popup. BR_Enumerate: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) clr BR_Count clr BR_Cached clr BR_Error ; A synthetic '..' item is always index 0 when not root. cmp BR_PathLen,#3. blos BR_NoParentSlot mov #1,BR_Count tst BR_CacheStart bne BR_NoParentSlot mov #BR_Entries,R2 mov #11.,R3 BR_ClearParent: clr (R2)+ sob R3,BR_ClearParent movb #20,@#BR_Entries+8. movb #'.,@#BR_Entries+9. movb #'.,@#BR_Entries+10. mov #1,BR_Cached BR_NoParentSlot:mov #1,BR_ErrorStage mov #2.,R0 mov #StrBRStageReset,R3 jsr PC,BR_TracePhase jsr PC,API_Reset tst R0 beq BR_EnumPath jmp BR_EnumError BR_EnumPath: ; 016 WORD stream, word NUL is mandatory for termination. mov #16,@#AZCSR mov #BR_Path,R2 mov BR_PathLen,R3 ; For mode=1, suppress the final slash in the transmitted ; string only; always restore the UI path afterward. tst BR_PathMode beq BR_PathBytesOK cmp R3,#3. blos BR_PathBytesOK dec R3 mov R2,R4 add R3,R4 clrb (R4) BR_PathBytesOK: mov R3,R5 add #3,R3 bic #1,R3 asr R3 BR_SendPath: mov (R2)+,@#AZDR sob R3,BR_SendPath ; Restore slash before any asynchronous controller wait. tst BR_PathMode beq BR_PathSent cmp BR_PathLen,#3. blos BR_PathSent movb #'/,(R4) BR_PathSent: mov #3.,R0 mov #StrBRStageOpen,R3 jsr PC,BR_TracePhase mov #3,@#AZCSR jsr PC,BR_WaitReady tst R0 bne BR_EnumError mov @#AZCSR,BR_LastCSR bit #100000,BR_LastCSR beq BR_InitialReset mov #4,R0 br BR_EnumError BR_InitialReset: mov #2,BR_ErrorStage mov #4.,R0 mov #StrBRStagePost,R3 jsr PC,BR_TracePhase ; AZDIR.MAC resets once AFTER OPEN, not every NEXT. jsr PC,API_Reset tst R0 bne BR_EnumError mov #5.,R0 mov #StrBRStageNext,R3 jsr PC,BR_TracePhase BR_ReadNext: mov #13,@#AZCSR jsr PC,BR_WaitReady tst R0 bne BR_EnumError mov @#AZCSR,BR_LastCSR bit #100000,BR_LastCSR beq BR_FetchEntry mov #4,R0 br BR_EnumError BR_FetchEntry: mov #15,@#AZCSR mov #BR_Record,R2 mov #11.,R3 BR_FetchWord: mov @#AZDR,(R2)+ sob R3,BR_FetchWord tstb BR_Record+9. beq BR_EnumDone jsr PC,BR_ValidateName tst R0 bne BR_EnumError ; Skip system volume label and native dot entries. bitb #10,BR_Record+8. bne BR_ReadNext cmpb BR_Record+9.,#'. bne BR_StoreEntry cmpb BR_Record+10.,#0 beq BR_ReadNext cmpb BR_Record+10.,#'. bne BR_StoreEntry tstb BR_Record+11. beq BR_ReadNext BR_StoreEntry: cmp BR_Count,#BR_MAX_ENTRIES bhis BR_EnumTooMany mov BR_Count,R0 cmp R0,BR_CacheStart blo BR_IncrCount sub BR_CacheStart,R0 cmp R0,#BR_CACHE_SIZE bhis BR_IncrCount jsr PC,BR_EntryPtr mov #BR_Record,R3 mov #11.,R4 BR_CopyEntry: mov (R3)+,(R2)+ sob R4,BR_CopyEntry inc BR_Cached BR_IncrCount: inc BR_Count br BR_ReadNext BR_EnumTooMany:mov #9.,R0 br BR_EnumError BR_EnumDone: clr R0 BR_EnumError: mov R0,BR_Error mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; SD directory commands may take longer than API027: nested bound. BR_WaitReady: mov R1,-(SP) mov R2,-(SP) inc BR_WaitCalls clr BR_WaitBlocks mov #40.,R2 BR_WaitOuter: inc BR_WaitBlocks mov #60000.,R1 BR_WaitInner: bit #200,@#AZCSR bne BR_WaitOK sob R1,BR_WaitInner sob R2,BR_WaitOuter inc BR_WaitTimeouts mov #3,R0 br BR_WaitReturn BR_WaitOK: clr R0 BR_WaitReturn: cmp BR_WaitBlocks,BR_WaitMax blos BR_WaitMaxDone mov BR_WaitBlocks,BR_WaitMax BR_WaitMaxDone: mov (SP)+,R2 mov (SP)+,R1 rts PC ; Scan 13-byte 8.3 payload. Reject non-terminated and '/' separators; ; unlike a host filesystem we do NOT normalize case. BR_ValidateName: mov #BR_Record+9.,R3 mov #13.,R4 BR_NameByte: movb (R3)+,R0 beq BR_NameOK cmpb R0,#'/ beq BR_NameBad cmpb R0,#134 ; backslash octal beq BR_NameBad cmpb R0,#40 blo BR_NameBad sob R4,BR_NameByte BR_NameBad: mov #8.,R0 rts PC BR_NameOK: clr R0 rts PC ; R0=0..17 -> pointer to 22-byte cached record in BK memory. BR_EntryPtr: mov R0,R1 asl R0 asl R0 mov R0,R2 ; 4*n asl R0 asl R0 ; 16*n add R2,R0 ; 20*n asl R1 add R1,R0 ; 22*n (no MUL on BK-0010) mov #BR_Entries,R2 add R0,R2 rts PC ; Parent always ends in '/', never escape MicroSD root "0:/". BR_Parent: mov BR_PathLen,R1 dec R1 dec R1 BR_ParentSeek: cmp R1,#2. blos BR_ParentRoot mov #BR_Path,R2 add R1,R2 cmpb (R2),#'/ beq BR_ParentFound dec R1 br BR_ParentSeek BR_ParentRoot: mov #2.,R1 BR_ParentFound: inc R1 mov R1,BR_PathLen mov #BR_Path,R2 add R1,R2 clrb (R2) clrb 1(R2) clrb 2(R2) clrb 3(R2) clr BR_Cursor clr BR_Top rts PC ; Directory record in R2. Append name + '/' atomically after check. BR_EnterDir: jsr PC,BR_GetNameLen mov BR_PathLen,R4 add R1,R4 inc R4 ; The old code allowed 255 bytes, but appends four ; NUL bytes after the slash and could corrupt the next ; WIN170 buffer. Require newLen+3 <= 255. cmp R4,#252. bhi BR_PathTooLong mov BR_PathLen,BR_OldPathLen mov #BR_Path,R3 add BR_OldPathLen,R3 add #9.,R2 BR_AppendName: movb (R2)+,(R3)+ dec R1 bne BR_AppendName movb #'/,(R3)+ clrb (R3) clrb 1(R3) clrb 2(R3) clrb 3(R3) mov R4,BR_PathLen clr BR_Top clr BR_Cursor jsr PC,BR_LoadDir tst R0 beq BR_DirDone ; Keep the failed child path/error visible. KT/LEFT ; still works and takes the user to the parent. br BR_DirDone BR_PathTooLong: mov #8.,BR_Banner BR_DirDone: rts PC BR_ChooseFile: jsr PC,BR_GetNameLen mov BR_PathLen,R4 add R1,R4 cmp R4,#255. bhi BR_ChoiceTooLong mov #BR_Path,R3 mov #BR_SelectedPath,R5 mov BR_PathLen,R0 BR_CopyBase: movb (R3)+,(R5)+ dec R0 bne BR_CopyBase add #9.,R2 BR_CopyFilename:movb (R2)+,(R5)+ dec R1 bne BR_CopyFilename clrb (R5) mov R4,BR_SelectedLen mov #1,BR_HasSelection clr R0 rts PC BR_ChoiceTooLong: mov #8.,BR_Banner mov #8.,R0 rts PC BR_GetNameLen: mov #0,R1 mov R2,R3 add #9.,R3 BR_LengthLoop: tstb (R3)+ beq BR_LengthDone inc R1 cmp R1,#12. blos BR_LengthLoop BR_LengthDone: rts PC ; Uses the same proven 192+58 geometry as BR_SaveRestore. ; CMD000 must not touch any pixel outside x8..55 / y7..31. BR_ClearWindowDMA: mov #1,BJ_CustomDMA clr BJ_Code clr BJ_FullDMA mov #020440,BJ_W1 clr BJ_W2 ; SRC unused by FILL mov #BR_SCREEN1_LOW,BJ_W3 clr BJ_W4 ; 000 FILL (packet W8 is zero) mov #BR_PAGE1_W5,BJ_CustomW5 mov #BR_WIDTH_STEP,BJ_CustomW6 jsr PC,BJ_RunDMA tst BJ_Code bne BR_FillError mov #BR_SCREEN2_LOW,BJ_W3 mov #BR_PAGE2_W5,BJ_CustomW5 jsr PC,BJ_RunDMA tst BJ_Code bne BR_FillError mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 clr R0 rts PC BR_FillError: mov #1,R0 rts PC ; First-open feedback: the directory command can take time before any ; file row is ready. SAVE042 was completed prior to drawing this frame. BR_DrawLoading: mov R1,-(SP) mov R3,-(SP) jsr PC,BR_ClearWindowDMA tst R0 bne BR_LoadingDone jsr PC,BR_Frame mov #12.,UY mov #10.,UX mov #StrBRLoading,R3 jsr PC,BR_PrintClipped BR_LoadingDone: mov (SP)+,R3 mov (SP)+,R1 rts PC ; Diagnostic stage marker; draw only during the first initial listing. ; R0=stage number, R3=pre-padded text. Preserve all data registers, ; cursor UX/UY, and the state visible to the controller command sender. BR_TracePhase: tst BR_TraceActive beq BR_TraceReturn mov R0,BR_Stage mov R0,-(SP) mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov UX,-(SP) mov UY,-(SP) mov #12.,UY mov #10.,UX jsr PC,BR_PrintClipped mov (SP)+,UY mov (SP)+,UX mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 mov (SP)+,R0 BR_TraceReturn: rts PC ; At first-open completion replaces help row y30 with read-only telemetry. ; R=retries; W=maximum wait-loop outer iterations; E=first error; ; S=stage of first error; T=timeout count. No extra SD commands. ; Update only browser footer y30 when IND SU is pressed in the popup. ; No window recreation, no additional SD commands. BR_RefreshDebugFooter: mov R0,-(SP) mov R1,-(SP) mov R3,-(SP) mov UX,-(SP) mov UY,-(SP) mov #30.,UY mov #10.,UX mov #StrBRDebugClear,R3 jsr PC,BR_PrintClipped tst DebugMode beq BR_RefreshNormal jsr PC,BR_ShowInitDiag br BR_RefreshDone BR_RefreshNormal: mov #30.,UY mov #10.,UX mov #StrBRHelp,R3 jsr PC,BR_PrintClipped BR_RefreshDone: mov (SP)+,UY mov (SP)+,UX mov (SP)+,R3 mov (SP)+,R1 mov (SP)+,R0 rts PC BR_ShowInitDiag: mov R0,-(SP) mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov UX,-(SP) mov UY,-(SP) mov #30.,UY mov #10.,UX mov #StrBRDiagR,R3 jsr PC,BR_PrintClipped mov BR_Retries,R1 jsr PC,UI_PrintDec5 mov #StrBRDiagW,R3 jsr PC,BR_PrintClipped mov BR_WaitMax,R1 jsr PC,UI_PrintDec5 mov #StrBRDiagE,R3 jsr PC,BR_PrintClipped mov BR_FirstError,R1 jsr PC,UI_PrintDec5 mov #StrBRDiagS,R3 jsr PC,BR_PrintClipped mov BR_FirstStage,R1 jsr PC,UI_PrintDec5 mov #StrBRDiagT,R3 jsr PC,BR_PrintClipped mov BR_WaitTimeouts,R1 jsr PC,UI_PrintDec5 mov (SP)+,UY mov (SP)+,UX mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 mov (SP)+,R0 rts PC BR_Paint: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) ; Zero ONLY the 48x25 popup rectangle via legacy DMA FILL. ; Old per-character space printing is kept solely as an ; emergency fallback if the FILL engine reports an error. jsr PC,BR_ClearWindowDMA tst R0 beq BR_ClearDone jsr PC,BJ_QuiesceDMA mov #BR_WIN_Y,R4 BR_ClearLine: mov R4,UY mov #BR_WIN_X,UX mov #48.,R5 BR_ClearChar: mov #40,R0 jsr PC,UI_PutChar sob R5,BR_ClearChar inc R4 cmp R4,#32. blo BR_ClearLine BR_ClearDone: jsr PC,BR_Frame mov #10.,UX mov #8.,UY mov #StrBRTitle,R3 jsr PC,BR_PrintClipped mov #41.,UX mov BR_Cursor,R1 tst BR_Count beq BR_CountZero inc R1 BR_CountZero: jsr PC,UI_PrintDec5 mov #'/,R0 jsr PC,UI_PutChar mov BR_Count,R1 jsr PC,UI_PrintDec5 mov #10.,UX mov #9.,UY jsr PC,BR_PrintPath mov #11.,R4 mov #BR_Entries,R5 clr BR_RowIndex BR_DrawList: mov BR_Top,R0 add BR_RowIndex,R0 cmp R0,BR_Count bhis BR_ListDone sub BR_CacheStart,R0 cmp R0,BR_Cached bhis BR_ListDone mov #10.,UX mov R4,UY mov BR_Top,R0 add BR_RowIndex,R0 sub BR_CacheStart,R0 jsr PC,BR_EntryPtr mov R2,R5 mov R2,R3 add #9.,R3 jsr PC,BR_PrintClipped jsr PC,BR_PrintMeta BR_FileShown: inc BR_RowIndex inc R4 cmp R4,#29. blo BR_DrawList BR_ListDone: tst BR_Error bne BR_ShowError tst BR_Count beq BR_DisplayEmpty cmp BR_PathLen,#3. blos BR_ShowHelp cmp BR_Count,#1 bne BR_ShowHelp mov #10.,UX mov #12.,UY mov #StrBREmpty,R3 jsr PC,BR_PrintClipped br BR_ShowHelp BR_DisplayEmpty:mov #10.,UX mov #11.,UY mov #StrBREmpty,R3 jsr PC,BR_PrintClipped BR_ShowHelp: mov #10.,UX mov #30.,UY mov #StrBRHelp,R3 jsr PC,BR_PrintClipped tst BR_BothEmpty beq BR_CheckFallback mov #10.,UX mov #30.,UY mov #StrBRUnconfirmed,R3 jsr PC,BR_PrintClipped BR_CheckFallback: tst BR_RootFallback beq BR_TestBanner mov #10.,UX mov #30.,UY mov #StrBRFallback,R3 jsr PC,BR_PrintClipped BR_TestBanner: tst BR_Banner beq BR_DrawHighlight mov #10.,UX mov #30.,UY mov #StrBRTooLong,R3 jsr PC,BR_PrintClipped clr BR_Banner br BR_DrawHighlight BR_ShowError: mov #10.,UX mov #11.,UY mov #StrBRBlocked,R3 jsr PC,BR_PrintClipped mov #10.,UX mov #30.,UY mov #StrBRError,R3 jsr PC,BR_PrintClipped mov BR_Error,R1 jsr PC,UI_PrintDec2 mov #StrBRDiagStage,R3 jsr PC,BR_PrintClipped mov BR_ErrorStage,R1 jsr PC,UI_PrintDec2 mov #StrBRDiagMode,R3 jsr PC,BR_PrintClipped mov BR_PathMode,R1 jsr PC,UI_PrintDec2 mov #StrBRDiagCSR,R3 jsr PC,BR_PrintClipped mov BR_LastCSR,R1 jsr PC,UI_PrintOct6 BR_DrawHighlight:tst BR_Error bne BR_PaintDone ; never highlight an untrusted listing tst BR_Cached beq BR_PaintDone mov BR_Cursor,R0 sub BR_Top,R0 cmp R0,BR_Cached bhis BR_PaintDone add #11.,R0 jsr PC,BR_InvertRow BR_PaintDone: mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Fast cursor path: no font repaint and no controller access for ; UP/DOWN while visible window has not crossed a boundary. BR_HideCursor: mov BR_Cursor,R0 sub BR_Top,R0 cmp R0,BR_Cached bhis BR_HideDone add #11.,R0 jsr PC,BR_InvertRow BR_HideDone: rts PC BR_ShowCursor: mov #41.,UX mov #8.,UY mov BR_Cursor,R1 tst BR_Count beq BR_CursorCounter inc R1 BR_CursorCounter:jsr PC,UI_PrintDec5 mov BR_Cursor,R0 sub BR_Top,R0 cmp R0,BR_Cached bhis BR_ShowDone add #11.,R0 jsr PC,BR_InvertRow BR_ShowDone: mov #VRAM_PAGE,@#WIN120 rts PC ; Repaint ONLY the interior 18-row directory list when it scrolls; ; preserve frame, title, path, divider, status and saved background. BR_PaintListOnly: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov #11.,R4 BR_ListClearY: mov R4,UY mov #9.,UX mov #46.,R5 BR_ListClearX: mov #40,R0 jsr PC,UI_PutChar sob R5,BR_ListClearX inc R4 cmp R4,#29. blo BR_ListClearY mov #11.,R4 clr BR_RowIndex BR_ScrollList: mov BR_Top,R0 add BR_RowIndex,R0 cmp R0,BR_Count bhis BR_ScrollDone sub BR_CacheStart,R0 cmp R0,BR_Cached bhis BR_ScrollDone mov #10.,UX mov R4,UY mov BR_Top,R0 add BR_RowIndex,R0 sub BR_CacheStart,R0 jsr PC,BR_EntryPtr mov R2,R5 mov R2,R3 add #9.,R3 jsr PC,BR_PrintClipped jsr PC,BR_PrintMeta BR_ScrollFile: inc BR_RowIndex inc R4 cmp R4,#29. blo BR_ScrollList BR_ScrollDone: jsr PC,BR_ShowCursor mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; A 64-record sliding cache. For <=64 entries all cursor movement is ; local. Beyond that, rescan in 32-record steps when the new viewport ; leaves the cache. Directory handles are not kept open between scans. BR_EnsureCache: mov BR_Top,R0 cmp R0,BR_CacheStart blo BR_Recache mov BR_Top,R0 add #17.,R0 cmp R0,BR_Count blo BR_ECacheValid mov BR_Count,R0 dec R0 BR_ECacheValid: sub BR_CacheStart,R0 cmp R0,BR_Cached blo BR_EnsureOK BR_Recache: ; Bias cache backward 16 entries; avoids frequent reload mov BR_Top,R0 cmp R0,#16. blo BR_StartZero sub #16.,R0 br BR_StartSet BR_StartZero: clr R0 BR_StartSet: mov R0,BR_CacheStart jsr PC,BR_Enumerate rts PC BR_EnsureOK: clr R0 rts PC ; Hardware-scroll one 10px row via a nonoverlapping AZ RAM scratch. ; Never DMA copy overlapping framebuffer SRC/DST in-place. ; 042 samples 170 scanlines at x10..53 into pages 2053..2054. ; 011 restores them shifted 10 scanlines. Then only the exposed edge ; is repainted; the frame, path and footer remain untouched. BR_ScrollDMA: clr BJ_Code mov #020440,BJ_W1 mov #BR_SCROLL_LOW,BJ_W2 mov #BR_SCROLL_W5,BJ_CustomW5 mov #BR_SCROLL_W6,BJ_CustomW6 mov #42,BJ_W4 tst BR_ScrollDir bne BR_SaveForDown mov #BR_SCROLL_UP_IN,BJ_W3 br BR_SaveScroll BR_SaveForDown:mov #BR_SCROLL_DN_IN,BJ_W3 BR_SaveScroll: jsr PC,BJ_RunDMA tst BJ_Code bne BR_ScrollFailed mov #11,BJ_W4 tst BR_ScrollDir bne BR_DrawForDown mov #BR_SCROLL_UP_OUT,BJ_W3 br BR_DrawScroll BR_DrawForDown:mov #BR_SCROLL_DN_OUT,BJ_W3 BR_DrawScroll: jsr PC,BJ_RunDMA tst BJ_Code bne BR_ScrollFailed clr R0 rts PC BR_ScrollFailed: mov #1,BR_ScrollFault jsr PC,BJ_QuiesceDMA mov #1,R0 rts PC BR_DrawEdgeRow: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov R0,R4 mov R1,R5 mov R4,UY mov #9.,UX mov #46.,R2 BR_EdgeBlank: mov #40,R0 jsr PC,UI_PutChar sob R2,BR_EdgeBlank mov BR_Top,R0 add R5,R0 cmp R0,BR_Count bhis BR_EdgeDone sub BR_CacheStart,R0 cmp R0,BR_Cached bhis BR_EdgeDone jsr PC,BR_EntryPtr mov R2,R5 mov R2,R3 add #9.,R3 mov #10.,UX mov R4,UY jsr PC,BR_PrintClipped jsr PC,BR_PrintMeta BR_EdgeDone: mov #VRAM_PAGE,@#WIN120 mov #MON_FONT_PAGE,@#WIN130 mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC ; Right column x44..53 (10 glyphs). FILINFO from AZDIR.MAC: ; fsize DWORD at bytes 0..3, fdate/ftime at 4..7, attribute byte 8, ; 13-byte NUL-terminated fname at byte 9. Never touch the SD card here. ; R5 points at the 22-byte cached record. 32-bit DECIMAL byte size, ; right aligned, with spaces instead of leading zeroes. No MUL/DIV. BR_PrintMeta: bitb #20,8.(R5) beq BR_MetaSize mov #49.,UX mov #StrBRDir,R3 jsr PC,BR_PrintClipped rts PC BR_MetaSize: mov R0,-(SP) mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R5,-(SP) mov (R5),R0 ; low 16 bits, little endian mov 2.(R5),R1 ; high 16 bits (unsigned) mov #BR_SizePowers,R2 clr R5 ; decimal character index 0..9 clr BR_SizeSeen BR_SizeNext: mov (R2)+,R4 ; power low word mov (R2)+,R3 ; power high word clr BR_SizeDigit BR_SizeSubtract:cmp R1,R3 bhi BR_SizeTake blo BR_SizeFinish cmp R0,R4 blo BR_SizeFinish BR_SizeTake: sub R4,R0 sbc R1 ; unsigned borrow from low word sub R3,R1 inc BR_SizeDigit br BR_SizeSubtract BR_SizeFinish: mov #BR_SizeText,R3 add R5,R3 mov BR_SizeDigit,R4 bne BR_SizePrint cmp R5,#9. beq BR_SizePrint ; the last digit prints zero tst BR_SizeSeen bne BR_SizePrint movb #40,(R3) ; leading space br BR_SizeAdvance BR_SizePrint: mov #1,BR_SizeSeen add #'0,R4 movb R4,(R3) BR_SizeAdvance: inc R5 cmp R5,#10. blo BR_SizeNext jsr PC,BR_GroupSize mov #41.,UX mov #BR_GroupedSize,R3 jsr PC,BR_PrintClipped mov (SP)+,R5 mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 mov (SP)+,R0 rts PC ; Format 10 decimal digits as 13 columns: 4'294'967'295. ; Spaces remain leading spaces; apostrophes appear only after printed ; groups. This routine changes no sizes and requires no extra SD access. BR_GroupSize: mov R0,-(SP) mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov #BR_GroupedSize,R2 mov #13.,R1 BR_GroupBlank: movb #40,(R2)+ sob R1,BR_GroupBlank movb #0,(R2) mov #BR_SizeText,R2 mov #BR_GroupOffsets,R1 mov #10.,R0 BR_GroupDigit: mov (R1)+,R3 add #BR_GroupedSize,R3 movb (R2)+,(R3) sob R0,BR_GroupDigit cmpb BR_SizeText,#40 beq BR_Group2 movb #47,BR_GroupedSize+1. BR_Group2: cmpb BR_SizeText+3.,#40 beq BR_Group3 movb #47,BR_GroupedSize+5. BR_Group3: cmpb BR_SizeText+6.,#40 beq BR_GroupDone movb #47,BR_GroupedSize+9. BR_GroupDone: mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 mov (SP)+,R0 rts PC ; text row R0, invert x9..54 (name + size), never touch frame. BR_InvertRow: mov R1,-(SP) mov R2,-(SP) mov R3,-(SP) mov R4,-(SP) mov R0,R4 mov R0,R1 asl R4 asl R4 add R1,R4 asl R4 mov #10.,R3 BR_InvertScan: mov R4,R0 jsr PC,UI_MapScanline add #9.,R2 mov #BR_MARK_WIDTH,R1 BR_InvertByte: comb (R2)+ sob R1,BR_InvertByte inc R4 sob R3,BR_InvertScan mov (SP)+,R4 mov (SP)+,R3 mov (SP)+,R2 mov (SP)+,R1 rts PC BR_Frame: mov #7.,UY mov #8.,UX mov #BOX_TL,R0 jsr PC,UI_PutChar mov #46.,R3 BR_FrameTop: mov #BOX_H,R0 jsr PC,UI_PutChar sob R3,BR_FrameTop mov #BOX_TR,R0 jsr PC,UI_PutChar mov #31.,UY mov #8.,UX mov #BOX_BL,R0 jsr PC,UI_PutChar mov #46.,R3 BR_FrameBottom: mov #BOX_H,R0 jsr PC,UI_PutChar sob R3,BR_FrameBottom mov #BOX_BR,R0 jsr PC,UI_PutChar mov #8.,R4 BR_FrameSides: mov R4,UY mov #8.,UX mov #BOX_V,R0 jsr PC,UI_PutChar mov #55.,UX mov #BOX_V,R0 jsr PC,UI_PutChar inc R4 cmp R4,#31. blo BR_FrameSides ; Dividing lines y=10,29; only 46 interior columns. mov #10.,UY jsr PC,BR_HRule mov #29.,UY jsr PC,BR_HRule rts PC BR_HRule: mov #9.,UX mov #46.,R3 BR_RuleChar: mov #BOX_H,R0 jsr PC,UI_PutChar sob R3,BR_RuleChar rts PC ; R3=zero-terminated string, clipped to column 54 (inside popup). BR_PrintClipped: mov R3,-(SP) BR_ClippedLoop: cmp UX,#55. bhis BR_ClippedEnd movb (R3)+,R0 beq BR_ClippedEnd jsr PC,UI_PutChar br BR_ClippedLoop BR_ClippedEnd: mov (SP)+,R3 rts PC BR_PrintPath: mov #BR_Path,R3 mov BR_PathLen,R1 cmp R1,#44. blos BR_PathShort mov #StrBREllipsis,R3 jsr PC,BR_PrintClipped mov BR_PathLen,R1 sub #41.,R1 mov #BR_Path,R3 add R1,R3 BR_PathShort: jsr PC,BR_PrintClipped rts PC ; Status report only: no mutation of WORK/controller on selection. BR_ReportFile: mov #StrBrowseSelect,R3 jsr PC,UI_StatusText mov #21.,UX mov #37.,UY mov #BR_SelectedPath,R3 jsr PC,UI_PrintString rts PC HW_Exit: tst BL_Unstopped beq HW_ExitAllowed clr @#BL_REG HW_AbortMustStop: bit #100000,@#BL_REG bne HW_AbortMustStop ; never return to ANDOS with running DMA clr BL_Unstopped HW_ExitAllowed: jsr PC,CLK_Stop tst HW_Saved beq HW_FinalExit mov (SP)+,@#SYSCTRL mov (SP)+,@#SYSCTRL716 ; from 177352 shadow: CORRECT mov (SP)+,@#WIN_DENY mov (SP)+,@#WIN_RO mov (SP)+,@#WIN_ENABLE mov (SP)+,@#102 mov (SP)+,@#100 mov (SP)+,@#WIN170 ; restore original ANDOS upper-window page mov (SP)+,@#WIN130 mov (SP)+,@#WIN120 mov (SP)+,@#HSCROLL mov (SP)+,@#VSCROLL mov (SP)+,@#VIDBASE_REG mov (SP)+,@#VIDMODE_REG clr HW_Saved tst OldKeyMask beq HW_KeyUnmask bis #100,@#KEYCSR br HW_FinalExit HW_KeyUnmask: bic #100,@#KEYCSR HW_FinalExit: jsr PC,NET_EnableIdle ; leave controller networking available to ANDOS ; r09: return pre-AZMNT vector exactly; then hand control to ANDOS. mov OldBusPC,@#4 mov OldBusPSW,@#6 jmp @#100000 ; Local BK state. Runtime-only (legacy BL diagnostics removed). .even NetReadyToUse: .word 0 ; 1 only after FPGA/STM32/video gate NetIdleOn: .word 0 ; CLR on every API_RESET, SET after CSR110 BL_Unstopped: .word 0 BH_Pending: .word 0 BH_NewBase: .word 0 BH_FrameTicks: .word 0 BH_FlipCount: .word 0 BH_WaitMode: .word 0 BH_OldSYS: .word 0 BH_OldPC: .word 0 BH_OldPSW: .word 0 BJ_Code: .word 0 BJ_Stage: .word 0 BJ_DmaCount: .word 0 BJ_DmaStatus: .word 0 BJ_ErrOffset: .word 0 BJ_Expected: .word 0 BJ_Actual: .word 0 BJ_HaveBackup: .word 0 BJ_AIsClean: .word 0 BJ_IrqOn: .word 0 BJ_OldPacket: .word 0 BJ_RectLow: .word 0 BJ_BackLow: .word 0 BJ_BackPage: .word 0 BJ_VisiblePage: .word 0 BJ_VisiblePtr: .word 0 BJ_ComparePage: .word 0 BJ_CompareError:.word 0 BJ_WorkPage: .word 0 BJ_Path: .word 0 BJ_Len: .word 0 BJ_Line: .word 0 BJ_Char: .word 0 BJ_Inverse: .word 0 BJ_Remain: .word 0 BJ_DrawBase: .word 0 BJ_FullDMA: .word 0 BJ_CustomDMA: .word 0 BJ_CustomW5: .word 0 BJ_CustomW6: .word 0 BJ_ClonePage: .word 0 BJ_CloneALow: .word 0 BJ_CloneBLow: .word 0 BJ_W1: .word 0 BJ_W2: .word 0 BJ_W3: .word 0 BJ_W4: .word 0 BN_Pos: .word 0 BN_Max: .word 0 BN_NextChar: .word 0 BN_BitMask: .word 0 BN_PrefixPtr: .word 0 BN_RowRemain: .word 0 BN_EarlyStop: .word 0 BN_Prefix: .byte 0,0,0,0,0,0,0,0,0,0 .even AppMain: .word 0 DebugMode: .word 0 ; IND SU toggles; controller state unaffected HL_Page: .word 0 HL_OldPacket: .word 0 HL_OldCustom: .word 0 HL_OldMarquee: .word 0 FocusIndex: .word 0 ReadTarget: .word 0 WriteTarget: .word 0 HighlightX: .word 0 HighlightWidth: .word 0 MarqueeAge: .word 0 MarqueeOffset: .word 0 MarqueeDone: .word 0 ClockActive: .word 0 ClockOldPreset: .word 0 ClockOldControl:.word 0 HeldArrow: .word 0 PendingCommand: .word 0 OldBusPC: .word 0 OldBusPSW: .word 0 BusFault: .word 0 FPGAValue: .word 0 HW_Saved: .word 0 OldKeyMask: .word 0 APIStage: .word 0 CSR_Pre: .word 0 CSR_Reset: .word 0 CSR_Cmd: .word 0 STM_Word: .word 0 STM_Major: .word 0 HW_Revision: .word 0 VideoModeReadback: .word 0 VideoPageReadback: .word 0 MaxDiskNo: .word 0 AZBootBuild: .word 0 AZBootValid: .word 0 UX: .word 0 UY: .word 0 DecWidth: .word 0 DecFactors: .word 10000.,1000.,100.,10.,1. OctBuffer: .byte 0,0,0,0,0,0,0 DiagOctBuf: .byte 0,0,0,0,0,0,0 DecBuffer: .byte 0,0,0,0,0,0 .even Msg170Fail: .asciz "AZ RAM 170000 WINDOW FAILED. " MsgNoAZ: .asciz "NO AZ CONTROLLER. " MsgOldFW: .asciz "UNSUPPORTED STM32 FW: V18+ REQUIRED. " MsgResetTimeout:.asciz "API 000 RESET TIMEOUT. " MsgResetStatus: .asciz "API 000 RESET STATUS ERROR. " MsgAPITimeout: .asciz "API 027 TIMEOUT. " MsgAPIStatus: .asciz "API 027 STATUS ERROR. " MsgCSRPre: .asciz " PRE:" MsgCSRReset: .asciz " RST:" MsgCSRCmd: .asciz " CMD:" MsgInitFail: .asciz "VIDEO INITIALIZATION FAILED. " MsgPressKey: .asciz " PRESS ANY KEY TO EXIT" StrHead0: .asciz "AZMNT 09 FPGA:" StrHead1: .asciz " STM:" StrHead2: .asciz " HW:" StrHead3: .asciz " BOOT:" StrNA: .asciz "N/A" StrDiskPrefix: .asciz ": D" StrDiskEmpty: .asciz " = " ; Approved two-page help, ASCII glyphs only. (c) is visual stand-in ; for the Cyrillic copyright letter on the BK monitor ROM glyph set. StrHLTitle: .asciz "AZMNT 09 HELP" StrHLP1Title: .asciz "CONTROLS 1/2" StrHLP2Title: .asciz "FILES + SAFETY 2/2" StrHLFooter: .asciz "LEFT/RIGHT: PAGE ENTER/KT: CLOSE" StrHLFailure: .asciz "HELP DMA ERROR - SCREEN NOT CHANGED" .even HL_P1Lines: .word HL_1_00,HL_1_01,HL_1_02,HL_1_03,HL_1_04,HL_1_05,HL_1_06,HL_1_07,HL_1_08,HL_1_09,HL_1_10,HL_1_11,HL_1_12,HL_1_13,HL_1_14,HL_1_15,HL_1_16,HL_1_17 HL_P2Lines: .word HL_2_00,HL_2_01,HL_2_02,HL_2_03,HL_2_04,HL_2_05,HL_2_06,HL_2_07,HL_2_08,HL_2_09,HL_2_10,HL_2_11,HL_2_12,HL_2_13,HL_2_14,HL_2_15,HL_2_16,HL_2_17 HL_1_00: .asciz "MAIN SCREEN" HL_1_01: .asciz "UP/DOWN SELECT DISK / MENU" HL_1_02: .asciz "ENTER BROWSE DISK / EXECUTE" HL_1_03: .asciz "SPACE CLEAR DISK PATH IN WORK" HL_1_04: .asciz "LEFT/RIGHT CHOOSE READ/WRITE SOURCE" HL_1_05: .asciz "READ LOAD AZ.INI / CONTROLLER" HL_1_06: .asciz "WRITE SAVE WORK TO TARGET" HL_1_07: .asciz "KT BACK TO SOURCE (DISCARD?)" HL_1_08: .asciz "EXIT RETURN TO ANDOS" HL_1_09: .asciz "HELP THESE TWO PAGES" HL_1_10: .asciz "" HL_1_11: .asciz "MICROSD BROWSER" HL_1_12: .asciz "UP/DOWN PREVIOUS / NEXT FILE" HL_1_13: .asciz "LEFT/RIGHT PAGE UP / DOWN (18)" HL_1_14: .asciz "ENTER OPEN DIR / SELECT FILE" HL_1_15: .asciz "KT CLOSE BROWSER" HL_1_16: .asciz "IND SU DEBUG MODE ON/OFF" HL_1_17: .asciz " STAGES AND R/W/E/S/T" HL_2_00: .asciz "SAVING DISK MAPPING" HL_2_01: .asciz "WRITE CTRL APPLY + READBACK VERIFY" HL_2_02: .asciz "WRITE INI BACKUP + SAVE + RESTART" HL_2_03: .asciz "" HL_2_04: .asciz "AZ.INI SAVE SEQUENCE" HL_2_05: .asciz "1. CHECK ORIGINAL AZ.INI UNCHANGED" HL_2_06: .asciz "2. COPY OLD AZ.INI TO AZINI.BAK" HL_2_07: .asciz "3. VERIFY BAK BYTE-FOR-BYTE" HL_2_08: .asciz "4. WRITE NEW AZ.INI FROM WORK" HL_2_09: .asciz "5. READBACK + PARSE FIVE SECTIONS" HL_2_10: .asciz "6. REPORT, AUTO RESTART IN 10 S" HL_2_11: .asciz " ANY KEY RESTARTS IMMEDIATELY" HL_2_12: .asciz "" HL_2_13: .asciz "AZINI.BAK = PREVIOUS AZ.INI" HL_2_14: .asciz "OLD BAK MAY BE OVERWRITTEN" HL_2_15: .asciz "KEEP AN EXTERNAL ARCHIVE IF NEEDED" HL_2_16: .asciz "ON SAVE ERROR: NO AUTOMATIC REBOOT" HL_2_17: .asciz "(c) MAXIOL LTD 2026" .even StrMenuRead: .asciz "READ : AZ.INI CONTROLLER" StrMenuWrite: .asciz "WRITE: AZ.INI CONTROLLER" StrMenuExit: .asciz "EXIT TO ANDOS HELP" StrStatus2: .asciz "UP/DOWN:SELECT ENTER:EDIT SPACE:CLEAR KT:SOURCE" StrDebugOn: .asciz "DEBUG MODE ON - IND SU:OFF / BROWSER R/W/E/S/T" StrStatusNoop: .asciz "READ ONLY - DISK MAPPING NOT YET LOADED" StrStatusMap: .asciz "CONTROLLER MAP LOADED - WRITE:CTRL CONFIRM" StrStatusIni: .asciz "AZ.INI LOADED - WRITE:BACKUP+MAIN+REBOOT" StrMapReadError:.asciz "READ FAILED C:00 CSR:000000 D:00" StrIniReadError:.asciz "INI ERROR C:00 S:00 Q:000000 L:00000 D:00" StrIniSDRead: .asciz "SD I/O C:00 S:00 Q:000000 L:00000 D:00" StrIniDirLimit: .asciz "DIR LIMIT C:00 S:00 Q:000000 L:00000 D:00" StrWriteDisabled:.asciz "SAVE DISABLED - WORK IN RAM ONLY" StrApplyPreview: .asciz "LIVE CONTROLLER DIFF / ENTER TO CONTINUE" StrNoChanges: .asciz "NO CHANGES TO WRITE" StrNoChangesIni: .asciz "WORK MATCHES LOADED SOURCE" StrNoChangesController:.asciz "NO LOCAL CONTROLLER CHANGES" StrAnyKey: .asciz "PRESS ANY KEY TO CLOSE" StrABQuestion: .asciz "CREATE BACKUP AZINI.BAK FROM AZ.INI?" StrABWarning: .asciz "EXISTING AZINI.BAK MAY BE OVERWRITTEN" StrABProgress: .asciz "READ AZ.INI / WRITE AZINI.BAK..." StrABSafeWarning:.asciz "DO NOT RESET OR POWER OFF" StrABSafeDetail:.asciz "REOPEN + VERIFY EVERY BYTE" StrABPhaseBlank:.asciz " " StrABPhaseRoot: .asciz "PHASE 11: ROOT DIR LOOKUP" StrABPhaseRead: .asciz "PHASE 12: FILE READ" StrABPhaseCopy: .asciz "PHASE 13: RAM COPY" StrABPhaseReset:.asciz "PHASE 14: SOURCE RESET" StrABPhaseWrite:.asciz "PHASE 15: WRITE + READBACK" StrABPreflightOK:.asciz "PREFLIGHT PASS - NO BAK CREATED" StrABPreflightFail:.asciz "PREFLIGHT FAILED - NO BAK CREATED" StrABVerified: .asciz "AZINI.BAK VERIFIED BYTE-FOR-BYTE" StrABFailed: .asciz "AZINI.BAK COPY / VERIFY FAILED" StrAMQuestion: .asciz "BACKUP + WRITE AZ.INI + RESTART BK?" StrAMWarning: .asciz "OLD BAK REPLACED / UNSAVED BK DATA LOST" StrAMProgress: .asciz "WRITING MAIN AZ.INI - DO NOT RESET" StrAMVerified: .asciz "MAIN AZ.INI VERIFIED BYTE-FOR-BYTE" StrAMFailed: .asciz "MAIN WRITE/VERIFY FAILED - KEEP BAK" StrAMBlocked: .asciz "MAIN SAVE BLOCKED - AZ.INI UNTOUCHED" StrAMBlockNoBAK:.asciz "MAIN SAVE BLOCKED: BAK CHECK FAILED" StrAMBlockStale:.asciz "MAIN SAVE BLOCKED: SOURCE CHANGED" StrAMBackupPhase:.asciz "CHECK OR UPDATE AZINI.BAK" StrAMFreshPhase: .asciz "READ FRESH AZ.INI / CHECK SOURCE" StrAMNewBackup: .asciz "CREATE AZINI.BAK + VERIFY" StrAMBuildPhase:.asciz "GENERATE WORK / VERIFY CONTENT" StrAMReloadPhase:.asciz "RELOAD SAVED AZ.INI" StrAMRefreshBackup:.asciz "REPLACE OLD BAK WITH CURRENT AZ.INI" StrAMWritingMain:.asciz "WRITE + VERIFY MAIN AZ.INI" StrAMReportBak: .asciz "AZINI.BAK: VERIFIED " StrAMReportMain: .asciz "AZ.INI: VERIFIED " StrAMReportBytes: .asciz " BYTES " StrAMReportReused:.asciz "REUSED" StrAMReportCreated:.asciz "CREATED" StrAMReportUpdated:.asciz "UPDATED" StrAMReportChecks:.asciz "SOURCE: MATCH / READBACK+PARSE: PASS" StrAMReportWait: .asciz "ANY KEY: REBOOT / AUTO IN: 00 S" StrAMRebootTitle:.asciz "MAIN AZ.INI VERIFIED - RESTARTING" StrAMRebootDetail:.asciz "RESET STM32 + BK VIA COMMAND 037" StrAMRebootWait: .asciz "PLEASE WAIT - FULL SYSTEM REBOOT" StrAWPotentialPartial:.asciz "MAIN MAY BE PARTIAL - CHECK AZINI.BAK" StrAWNotWritten: .asciz "MAIN NOT WRITTEN - CHECK AZINI.BAK" StrAWCheckAndRestart:.asciz "AZ.INI WRITTEN - VERIFY BEFORE RESTART" StrAWSavedManual: .asciz "AZ.INI VERIFIED - RESTART BK MANUALLY" StrAMRebootFailed:.asciz "AZ.INI SAVED - RESTART NOT CONFIRMED" StrAWUnsupported:.asciz "READ AZ.INI FIRST - SAVE BLOCKED" StrAWBuildError:.asciz "INI BUILD FAILED - NO WRITE SENT" StrAWBuildCode: .asciz "BUILD CODE:" StrAWQuestion: .asciz "SAVE WORK DISKS INTO AZ2.INI?" StrAWWarning: .asciz "AZ.INI UNCHANGED / AZ2 MAY OVERWRITE" StrAWProgress: .asciz "WRITING AZ2.INI FROM WORK..." StrAWReadback: .asciz "REOPEN + PARSE + BYTE READBACK" StrAWVerified: .asciz "AZ2.INI WORK SAVE VERIFIED" StrAWFailed: .asciz "AZ2.INI WRITE / VERIFY FAILED" StrAWStage: .asciz "STAGE:" StrAWError: .asciz " E:" StrAWCSR: .asciz " CSR:" StrAWReadStage: .asciz " F:" StrAWReadCode: .asciz " C:" StrAWLength: .asciz "BYTES:" StrAWOffset: .asciz " CHECK:" StrWritingController:.asciz "WRITING TO CONTROLLER..." StrWritingIni: .asciz "WRITING AZ.INI..." StrWritingWarning: .asciz "DO NOT RESET OR POWER OFF" StrWritingVerify: .asciz "APPLY + READBACK VERIFICATION" StrWritingWait: .asciz "PLEASE WAIT" StrApplyQuestion:.asciz "APPLY CHANGES TO CONTROLLER?" StrApplyWarning: .asciz "ACTIVE SYSTEM DISKS MAY CHANGE!" StrApplyChoices: .asciz "NO (KEEP WORK) YES (APPLY)" StrApplyKeys: .asciz "LEFT/RIGHT SELECT ENTER OK KT CANCEL" StrApplyOK: .asciz "CONTROLLER WRITE VERIFIED" StrApplyFailed: .asciz "CONTROLLER PARTIALLY UPDATED / FAILED" StrApplyUnknown: .asciz "CONTROLLER STATE UNKNOWN / READ ERROR" StrApplyStage: .asciz "STAGE:" StrApplyDisk: .asciz " DISK:" StrApplyDone: .asciz "OK:" StrApplyRemain: .asciz " LEFT:" StrApplyCsr: .asciz " CSR:" StrApplyErr: .asciz " E:" StrApplyClose: .asciz "ENTER / KT: CLOSE - NO AUTO ROLLBACK" StrDiffTitle: .asciz "WORK DIFF / AZ2, BAK OR MAIN SAVE" StrDiffCount: .asciz "CHANGED DISKS: " StrDiffLo: .asciz "D00-D15: " StrDiffHi: .asciz "D16-D31: " StrDiscardChanges:.asciz "DISCARD UNSAVED CHANGES?" StrDiscardWarning:.asciz "CURRENT WORK EDITS WILL BE LOST" StrDiscardOptions:.asciz "NO (KEEP WORK) YES (DISCARD)" StrDiscardControls:.asciz "LEFT/RIGHT:SELECT ENTER:OK KT:CANCEL" StrDialogDmaError:.asciz "DIALOG DMA ERROR - CHECK BLITTER" StrWorkError: .asciz "WORK EDIT FAILED - SOURCE UNCHANGED" StrWorkDirty: .asciz "WORK MODIFIED / WRITE:CTRL APPLY / KT:SOURCE" StrBrowseClosed: .asciz "BROWSER CLOSED - DISK MAPPING UNCHANGED" StrBrowseSelect:.asciz "WORK FILE: " StrBrowseErrorStatus:.asciz "BROWSER ERROR C:" StrScrollError: .asciz "SCROLL DMA ERROR C:" StrDlgTitle: .asciz "LOAD DISK MAPPING" StrDlgDefault: .asciz "CONTROLLER (DEFAULT) AZ.INI" StrDlgController:.asciz "SOURCE: CONTROLLER" StrDlgIniSelected:.asciz "SOURCE: AZ.INI" StrDlgContinue: .asciz "LEFT:CTRL RIGHT:INI ENTER:LOAD KT:EXIT" StrDlgReadFail: .asciz "ERROR C:00 CSR:000000" StrDlgIniSD: .asciz "SD I/O:00 CSR:000000" StrDlgIniLimit: .asciz "DIR LIM:00 CSR:000000" StrDlgRetry: .asciz "ENTER: RETRY KT: EXIT " StrDlgBlank: .asciz " " StrDlgDiagBlank:.asciz " " StrDlgIniDiag: .asciz "S:00 L:00000 N:00000" StrDlgHead: .asciz "H:" StrDlgNulOffset:.asciz "O:" Str64Spaces: .asciz " " .even ; One local BK scratch path, never banked; 386 bytes incl NUL tail. MapHeaderCache: .byte 0,0,0,0,0,0,0,0,0,0 MapPathCache: .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0 .even ; Fixed 64-entry sliding cache, 64 x 22 = 1408 bytes; directory may ; contain many more entries. Entries beyond this window are rescanned. .even BR_OldPacket: .word 0 BR_Backed: .word 0 BR_Restore: .word 0 BR_Error: .word 0 BR_ErrorStage: .word 0 BR_Banner: .word 0 BR_RootFallback:.word 0 BR_PathMode: .word 0 ; 1=wire omit trailing slash, 0=wire keep slash BR_BothEmpty: .word 0 ; nested dir returned no entries with either form BR_LastCSR: .word 0 BR_PathLen: .word 0 BR_OldPathLen: .word 0 BR_Cursor: .word 0 BR_Top: .word 0 BR_Count: .word 0 BR_Cached: .word 0 BR_CacheStart: .word 0 BR_ScrollDir: .word 0 BR_ScrollFault: .word 0 BR_OldMarquee: .word 0 BR_RowIndex: .word 0 BR_HasSelection:.word 0 BR_SelectedLen: .word 0 BR_FailStage: .word 0 BR_VerifyLine: .word 0 BR_VerifyWord: .word 0 BR_VerifySaved: .word 0 BR_VerifyScreen:.word 0 BR_DmaCode: .word 0 BR_BlRegister: .word 0 BR_DmaStatus: .word 0 BR_TraceActive: .word 0 BR_Stage: .word 0 BR_FirstError: .word 0 BR_FirstStage: .word 0 BR_Retries: .word 0 BR_WaitCalls: .word 0 BR_WaitMax: .word 0 BR_WaitBlocks: .word 0 BR_WaitTimeouts:.word 0 BR_StartPath: .asciz "0:/DISKS/" StrBRLoading: .asciz "READING MICROSD DIRECTORY..." StrBRStageReset:.asciz "STAGE: RESET " StrBRStageOpen: .asciz "STAGE: OPEN " StrBRStagePost: .asciz "STAGE: POST-OPEN RESET " StrBRStageNext: .asciz "STAGE: NEXT/READ " StrBRStagePaint:.asciz "STAGE: PAINT " StrBRDiagR: .asciz "R:" StrBRDiagW: .asciz " W:" StrBRDiagE: .asciz " E:" StrBRDiagS: .asciz " S:" StrBRDiagT: .asciz " T:" StrBRDebugClear:.asciz " " StrBRTitle: .asciz "MICROSD BROWSER - READ ONLY" StrBRDir: .asciz "" .even ; 10-digit unsigned byte lengths, includes 4GiB-1 (4294967295). ; Each factor: low 16 bits, then high 16 bits, in OCTAL. BR_SizePowers: .word 145000,035632 ; 10^9 .word 160400,002765 ; 10^8 .word 113200,000230 ; 10^7 .word 041100,000017 ; 10^6 .word 103240,000001 ; 10^5 .word 023420,000000 ; 10^4 .word 001750,000000 ; 10^3 .word 000144,000000 ; 10^2 .word 000012,000000 ; 10^1 .word 000001,000000 ; 10^0 BR_SizeSeen: .word 0 BR_SizeDigit: .word 0 BR_SizeText: .asciz " " .even BR_GroupOffsets: .word 0.,2.,3.,4.,6.,7.,8.,10.,11.,12. BR_GroupedSize: .asciz " " StrBREmpty: .asciz "" StrBRUnconfirmed:.asciz "NO ENTRIES FROM EITHER PATH FORM" StrBRHelp: .asciz "UP/DN:ROW L/R:PAGE ENTER:OPEN ..:UP KT:EXIT" StrBRScrollFault:.asciz "SCROLL DMA FAILED - FULL DRAW FALLBACK" StrBRFallback: .asciz "DISKS UNAVAILABLE - ROOT OPENED" StrBRTooLong: .asciz "PATH TOO LONG / DIR NOT OPENED" StrBRError: .asciz "MICROSD DIR ERROR C:" StrBRBlocked: .asciz "DIRECTORY READ FAILED - KT: RETURN" StrBRDiagStage: .asciz " S:" StrBRDiagMode: .asciz " M:" StrBRDiagCSR: .asciz " Q:" StrBRDiagCode: .asciz " J:" StrBRDiagRegister:.asciz " Q:" StrBRDiagLast: .asciz " T:" StrBRDiagLine: .asciz " L:" StrBRDiagWord: .asciz " W:" StrBRDiagBackup:.asciz " P:" StrBRDiagVideo: .asciz " V:" StrBREllipsis: .asciz "..." .even BR_Record: .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0 ; CPU fast-window AZ RAM page 2140 holds the following 2436 bytes: ; BR_Entries (1408; AP_OldPath / AP_NewPath / AP_MountText / SG_SavedPath), ; BR_Path (256), BR_SelectedPath (260), INI_Line (512). ; These are absolute addresses defined before Begin, not emitted BIN data. ; One-page bank setup and round-trip proof: HW_EnterMono. ; WARNING: never repage WIN170 while executing AZMNT code or parsing INI. .even ; INI reader metadata (all original file bytes remain in AZ RAM). .even DiffCount: .word 0 DiffRows: .word 0 DiffSrcStart: .word 0 DiffDstStart: .word 0 DiffSrcPage: .word 0 DiffDstPage: .word 0 DiffMarksLo: .asciz "................" DiffMarksHi: .asciz "................" .even ; AZMNT_07 controller-write state; all hardware addresses are octal. AP_Stage: .word 0 AP_Error: .word 0 AP_FailedStage: .word 0 AP_FailedDisk: .word 0 AP_FailedCSR: .word 0 AP_PostBad: .word 0 AP_CSR: .word 0 AP_Disk: .word 0 AP_Total: .word 0 AP_Remaining: .word 0 AP_Verified: .word 0 AP_OldLen: .word 0 AP_NewLen: .word 0 AP_CaseFold: .word 0 ; local comparison mode (both 0:/ only) WorkDirty: .word 0 DiscardChoice: .word 0 ; 0=NO(default); 1=YES DL_OldPacket: .word 0 DL_OldCustom: .word 0 DL_HaveSaved: .word 0 DL_Result: .word 0 WorkRowChanged: .word 0 WorkOriginalBase:.word 0 .even ; Writer scratch is separate from all framebuffers, maps and INI source. INI_DirNamePtr: .word INI_BaseName INI_FileNamePtr:.word INI_FileName AW_Result: .word 0 AW_Mode: .word 0 ; 0=WORK->AZ2, 1=BAK, 2=MAIN AZ.INI AW_TargetBasePtr:.word INI_BaseName AW_TargetFilePtr:.word INI_FileName AB_OldStage: .word 0 AB_OldLen: .word 0 AB_OldDirLen: .word 0 AB_OldDirPtr: .word 0 AB_OldFilePtr: .word 0 AB_SavedWinRO: .word 0 ; exact WIN_RO state before BAK preflight ; AZMNT_08 r02 serialization metadata in ordinary BK RAM. .even SG_Error: .word 0 SG_SrcPos: .word 0 SG_LineStart: .word 0 SG_LineLen: .word 0 SG_TextEnd: .word 0 SG_Current: .word 0 SG_NewSection: .word 0 SG_UnknownCount: .word 0 SG_UnknownEndPtr:.word 0 SG_UnknownIndex: .word 0 SG_SectionIndex: .word 0 SG_From: .word 0 SG_To: .word 0 SG_OutLen: .word 0 SG_DiskIndex: .word 0 SG_DiskLen: .word 0 SG_OldStage: .word 0 SG_OldLength: .word 0 SG_OldMapStage: .word 0 SG_StdStarts: .word 0,0,0,0,0 SG_StdEnds: .word 0,0,0,0,0 SG_UnknownStarts:.blkw 32. SG_UnknownEnds: .blkw 32. .even AW_Error: .word 0 AW_Stage: .word 0 AW_CSR: .word 0 AW_ExpectedLen: .word 0 AW_ReadStage: .word 0 AW_ReadCode: .word 0 AW_Remain: .word 0 AW_BlockBytes: .word 0 AW_Page: .word 0 AW_Ptr: .word 0 AW_VerifyPage: .word 0 AW_BadOffset: .word 0 AW_OldStageBase: .word 0 AW_OldLength: .word 0 AW_OldDirLength: .word 0 AM_SavedSrcLen: .word 0 AM_BackupReady: .word 0 AM_BackupSize: .word 0 AM_BakAction: .word 0 ; 0=reused, 1=created, 2=updated AM_MainSize: .word 0 ; verified WORK-derived AZ.INI bytes AM_SecondsLeft: .word 0 ; 10..1, then reboot AM_TicksLeft: .word 0 ; 20 hardware ticks per second AM_CheckBankA: .word 0 AM_CheckBankB: .word 0 AM_CheckLength: .word 0 AM_Stage: .word 0 AM_Result: .word 0 AM_WriteStarted:.word 0 AM_RestoreOldBase: .word 0 AM_RestoreOldLen: .word 0 AM_RestoreOldDir: .word 0 AM_RestoreDirPtr:.word 0 AM_RestoreFilePtr:.word 0 AM_CompareTemp: .word 0 ; MicroSD names; MAIN target AZ.INI may be opened for writing ONLY after r08 guard + YES. AB_BaseName: .asciz "AZINI.BAK" .even AB_FileName: .asciz "AZINI.BAK" .even .word 0 INI_DirOutcome: .word 0 ; 1=found,2=missing at directory EOF,0=unknown/error INI_DirLength: .word 0 INI_BlockReported:.word 0 ModalSource: .word 0 MapSource: .word 0 ; 1=CONTROLLER 2=AZ.INI INI_ActiveBase: .word 0 INI_ActiveLength:.word 0 INI_StageBase: .word 0 INI_StageBasePage:.word 0 INI_Length: .word 0 INI_SizeHigh: .word 0 INI_Remain: .word 0 INI_BlockSize: .word 0 INI_Error: .word 0 INI_RetryCount: .word 0 ; failed read transport: retries already performed 0..5 INI_Stage: .word 0 INI_LastCSR: .word 0 INI_HeadWord: .word 0 INI_NulOffset: .word 0 INI_BadByte: .word 0 INI_Seen: .word 0 INI_Section: .word 0 INI_DiskSeenLo: .word 0 INI_DiskSeenHi: .word 0 INI_DiskCount: .word 0 INI_ParseRemaining:.word 0 INI_ParsePage: .word 0 INI_ParsePtr: .word 0 INI_LineNo: .word 0 INI_LineLen: .word 0 ; Exact path used by original RT-11 azinrd.mac; explicit padding. INI_RootName: .asciz "0:/" .even .word 0,0 INI_BaseName: .asciz "AZ.INI" .even INI_FileName: .asciz "AZ.INI" .even .word 0 INI_ROM: .asciz "[ROM]" INI_LOGO: .asciz "[LOGO]" INI_DISKS: .asciz "[DISKS]" INI_NETWORK: .asciz "[NETWORK]" INI_BOOT: .asciz "[BOOT]" .even ; INI_Line fixed at 173404 in AZ RAM page 2140; 512 bytes reserved in bank. .even MapActiveBase: .word 0 MapStageBase: .word 0 MapReadBase: .word 0 MapLoaded: .word 0 MapLastCSR: .word 0 MapErrorCode: .word 0 MapBadDisk: .word 0 .END