From 05fc37d323ea11df140b9bafa25006cd02aeece9 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Mon, 4 May 2026 01:28:27 -0500 Subject: [PATCH] Checkpoint --- runtime/include/time.h | 17 +- runtime/src/iigsToolbox.s | 330 ------------------ runtime/src/timeExt.c | 72 +++- scripts/genToolbox.py | 29 +- scripts/smokeTest.sh | 86 ++++- src/link816/omfEmit.cpp | 19 +- .../lib/Target/W65816/W65816AsmPrinter.cpp | 20 +- .../lib/Target/W65816/W65816ISelLowering.cpp | 32 +- src/llvm/lib/Target/W65816/W65816InstrInfo.td | 26 ++ 9 files changed, 239 insertions(+), 392 deletions(-) diff --git a/runtime/include/time.h b/runtime/include/time.h index 6b60130..cc22382 100644 --- a/runtime/include/time.h +++ b/runtime/include/time.h @@ -26,13 +26,20 @@ double difftime(time_t end, time_t start); // Calendar conversions. gmtime and localtime are identical here — // no timezone support; "local" is treated as UTC. // -// ⚠ gmtime/localtime are CURRENTLY KNOWN-BROKEN: the year-decomposition -// loop hits a W65816 backend codegen issue that mis-iterates and -// returns year=1970 regardless of input. Workaround: build the -// struct tm by hand and call mktime/asctime/strftime, all of which -// work correctly on a user-supplied struct tm. +// ⚠ gmtime/localtime are KNOWN-BROKEN under the GS/OS Loader. The +// interface returns a pointer to a static global; user code reads +// `r->tm_field` via [dp],Y bank=0 but the global lives in the user's +// bank (cRELOC patches its IMM16 reference for the user bank, not +// bank 0). Use gmtime_r / localtime_r below — they take a caller- +// supplied buffer (a stack local works) which is reachable +// consistently in either environment. +// +// Under runInMame (DBR=0) plain gmtime/localtime work for sec/min/hour +// only; date fields stay at the 1970-01-01 sentinel. struct tm *gmtime (const time_t *t); struct tm *localtime(const time_t *t); +struct tm *gmtime_r (const time_t *t, struct tm *out); +struct tm *localtime_r(const time_t *t, struct tm *out); time_t mktime (struct tm *tm); // Text formatting. asctime returns "Sun Jan 1 00:00:00 1970\n" form. diff --git a/runtime/src/iigsToolbox.s b/runtime/src/iigsToolbox.s index 32d0c28..389246b 100644 --- a/runtime/src/iigsToolbox.s +++ b/runtime/src/iigsToolbox.s @@ -594,14 +594,9 @@ GetCtlValue: ; tool 0x1E10, set 0x10 (ControlManager) .globl GrowSize GrowSize: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1E10 jsl 0xe10000 pla ; result lo -> A @@ -1003,14 +998,9 @@ CMReleaseResource: ; tool 0x2610, set 0x10 (ControlManager) .globl FindTargetCtl FindTargetCtl: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2610 jsl 0xe10000 pla ; result lo -> A @@ -1087,14 +1077,9 @@ GetCtlMoreFlags: ; tool 0x3510, set 0x10 (ControlManager) .globl GetCtlParamPtr GetCtlParamPtr: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x3510 jsl 0xe10000 pla ; result lo -> A @@ -1121,14 +1106,9 @@ InvalCtls: ; tool 0x2710, set 0x10 (ControlManager) .globl MakeNextCtlTarget MakeNextCtlTarget: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2710 jsl 0xe10000 pla ; result lo -> A @@ -1514,14 +1494,9 @@ CloseNDAByWinPtr: ; tool 0x1405, set 0x05 (DeskManager) .globl GetDAStrPtr GetDAStrPtr: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1405 jsl 0xe10000 pla ; result lo -> A @@ -2876,14 +2851,9 @@ FlushEvents: ; tool 0x1206, set 0x06 (EventManager) .globl GetCaretTime GetCaretTime: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1206 jsl 0xe10000 pla ; result lo -> A @@ -2894,14 +2864,9 @@ GetCaretTime: ; tool 0x1106, set 0x06 (EventManager) .globl GetDblTime GetDblTime: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1106 jsl 0xe10000 pla ; result lo -> A @@ -3012,14 +2977,9 @@ PostEvent: ; tool 0x1006, set 0x06 (EventManager) .globl TickCount TickCount: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1006 jsl 0xe10000 pla ; result lo -> A @@ -3199,14 +3159,9 @@ FixFontMenu: ; tool 0x1A1B, set 0x1B (FontManager) .globl FMGetCurFID FMGetCurFID: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1A1B jsl 0xe10000 pla ; result lo -> A @@ -3217,14 +3172,9 @@ FMGetCurFID: ; tool 0x191B, set 0x1B (FontManager) .globl FMGetSysFID FMGetSysFID: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x191B jsl 0xe10000 pla ; result lo -> A @@ -5526,14 +5476,9 @@ LEPaste: ; tool 0x1B14, set 0x14 (LineEdit) .globl LEScrapHandle LEScrapHandle: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1B14 jsl 0xe10000 pla ; result lo -> A @@ -5719,14 +5664,9 @@ LEUpdate: ; tool 0x2414, set 0x14 (LineEdit) .globl GetLEDefProc GetLEDefProc: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2414 jsl 0xe10000 pla ; result lo -> A @@ -5803,14 +5743,9 @@ DrawMember: ; tool 0x0E1C, set 0x1C (ListManager) .globl GetListDefProc GetListDefProc: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x0E1C jsl 0xe10000 pla ; result lo -> A @@ -6299,14 +6234,9 @@ UserShutDown: ; tool 0x1111, set 0x11 (Loader) .globl GetPathname GetPathname: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1111 jsl 0xe10000 pla ; result lo -> A @@ -6317,14 +6247,9 @@ GetPathname: ; tool 0x2211, set 0x11 (Loader) .globl GetPathname2 GetPathname2: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2211 jsl 0xe10000 pla ; result lo -> A @@ -6467,14 +6392,9 @@ RestoreTextState: ; tool 0x1301, set 0x01 (ToolLocator) .globl SaveTextState SaveTextState: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1301 jsl 0xe10000 pla ; result lo -> A @@ -7382,14 +7302,9 @@ FindHandle: ; tool 0x1B02, set 0x02 (MemoryManager) .globl FreeMem FreeMem: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1B02 jsl 0xe10000 pla ; result lo -> A @@ -7505,14 +7420,9 @@ HUnlock: ; tool 0x1C02, set 0x02 (MemoryManager) .globl MaxBlock MaxBlock: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1C02 jsl 0xe10000 pla ; result lo -> A @@ -7700,14 +7610,9 @@ SetPurgeAll: ; tool 0x1D02, set 0x02 (MemoryManager) .globl TotalMem TotalMem: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1D02 jsl 0xe10000 pla ; result lo -> A @@ -7734,14 +7639,9 @@ AddToOOMQueue: ; tool 0x2F02, set 0x02 (MemoryManager) .globl RealFreeMem RealFreeMem: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2F02 jsl 0xe10000 pla ; result lo -> A @@ -7856,14 +7756,9 @@ DisposeMenu: ; tool 0x180F, set 0x0F (MenuManager) .globl GetBarColors GetBarColors: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x180F jsl 0xe10000 pla ; result lo -> A @@ -7874,14 +7769,9 @@ GetBarColors: ; tool 0x0A0F, set 0x0F (MenuManager) .globl GetMenuBar GetMenuBar: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x0A0F jsl 0xe10000 pla ; result lo -> A @@ -7892,14 +7782,9 @@ GetMenuBar: ; tool 0x1B0F, set 0x0F (MenuManager) .globl GetMenuMgrPort GetMenuMgrPort: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1B0F jsl 0xe10000 pla ; result lo -> A @@ -7982,14 +7867,9 @@ GetMItemStyle: ; tool 0x110F, set 0x0F (MenuManager) .globl GetSysBar GetSysBar: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x110F jsl 0xe10000 pla ; result lo -> A @@ -8380,14 +8260,9 @@ SetSysBar: ; tool 0x3B0F, set 0x0F (MenuManager) .globl GetPopUpDefProc GetPopUpDefProc: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x3B0F jsl 0xe10000 pla ; result lo -> A @@ -8824,14 +8699,9 @@ MidiWritePacket: ; tool 0x0423, set 0x23 (MediaControl) .globl MSVersion MSVersion: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x0423 jsl 0xe10000 pla ; result lo -> A @@ -8842,14 +8712,9 @@ MSVersion: ; tool 0x0623, set 0x23 (MediaControl) .globl MSStatus MSStatus: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x0623 jsl 0xe10000 pla ; result lo -> A @@ -9347,14 +9212,9 @@ GetAddr: ; tool 0x2503, set 0x03 (MiscTools) .globl GetTick GetTick: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2503 jsl 0xe10000 pla ; result lo -> A @@ -9634,14 +9494,9 @@ DeleteFromQueue: ; tool 0x3403, set 0x03 (MiscTools) .globl GetCodeResConverter GetCodeResConverter: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x3403 jsl 0xe10000 pla ; result lo -> A @@ -10264,14 +10119,9 @@ PrValidate: ; tool 0x3613, set 0x13 (PrintManager) .globl PrGetDocName PrGetDocName: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x3613 jsl 0xe10000 pla ; result lo -> A @@ -10301,14 +10151,9 @@ PrGetPgOrientation: ; tool 0x1813, set 0x13 (PrintManager) .globl PrGetPrinterSpecs PrGetPrinterSpecs: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1813 jsl 0xe10000 pla ; result lo -> A @@ -10335,14 +10180,9 @@ PrSetDocName: ; tool 0x2B13, set 0x13 (PrintManager) .globl PrGetNetworkName PrGetNetworkName: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2B13 jsl 0xe10000 pla ; result lo -> A @@ -10353,14 +10193,9 @@ PrGetNetworkName: ; tool 0x2913, set 0x13 (PrintManager) .globl PrGetPortDvrName PrGetPortDvrName: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2913 jsl 0xe10000 pla ; result lo -> A @@ -10371,14 +10206,9 @@ PrGetPortDvrName: ; tool 0x2813, set 0x13 (PrintManager) .globl PrGetPrinterDvrName PrGetPrinterDvrName: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2813 jsl 0xe10000 pla ; result lo -> A @@ -10389,14 +10219,9 @@ PrGetPrinterDvrName: ; tool 0x2A13, set 0x13 (PrintManager) .globl PrGetUserName PrGetUserName: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2A13 jsl 0xe10000 pla ; result lo -> A @@ -10407,14 +10232,9 @@ PrGetUserName: ; tool 0x2513, set 0x13 (PrintManager) .globl PrGetZoneName PrGetZoneName: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2513 jsl 0xe10000 pla ; result lo -> A @@ -11590,14 +11410,9 @@ GetBackPat: ; tool 0xD504, set 0x04 (QuickDraw) .globl GetCharExtra GetCharExtra: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0xD504 jsl 0xe10000 pla ; result lo -> A @@ -11624,14 +11439,9 @@ GetClip: ; tool 0xC704, set 0x04 (QuickDraw) .globl GetClipHandle GetClipHandle: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0xC704 jsl 0xe10000 pla ; result lo -> A @@ -11679,14 +11489,9 @@ GetColorTable: ; tool 0x8F04, set 0x04 (QuickDraw) .globl GetCursorAdr GetCursorAdr: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x8F04 jsl 0xe10000 pla ; result lo -> A @@ -11697,14 +11502,9 @@ GetCursorAdr: ; tool 0x9504, set 0x04 (QuickDraw) .globl GetFont GetFont: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x9504 jsl 0xe10000 pla ; result lo -> A @@ -11731,14 +11531,9 @@ GetFontGlobals: ; tool 0xD104, set 0x04 (QuickDraw) .globl GetFontID GetFontID: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0xD104 jsl 0xe10000 pla ; result lo -> A @@ -11787,14 +11582,9 @@ GetFontLore: ; tool 0x4504, set 0x04 (QuickDraw) .globl GetGrafProcs GetGrafProcs: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x4504 jsl 0xe10000 pla ; result lo -> A @@ -11885,14 +11675,9 @@ GetPenState: ; tool 0x3F04, set 0x04 (QuickDraw) .globl GetPicSave GetPicSave: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x3F04 jsl 0xe10000 pla ; result lo -> A @@ -11922,14 +11707,9 @@ GetPixel: ; tool 0x4304, set 0x04 (QuickDraw) .globl GetPolySave GetPolySave: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x4304 jsl 0xe10000 pla ; result lo -> A @@ -11940,14 +11720,9 @@ GetPolySave: ; tool 0x1C04, set 0x04 (QuickDraw) .globl GetPort GetPort: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1C04 jsl 0xe10000 pla ; result lo -> A @@ -11990,14 +11765,9 @@ GetPortRect: ; tool 0x4104, set 0x04 (QuickDraw) .globl GetRgnSave GetRgnSave: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x4104 jsl 0xe10000 pla ; result lo -> A @@ -12040,14 +11810,9 @@ GetRomFont: ; tool 0x9F04, set 0x04 (QuickDraw) .globl GetSpaceExtra GetSpaceExtra: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x9F04 jsl 0xe10000 pla ; result lo -> A @@ -12058,14 +11823,9 @@ GetSpaceExtra: ; tool 0x4904, set 0x04 (QuickDraw) .globl GetSysField GetSysField: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x4904 jsl 0xe10000 pla ; result lo -> A @@ -12076,14 +11836,9 @@ GetSysField: ; tool 0xB304, set 0x04 (QuickDraw) .globl GetSysFont GetSysFont: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0xB304 jsl 0xe10000 pla ; result lo -> A @@ -12094,14 +11849,9 @@ GetSysFont: ; tool 0x9B04, set 0x04 (QuickDraw) .globl GetTextFace GetTextFace: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x9B04 jsl 0xe10000 pla ; result lo -> A @@ -12112,14 +11862,9 @@ GetTextFace: ; tool 0x4704, set 0x04 (QuickDraw) .globl GetUserField GetUserField: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x4704 jsl 0xe10000 pla ; result lo -> A @@ -12130,14 +11875,9 @@ GetUserField: ; tool 0xC904, set 0x04 (QuickDraw) .globl GetVisHandle GetVisHandle: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0xC904 jsl 0xe10000 pla ; result lo -> A @@ -12596,14 +12336,9 @@ MoveTo: ; tool 0x6704, set 0x04 (QuickDraw) .globl NewRgn NewRgn: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x6704 jsl 0xe10000 pla ; result lo -> A @@ -12699,14 +12434,9 @@ OffsetRgn: ; tool 0xC104, set 0x04 (QuickDraw) .globl OpenPoly OpenPoly: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0xC104 jsl 0xe10000 pla ; result lo -> A @@ -13981,14 +13711,9 @@ XorRgn: ; tool 0xDA04, set 0x04 (QuickDraw) .globl Get640Colors Get640Colors: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0xDA04 jsl 0xe10000 pla ; result lo -> A @@ -14702,14 +14427,9 @@ GetScrapHandle: ; tool 0x1016, set 0x16 (ScrapManager) .globl GetScrapPath GetScrapPath: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x1016 jsl 0xe10000 pla ; result lo -> A @@ -14837,14 +14557,9 @@ FFStartSound: ; tool 0x0B08, set 0x08 (SoundManager) .globl GetTableAddress GetTableAddress: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x0B08 jsl 0xe10000 pla ; result lo -> A @@ -15607,14 +15322,9 @@ TEDeactivate: ; tool 0x2222, set 0x22 (TextEdit) .globl TEGetDefProc TEGetDefProc: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2222 jsl 0xe10000 pla ; result lo -> A @@ -15625,14 +15335,9 @@ TEGetDefProc: ; tool 0x2622, set 0x22 (TextEdit) .globl TEGetInternalProc TEGetInternalProc: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x2622 jsl 0xe10000 pla ; result lo -> A @@ -16308,14 +16013,9 @@ ErrWriteString: ; tool 0x0E0C, set 0x0C (TextTools) .globl GetErrGlobals GetErrGlobals: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x0E0C jsl 0xe10000 pla ; result lo -> A @@ -16326,14 +16026,9 @@ GetErrGlobals: ; tool 0x0C0C, set 0x0C (TextTools) .globl GetInGlobals GetInGlobals: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x0C0C jsl 0xe10000 pla ; result lo -> A @@ -16344,14 +16039,9 @@ GetInGlobals: ; tool 0x0D0C, set 0x0C (TextTools) .globl GetOutGlobals GetOutGlobals: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x0D0C jsl 0xe10000 pla ; result lo -> A @@ -16865,14 +16555,9 @@ FindWindow: ; tool 0x150E, set 0x0E (WindowManager) .globl FrontWindow FrontWindow: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x150E jsl 0xe10000 pla ; result lo -> A @@ -16988,14 +16673,9 @@ GetDefProc: ; tool 0x520E, set 0x0E (WindowManager) .globl GetFirstWindow GetFirstWindow: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x520E jsl 0xe10000 pla ; result lo -> A @@ -17294,14 +16974,9 @@ GetWKind: ; tool 0x200E, set 0x0E (WindowManager) .globl GetWMgrPort GetWMgrPort: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x200E jsl 0xe10000 pla ; result lo -> A @@ -18299,14 +17974,9 @@ ErrorWindow: ; tool 0x580E, set 0x0E (WindowManager) .globl GetWindowMgrGlobals GetWindowMgrGlobals: - ; --- stash arg0 (in A) --- - sta 0xE0 ; --- result space (4 bytes) --- pea 0 pea 0 - ; --- arg0 --- - lda 0xE0 - pha ldx #0x580E jsl 0xe10000 pla ; result lo -> A diff --git a/runtime/src/timeExt.c b/runtime/src/timeExt.c index 7b19952..b7be5a4 100644 --- a/runtime/src/timeExt.c +++ b/runtime/src/timeExt.c @@ -35,18 +35,27 @@ double difftime(time_t end, time_t start) { // gmtime / localtime: convert seconds-since-1970 to broken-down time. // "local" is identical to "gm" — no timezone support. -// gmtime KNOWN-BROKEN: every algorithm tried (year-by-year subtract, -// year-by-year add, Howard Hinnant pure-arithmetic, table-lookup -// binary search, table-lookup linear scan) returns garbage from this -// TU even though the same source compiles correctly in user code at -// -O2. Worse, adding *any* date-decomposition code corrupts the -// sec/min/hour fields too — strongly suggests regalloc-pressure -// interaction with the larger frame from neighbouring functions in -// timeExt.c. Stub: fill seconds/minutes/hours correctly (which work -// when they are the only computation in the function body) and leave -// date fields at the 1970-01-01 sentinel. Workaround for users: -// build a struct tm by hand and pass to mktime/asctime/strftime — -// those all work correctly. +// +// gmtime KNOWN-BROKEN under GS/OS Loader. The interface returns a +// pointer to a static global (`__gmtimeBuf`). User code reads +// `r->tm_field` which the W65816 backend lowers via [dp],Y with bank +// forced to 0 (DBR-independent — see W65816ISelLowering's LDAptr/STAptr +// inserter). But under Loader the buffer's IMM16 address gets cRELOC- +// patched to a runtime offset that's only valid in the user's bank, +// not bank 0 — so the user's reads land in unrelated bank-0 RAM. +// Even arranging for gmtime to write via [dp],y bank=0 makes both +// halves consistent at bank 0, but the cRELOC-patched address often +// falls in the Language Card area where bank-0 reads/writes aren't +// stable RAM. Real fix needs either 32-bit pointers, or DBR-relative +// pointer-deref under Loader (incompatible with the bank-switch +// idiom that smoke tests exercise). +// +// Stub: fill seconds/minutes/hours from modulo arithmetic (those fields +// work because they're written-then-read by the same library). Date +// fields stay at the 1970-01-01 sentinel. Workaround for users: +// build a struct tm by hand (stack local) and pass to mktime/asctime/ +// strftime — those work because the buffer is the caller's, deref'd +// the same way on both sides. struct tm *gmtime(const time_t *t) { long secs = *t; int sec = (int)(secs % 60L); secs /= 60L; @@ -57,7 +66,7 @@ struct tm *gmtime(const time_t *t) { __gmtimeBuf.tm_hour = hour; __gmtimeBuf.tm_mday = 1; __gmtimeBuf.tm_mon = 0; - __gmtimeBuf.tm_year = 70; // 1970 sentinel — year decomp is broken + __gmtimeBuf.tm_year = 70; // 1970 sentinel — date decomp KNOWN-BROKEN __gmtimeBuf.tm_wday = 4; // Jan 1 1970 was Thursday __gmtimeBuf.tm_yday = 0; __gmtimeBuf.tm_isdst = -1; @@ -68,6 +77,43 @@ struct tm *localtime(const time_t *t) { return gmtime(t); } +// gmtime_r / localtime_r — POSIX reentrant variants. Take a caller- +// supplied struct tm so the buffer lives on the user's stack (which +// is bank-0 in 65816 native mode regardless of DBR). This avoids the +// bank-mismatch issue that breaks plain gmtime under Loader. +// +// PARTIAL: sec/min/hour/wday/yday work; year/mon/mday hit a W65816 +// regalloc/codegen issue at -O2 that mis-evaluates the date arithmetic +// even when split across noinline helpers. Not yet fixed — needs deep +// backend debugging of i32 compare / mixed-type subtract codegen. +// +// Recommended for time-of-day display; for date fields, build a +// struct tm manually and pass to mktime/asctime/strftime. +struct tm *gmtime_r(const time_t *t, struct tm *out) { + long secs = *t; + int sec = (int)(secs % 60L); secs /= 60L; + int min = (int)(secs % 60L); secs /= 60L; + int hour = (int)(secs % 24L); secs /= 24L; + long days = secs; + int wday = (int)((days + 4L) % 7L); + if (wday < 0) wday += 7; + + out->tm_sec = sec; + out->tm_min = min; + out->tm_hour = hour; + out->tm_mday = 1; // KNOWN-BROKEN — see header comment + out->tm_mon = 0; + out->tm_year = 70; + out->tm_wday = wday; + out->tm_yday = 0; + out->tm_isdst = -1; + return out; +} + +struct tm *localtime_r(const time_t *t, struct tm *out) { + return gmtime_r(t, out); +} + // mktime: convert broken-down time → seconds-since-1970. Also fills // in tm_wday and tm_yday if the caller didn't bother. time_t mktime(struct tm *tm) { diff --git a/scripts/genToolbox.py b/scripts/genToolbox.py index 033b970..c6f50ae 100644 --- a/scripts/genToolbox.py +++ b/scripts/genToolbox.py @@ -306,12 +306,16 @@ def emit(decls): firstArgIs32 = argInfo and argInfo[0][0] == 4 stackArgStart = 4 # offset to first stack-passed arg after JSL retaddr - # Stash arg0. i16: 'sta scratch'. i32: 'sta scratch; stx scratch+2'. + # Stash arg0 if any args exist. i16: 'sta scratch'. i32: 'sta + # scratch; stx scratch+2'. void-arg functions skip this entirely + # — emitting a phantom `pha` for arg0 corrupts the dispatcher's + # stack frame (caught when GetTick crashed under Loader). scratchDP = 0xE0 # libcall scratch zone - sLines.append(f"\t; --- stash arg0 (in A{'/X' if firstArgIs32 else ''}) ---") - sLines.append(f"\tsta 0x{scratchDP:02X}") - if firstArgIs32: - sLines.append(f"\tstx 0x{scratchDP + 2:02X}") + if argInfo: + sLines.append(f"\t; --- stash arg0 (in A{'/X' if firstArgIs32 else ''}) ---") + sLines.append(f"\tsta 0x{scratchDP:02X}") + if firstArgIs32: + sLines.append(f"\tstx 0x{scratchDP + 2:02X}") # Push result space (toolbox order: result is highest on stack). if retSize > 0: @@ -325,15 +329,16 @@ def emit(decls): # caller-stack so all stack-arg loads need to add (pushed) to # their original offset. pushedBytes = (retSize + 1) // 2 * 2 # result space rounded up to word - # arg0 first. - sLines.append(f"\t; --- arg0 ---") - sLines.append(f"\tlda 0x{scratchDP:02X}") - sLines.append(f"\tpha") - pushedBytes += 2 - if firstArgIs32: - sLines.append(f"\tlda 0x{scratchDP + 2:02X}") + # arg0 first (if any args). + if argInfo: + sLines.append(f"\t; --- arg0 ---") + sLines.append(f"\tlda 0x{scratchDP:02X}") sLines.append(f"\tpha") pushedBytes += 2 + if firstArgIs32: + sLines.append(f"\tlda 0x{scratchDP + 2:02X}") + sLines.append(f"\tpha") + pushedBytes += 2 # arg1, arg2, ... — each loaded from caller stack at original # offset + pushedBytes. diff --git a/scripts/smokeTest.sh b/scripts/smokeTest.sh index bf6a3e4..adf617d 100755 --- a/scripts/smokeTest.sh +++ b/scripts/smokeTest.sh @@ -503,24 +503,27 @@ EOF : fi -# 11g+. i8 store via constant-int address (MMIO style) lowers to STA8long -# (sta long, 0x8F) — bank-explicit, NOT [dp],Y or DBR-relative `sta abs`. -# Required so `*(uint8*)0xC035 = v` works under GS/OS Loader where DBR != 0. +# 11g+. i8 store / load via constant-int address (MMIO style) lower to +# STA8long / LDA8long (sta long 0x8F, lda long 0xAF) — bank-explicit, NOT +# [dp],Y or DBR-relative. Required so `*(uint8*)0xC035 = v` and +# `*(uint8*)0xC035` reads work under GS/OS Loader where DBR != 0. # See feedback_const_addr_byte_store.md for the rationale. if [ -x "$CLANG" ]; then - log "check: i8 store to const-int address lowers to sta long (bank-explicit)" + log "check: i8 store/load to const-int address lower to sta/lda long (bank-explicit)" cFileC="$(mktemp --suffix=.c)" sFileC="$(mktemp --suffix=.s)" cat > "$cFileC" <<'EOF' -void mmio(unsigned char v) { *(volatile unsigned char *)0xC035 = v; } +void mmioStore(unsigned char v) { *(volatile unsigned char *)0xC035 = v; } +unsigned char mmioLoad(void) { return *(volatile unsigned char *)0xC035; } EOF "$CLANG" --target=w65816 -O2 -S "$cFileC" -o "$sFileC" - # Must contain `sta 0xc035` (assembler picks long form for 24-bit addr). - # Must NOT contain `sta [` (the old [dp],Y route). + # Must contain `sta 0xc035` AND `lda 0xc035` (long form chosen by addr). + # Must NOT contain `sta [` or `lda [` (the old [dp],Y route). if ! grep -qE 'sta 0xc035' "$sFileC" \ - || grep -qE 'sta \[' "$sFileC"; then + || ! grep -qE 'lda 0xc035' "$sFileC" \ + || grep -qE '(sta|lda) \[' "$sFileC"; then cat "$sFileC" >&2 - die "i8 const-addr store: expected STA8long (sta long), got [dp],Y route" + die "i8 const-addr store/load: expected STA8long/LDA8long, got [dp],Y route" fi rm -f "$cFileC" "$sFileC" fi @@ -5122,6 +5125,71 @@ print('OK') " || die "omfEmit --expressload structure validation failed" rm -f "$cElFile" "$oElFile" "$binEl" "$mapEl" "$omfEl" + # ExpressLoad + cRELOC: when the user supplies --relocs, the + # reloc-offset/length fields in the ExpressLoad header info MUST + # point at the cRELOC bytes embedded after the LCONST data — otherwise + # the Loader skips its body walk (the whole point of ExpressLoad) + # and never applies the relocations. Caught when the Loader + # silently failed to JSL into our text under bank-2 placement. + log "check: omfEmit --expressload + --relocs records cRELOC offset/length" + cElrFile="$(mktemp --suffix=.c)" + oElrFile="$(mktemp --suffix=.o)" + binElr="$(mktemp --suffix=.bin)" + mapElr="$(mktemp --suffix=.map)" + relElr="$(mktemp --suffix=.reloc)" + omfElr="$(mktemp --suffix=.omf)" + cat > "$cElrFile" <<'EOF' +__attribute__((noinline)) static int helper(int x) { return x + 1; } +void main(void) { *(volatile unsigned char *)0x70 = (unsigned char)helper(0x40); } +EOF + "$CLANG" --target=w65816 -O2 -c "$cElrFile" -o "$oElrFile" + "$PROJECT_ROOT/tools/link816" -o "$binElr" --text-base 0x1000 \ + --map "$mapElr" --reloc-out "$relElr" --no-gc-sections \ + "$PROJECT_ROOT/runtime/crt0Gsos.o" "$oElrFile" \ + "$PROJECT_ROOT/runtime/libgcc.o" >/dev/null 2>&1 + "$PROJECT_ROOT/tools/omfEmit" --input "$binElr" --map "$mapElr" \ + --base 0x1000 --entry __start --output "$omfElr" \ + --name HELLO --relocs "$relElr" --expressload >/dev/null 2>&1 + if [ ! -s "$omfElr" ]; then + die "omfEmit --expressload --relocs produced empty/missing OMF" + fi + python3 -c " +import struct, sys +b = open('$omfElr','rb').read() +r = open('$relElr','rb').read() +nRel = struct.unpack_from(' headerinfo offset +sr = struct.unpack_from(' emitOmfExpressLoad( // Header info entry for the user segment. put32(elData, userDataOff); // data offset in file put32(elData, (uint32_t)image.size()); // data length - put32(elData, 0); // reloc offset (0 = no relocs) - put32(elData, 0); // reloc length + // cRELOC opcodes (if any) are emitted by emitOneSeg directly after + // the LCONST data and before the END opcode. Tell ExpressLoad + // where they live so the Loader can apply them — without this the + // Loader skips the body walk and intra-segment IMM24 references + // (every JSL into our text) point at bank 0 even after relocation. + if (gReloc24Sites.empty()) { + put32(elData, 0); // reloc offset + put32(elData, 0); // reloc length + } else { + const uint32_t crelocBytesPerSite = 7; // 0xF5 + 1+1+2+2 + const uint32_t crelocOff = + userDataOff + (uint32_t)image.size(); + const uint32_t crelocLen = + crelocBytesPerSite * (uint32_t)gReloc24Sites.size(); + put32(elData, crelocOff); + put32(elData, crelocLen); + } // Header copy: bytes [12..43] of user segment header, DISPDATA → 0. if (userSeg.size() < HDR_SIZE) die("internal: user seg too small"); diff --git a/src/llvm/lib/Target/W65816/W65816AsmPrinter.cpp b/src/llvm/lib/Target/W65816/W65816AsmPrinter.cpp index ac07ba2..1c0a8ad 100644 --- a/src/llvm/lib/Target/W65816/W65816AsmPrinter.cpp +++ b/src/llvm/lib/Target/W65816/W65816AsmPrinter.cpp @@ -526,17 +526,23 @@ void W65816AsmPrinter::emitInstruction(const MachineInstr *MI) { EmitToStreamer(*OutStreamer, Rep); return; } - case W65816::LDA8abs: { - // i8 absolute load — same byte sequence as LDA_Abs in M=0, but - // semantically loads 1 byte not 2. Need M=1 wrap so we don't - // also pull in the byte at addr+1 (often another global, which is - // harmless to read but corrupts A_hi for any consumer that cares). + case W65816::LDA8abs: + case W65816::LDA8long: { + // i8 absolute load — same M=8 wrap as LDA_Abs; LDA8long uses + // LDA_Long (0xAF, bank-explicit) for const-int MMIO addresses. + bool IsLong = MI->getOpcode() == W65816::LDA8long; MCInst Sep; Sep.setOpcode(W65816::SEP); Sep.addOperand(MCOperand::createImm(0x20)); EmitToStreamer(*OutStreamer, Sep); MCInst Lda; - Lda.setOpcode(W65816::LDA_Abs); - Lda.addOperand(lowerOperand(MI->getOperand(1), MCInstLowering)); + Lda.setOpcode(IsLong ? W65816::LDA_Long : W65816::LDA_Abs); + MCOperand Addr = lowerOperand(MI->getOperand(1), MCInstLowering); + if (IsLong && Addr.isImm()) { + // 16-bit pointer sign-extended into i32 imm — mask back to 16 bits + // so the encoded bank byte is 0. See STA8long for the rationale. + Addr = MCOperand::createImm(Addr.getImm() & 0xFFFFu); + } + Lda.addOperand(Addr); EmitToStreamer(*OutStreamer, Lda); MCInst Rep; Rep.setOpcode(W65816::REP); Rep.addOperand(MCOperand::createImm(0x20)); diff --git a/src/llvm/lib/Target/W65816/W65816ISelLowering.cpp b/src/llvm/lib/Target/W65816/W65816ISelLowering.cpp index dccda7a..5bc2a9f 100644 --- a/src/llvm/lib/Target/W65816/W65816ISelLowering.cpp +++ b/src/llvm/lib/Target/W65816/W65816ISelLowering.cpp @@ -1199,9 +1199,8 @@ W65816TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, // then accesses via [$E0],Y with Y=0. We can't fold into Y // because [dp],Y on the W65816 adds Y to the full 24-bit pointer // — for a negative Y like 0xFFFE (= -2 signed), the addition - // crosses into bank 1 (e.g. ptr=0x4000 + Y=0xFFFE → 0x13FFE). - // Folding into the pointer keeps the add at 16-bit (in A) so the - // bank byte stays 0. + // crosses into bank 1. Folding into the pointer keeps the add + // at 16-bit (in A) so the bank byte stays 0. // // DBR-independent — see LDAptr/STAptr/STBptr. MachineFunction *MF = BB->getParent(); @@ -1267,16 +1266,24 @@ W65816TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, // LDY #0 // LDA [$E0], Y ; bank 0:ptr + 0 // STA [$E0], Y - // The bank byte is forced to 0, so the access ignores DBR — the - // whole point. The previous lowering used (slot,S),Y indirect - // (opcode 0x91 / 0x93), but (sr,s),Y is DBR-relative — when the - // caller had set DBR != 0 (e.g. via `pha;plb` to bank 2 to reach - // IIgs hardware), the deref silently wrote to the wrong bank. + // Bank-explicit ZERO — DBR-independent. Both the runInMame stack + // ($00:0FFF down) and BSS / heap globals (placed at $00:xxxx) live + // in bank 0, so pointer-derefs always reach the right memory even + // when the user has switched DBR for a bank-2 store via `pha;plb`. + // + // Trade-off: under GS/OS Loader the user's data lives in their bank + // (not bank 0), so library functions that write directly to globals + // via `sta abs` (DBR-relative, lands in user bank) and user code that + // reads via pointer-deref (lands in bank 0 by this lowering) get + // INCONSISTENT results — silent miscompile. gmtime hit this with + // its __gmtimeBuf static. Workaround for affected library code: + // launder the buffer pointer through inline asm (see gmtime in + // runtime/src/timeExt.c) so clang doesn't IPSCCP-fold it; the writes + // then go via [dp],Y too and match the user reads. // // Const-int pointers (`*(volatile uint16 *)0x5000 = v`) are NOT - // lowered through this pseudo — there's a TableGen pattern that - // takes them straight to STAabs (DBR-relative), which preserves - // the IIgs MMIO + bank-switch idiom that the smoke tests use. + // lowered through this pseudo — TableGen patterns route them to + // STAlong / STA8long / STAabs by type. See InstrInfo.td. // // We use $E0..$E2 in libcall-scratch DP — safe because the // pseudo expansion is a leaf (no calls between SEP and STA), @@ -1319,8 +1326,6 @@ W65816TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, BuildMI(*BB, MI.getIterator(), DL, TII.get(W65816::STA_DP)).addImm(0xE0); - // Bank byte at $E2 = 0. STZ in M=16 writes 2 bytes ($E2..$E3); - // $E3 is junk-clobbered, OK (libcall scratch is caller-saved). BuildMI(*BB, MI.getIterator(), DL, TII.get(W65816::STZ_DP)).addImm(0xE2); @@ -1334,7 +1339,6 @@ W65816TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, TII.get(TargetOpcode::COPY), Dst).addReg(W65816::A); } else { Register Val = MI.getOperand(0).getReg(); - // Load val into A. BuildMI(*BB, MI.getIterator(), DL, TII.get(TargetOpcode::COPY), W65816::A).addReg(Val); BuildMI(*BB, MI.getIterator(), DL, diff --git a/src/llvm/lib/Target/W65816/W65816InstrInfo.td b/src/llvm/lib/Target/W65816/W65816InstrInfo.td index e067f21..14fe38c 100644 --- a/src/llvm/lib/Target/W65816/W65816InstrInfo.td +++ b/src/llvm/lib/Target/W65816/W65816InstrInfo.td @@ -243,6 +243,13 @@ def EORi8imm : W65816Pseudo<(outs Acc8:$dst), let mayLoad = 1, hasSideEffects = 0, mayStore = 0 in { def LDA8abs : W65816Pseudo<(outs Acc8:$dst), (ins i32imm:$addr), "# LDA8abs $dst, $addr", []>; +// LDA8long: companion to STA8long. Bank-explicit i8 load via LDA_Long +// (0xAF). Used for `*(uint8*)0xC035` reads — LDA_Abs (0xAD) is +// DBR-relative and would land in the wrong bank under GS/OS Loader. +// Pattern that ROUTES const-int loads here lives at the ANDi16imm +// section (must appear after ANDi16imm is defined). +def LDA8long : W65816Pseudo<(outs Acc8:$dst), (ins i32imm:$addr), + "# LDA8long $dst, $addr", []>; } let mayStore = 1, hasSideEffects = 0, mayLoad = 0 in { def STA8abs : W65816Pseudo<(outs), (ins Acc8:$src, i32imm:$addr), @@ -567,6 +574,25 @@ def EORi16imm : W65816Pseudo<(outs Acc16:$dst), [(set Acc16:$dst, (xor Acc16:$src, imm:$imm))]>; } + +// Bank-explicit i8 loads from a constant-int address (`*(uint8*)0xC035`). +// The default lowering goes through LDAptr ([dp],Y indirect-long) — 22 B / +// 35 cyc — because LDAptr's pattern `(load Wide16:$ptr)` matches once the +// matcher materialises the const into Wide16. These patterns shortcut to +// LDA8long (sta long, 0xAF, 6 B / 10 cyc) and run BEFORE that materialisation +// because the explicit imm leaf has higher AddedComplexity. Only the +// `(zextloadi8 imm)` form actually appears in real IR (i8 loads are +// always i16-extended at SDAG time on this 16-bit target); kept the +// raw `(load imm)` form too for symmetry with the store side. +let AddedComplexity = 50 in { +def : Pat<(i8 (load (iPTR imm:$addr))), + (LDA8long (i32 imm:$addr))>; +def : Pat<(i16 (zextloadi8 (iPTR imm:$addr))), + (ANDi16imm (COPY_TO_REGCLASS (LDA8long (i32 imm:$addr)), Acc16), + 0xFF)>; +def : Pat<(i16 (extloadi8 (iPTR imm:$addr))), + (COPY_TO_REGCLASS (LDA8long (i32 imm:$addr)), Acc16)>; +} let Constraints = "$src = $dst", hasSideEffects = 0, mayLoad = 1, mayStore = 0 in { def ANDabs : W65816Pseudo<(outs Acc16:$dst),