Checkpoint

This commit is contained in:
Scott Duensing 2026-05-04 01:28:27 -05:00
parent dc2505c4af
commit 05fc37d323
9 changed files with 239 additions and 392 deletions

View file

@ -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.

View file

@ -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

View file

@ -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) {

View file

@ -306,8 +306,12 @@ 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
if argInfo:
sLines.append(f"\t; --- stash arg0 (in A{'/X' if firstArgIs32 else ''}) ---")
sLines.append(f"\tsta 0x{scratchDP:02X}")
if firstArgIs32:
@ -325,7 +329,8 @@ 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.
# arg0 first (if any args).
if argInfo:
sLines.append(f"\t; --- arg0 ---")
sLines.append(f"\tlda 0x{scratchDP:02X}")
sLines.append(f"\tpha")

View file

@ -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('<I', r, 0)[0]
seg1_bytecnt = struct.unpack_from('<I', b, 0)[0]
el_data_start = 0x48 # ExpressLoad LCONST data start (header bytes 0..0x47)
# Segment table entry 0 -> headerinfo offset
sr = struct.unpack_from('<H', b, el_data_start + 6)[0]
hdrinfo_off = el_data_start + 6 + sr
reloc_off = struct.unpack_from('<I', b, hdrinfo_off + 8)[0]
reloc_len = struct.unpack_from('<I', b, hdrinfo_off + 12)[0]
expected_len = 7 * nRel # 7 bytes per cRELOC opcode
if nRel == 0:
print(f'FAIL: expected reloc sites in test program'); sys.exit(1)
if reloc_off == 0 or reloc_len == 0:
print(f'FAIL: ExpressLoad reloc fields zero — Loader will skip relocs'); sys.exit(1)
if reloc_len != expected_len:
print(f'FAIL: reloc_len {reloc_len} != expected {expected_len} ({nRel} sites)'); sys.exit(1)
# Verify the bytes at reloc_off start with 0xF5 (cRELOC opcode).
if b[reloc_off] != 0xF5:
print(f'FAIL: byte at reloc_off {reloc_off:#x} = {b[reloc_off]:#x} != 0xF5'); sys.exit(1)
print(f'OK: ExpressLoad header points at {nRel} cRELOC sites')
" || die "ExpressLoad reloc-table validation failed"
rm -f "$cElrFile" "$oElrFile" "$binElr" "$mapElr" "$relElr" "$omfElr"
# Toolbox void-arg generator must NOT push a phantom arg0. Earlier
# GetTick() (tool 0x2503, void return-2-words void-args) shipped
# with `pha` of garbage A; under GS/OS Loader the corrupted stack
# frame caused the dispatcher to return into bad code, hanging the
# program before main reached its sentinel store.
log "check: genToolbox emits no phantom arg0 push for void-arg routines"
if grep -A 2 "^GetTick:" "$PROJECT_ROOT/runtime/src/iigsToolbox.s" | \
grep -q "stash arg0"; then
die "GetTick has 'stash arg0' but takes no args (regenerate iigsToolbox.s)"
fi
# link816 --reloc-out + omfEmit --relocs round-trip: emit IMM24
# site list, decode it, verify cRELOC opcodes appear at the end of
# the OMF body. This is the mechanism that makes compiled C

View file

@ -339,8 +339,23 @@ static std::vector<uint8_t> 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)
// 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");

View file

@ -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));

View file

@ -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,

View file

@ -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),