A couple thoughts. First, shell assembly programs that can also be run from the homescreen should not show up on the PRGM menu at all. They can be kept as AppVars all the time. Similarly, using programs as data files should also be deprecated. Thus, we can reserve the PRGM menu for programs that can actually be run from the homescreen.
Second, instead of using the regular assembly header, we can use a different header. I propose starting with D3 3F, which is the BASIC Return token followed by a newline. Thus, even if the shell-based program appears as a regular program, attempting to run a it with either do nothing or throw an error.
Third, it would be nice to include more metadata and bigger icons. Both these use more space. And we have lots more archive space! But we need not copy any metadata into RAM when we run the program, so the .org should specify the start of executable code, not metadata, as the start of the program.
Fourth, tr1p1ea has some idea about screen modes and color modes. But, aside from BGR mode and 16-/18-/fake 24-bit color modes, the LCD controller has no modes, so it's kind of a moot point. Icons and other basic graphics that don't need fancy color depth might use a standard 4-bit palette to save space.
Finally, in regard to the above comments on dynamic memory allocation: DMA is often see as unwieldy on the Z80. However, it could be done by having programs include relocating information in their header and different segments for Code, Initalized Data, and Uninitalized Data. And as long as we make programs relocatable, we might as well include multitasking.
Code: ; Metadata format: The high four bits are the ID, the low 12 bits are the length.
; If the high bit is set, it's a shell-specific or program-specific field.
; Strings are standard ASCII, zero-terminated, and shall never exceed 252 characters in length.
; The normal metadata format is
; .db lengthLow
; .db lengthHigh | mdFieldId
; So do something like
; ld e, (hl) \ inc hl \ ld d, (hl) \ dec hl \ ld a, d \ and mdFieldIdMask
; to get the field type. If it's not the field you want,
; ld a, d \ and ~mdFieldIdMask \ ex de, hl \ add hl, de
; will skip to the next field.
; This metadata format can also be used for data files. Now, isn't that nice?
; If a metadata field type appears more than once, it means the field has more than one value.
; For example, a program could have more than one author.
; Although, for some fields, like PrettyName, you might simply only display the first field found.
; Or, multiple fields could specify different languages in a shell-specific manner.
; Finally, if you want icons for data files,
; it's probably a good idea to use ShellType to identify the file type and icon,
; rather than including an icon in every file.
mdFieldIdMask equ 0F000h
mdMetatdataField equ 00h
; The metadata block MUST end with mdNoMoreField, i.e. .db 2, 0
mdNoMoreFields equ 0
mdNoMoreFieldsSize equ 2
; Shell type is the only REQUIRED field.
; It MUST be at least one byte, but may be up to 253 bytes.
; This field can used not only to identify a specific shell,
; it can also identify what type a data file is.
; In other words, for data files, it may also contain information for launching an editor.
mdShellType equ 10h
mdShellTypeLength equ 3
mdPrettyName equ 20h
mdPrettyNameLength equ 2
mdDescription equ 30h
mdDescriptionLength equ 2
mdAuthor equ 40h
mdAuthorLength equ 2
mdVersion equ 50h
mdVersionLength equ 2
mdOtherMetadata equ 60h
mdOtherMetadataLength equ 3
mdIcon equ 70h
mdIconLength equ 4
mdShellSpecific equ 80h
; Standard fout-bit palette for basic graphics
; The shell routines that render anything using this palette not be particularly fast.
stdBlack equ 0
stdRed equ 1
stdGreen equ 2
stdBlue equ 4
stdYellow equ (stdRed | stdGreen)
stdMagenta equ (stdRed | stdBlue)
stdCyan equ (stdGreen | stdBlue)
stdGray equ (stdReg | stdGreen | stdBlue)
stdBrightColor equ 8
stdTransparent equ 8 ; Who needs two shades of gray?
stdPink equ (stdBrightColor | stdRed)
stdLightGreen equ (stdBrightColor | stdGreen)
stdLightBlue equ (stdBrightColor | stdBlue)
stdLightYellow equ (stdBrightColor | stdYellow)
stdLightMagenta equ (stdBrightColor | stdMagenta)
stdLightCyan equ (stdBrightColor | stdCyan)
stdWhite equ (stdBrightColor | stdWhite)
HstdBlack equ 0
HstdRed equ (stdRed << 4)
HstdGreen equ (stdGreen << 4)
HstdBlue equ (stdBlue << 4)
HstdYellow equ (stdYellow << 4)
HstdMagenta equ (stdMagenta << 4)
HstdCyan equ (stdCyan << 4)
HstdGray equ (stdGray << 4)
HstdTransparent equ (stdTransparent << 4)
HstdPink equ (stdPink << 4)
HstdLightGreen equ (stdLightGreen << 4)
HstdLightBlue equ (stdLightBlue << 4)
HstdLightYellow equ (stdLightYellow << 4)
HstdLightMagenta equ (stdLightMagenta << 4)
HstdLightCyan equ (stdLightCyan << 4)
HstdWhite equ (stdWhite << 4)
.org userMem - (MainEntryPoint - MetaData)
MetaData:
.db tStop, tNewline
.dw metadataLength
; The shell should parse these fields and allow them to appear in any order.
.db mdShellTypeLength
.db mdShellType
.db mdShellTypeId ; Actual shell ID, e.g. MirageOS or whatever
.db mdPrettyNameLength + _++ - _+
.db mdPrettyName
_: .db "Tetris", 0
_:
.db mdScriptionLength + _++ - _+
.db mdDescription
_: .db "A classic game!", 0
_:
.db mdAuthorLength + _++ - _+
.db mdAuthor
_: .db "DrDnar", 0
_:
; Maybe I'm too lazy to supply a version
; If a metadata field is not supplied, programs should intelligently
; simply consider the field null, instead of behaving strangely.
; WORST ICON EVER
myIconSize = myIconEnd - myIconStart
myIconHeight = 4
myIconWidth = 4
myIconStart:
.db mdIcon | (myIconSize >> 8)
.db myIconSize & 0FFh
.db ((myIconHeight / 4) << 4) | (myIconWidth / 4)
.db HstdGray | stdGray, HstdGray | stdGray, HstdGray | stdGray, HstdGray | stdGray
.db HstdGray | stdGray, HstdGray | stdGray, HstdGray | stdGray, HstdGray | stdGray
.db HstdGray | stdGray, HstdGray | stdGray, HstdGray | stdGray, HstdGray | stdGray
.db HstdGray | stdGray, HstdGray | stdGray, HstdGray | stdGray, HstdGray | stdGray
myIconEnd:
.db mdNoMoreFieldsLength
.db mdNoMoreFields
; END OF METADATA
MainEntryPoint:
; Your program actually begins here