1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
; =============================================================================
; programs.asm - userland program images (text-in-ROM model) + the shell.
;
; Programs are linked to run from the ROMX window ($4000-$7FFF) and live in
; their own ROM banks. exec() maps the bank and jumps in. Programs talk to the
; kernel only via `rst $30`.
; =============================================================================
INCLUDE "include/gbos.inc"
; the shell keeps its line buffer + scratch at the bottom of its RAM bank
DEF SH_LINEBUF EQU $A000 ; up to 32 bytes
DEF SH_PROGID EQU $A040 ; chosen program id (survives fork via bank copy)
DEF SH_MAXLINE EQU 32
; -----------------------------------------------------------------------------
; PROG_WORKER (bank 2) - print a line, exit(0).
; -----------------------------------------------------------------------------
SECTION "prog_worker", ROMX[$4000], BANK[2]
ProgWorker:
ld de, .msg
ld b, .msgend - .msg
ld c, SYS_WRITE
rst $30
ld b, 0
ld c, SYS_EXIT
rst $30
.msg
db "worker!", $0D, $0A
.msgend
; -----------------------------------------------------------------------------
; PROG_HELLO (bank 4) - print a line, exit(0).
; -----------------------------------------------------------------------------
SECTION "prog_hello", ROMX[$4000], BANK[4]
ProgHello:
ld de, .msg
ld b, .msgend - .msg
ld c, SYS_WRITE
rst $30
ld b, 0
ld c, SYS_EXIT
rst $30
.msg
db "hello world!", $0D, $0A
.msgend
; -----------------------------------------------------------------------------
; PROG_CHELLO (bank 5) - a program written in C, compiled with SDCC to a
; self-contained ROM-bank image (crt0 + libc + code) and included verbatim.
; Rebuild with: sh c/build.sh c/chello.c c/chello.bin
; -----------------------------------------------------------------------------
SECTION "prog_chello", ROMX[$4000], BANK[5]
ProgChello:
INCBIN "c/chello.bin"
SECTION "prog_echo", ROMX[$4000], BANK[6]
ProgEcho:
INCBIN "c/echo.bin"
SECTION "prog_true", ROMX[$4000], BANK[7]
ProgTrue:
INCBIN "c/true.bin"
SECTION "prog_false", ROMX[$4000], BANK[8]
ProgFalse:
INCBIN "c/false.bin"
SECTION "prog_uname", ROMX[$4000], BANK[9]
ProgUname:
INCBIN "c/uname.bin"
SECTION "prog_pid", ROMX[$4000], BANK[10]
ProgPid:
INCBIN "c/pid.bin"
SECTION "prog_cat", ROMX[$4000], BANK[11]
ProgCat:
INCBIN "c/cat.bin"
SECTION "prog_wc", ROMX[$4000], BANK[12]
ProgWc:
INCBIN "c/wc.bin"
SECTION "prog_head", ROMX[$4000], BANK[13]
ProgHead:
INCBIN "c/head.bin"
SECTION "prog_args", ROMX[$4000], BANK[14]
ProgArgs:
INCBIN "c/args.bin"
SECTION "prog_ls", ROMX[$4000], BANK[15]
ProgLs:
INCBIN "c/ls.bin"
SECTION "prog_save", ROMX[$4000], BANK[16]
ProgSave:
INCBIN "c/save.bin"
SECTION "prog_rm", ROMX[$4000], BANK[17]
ProgRm:
INCBIN "c/rm.bin"
SECTION "prog_ps", ROMX[$4000], BANK[18]
ProgPs:
INCBIN "c/ps.bin"
SECTION "prog_kill", ROMX[$4000], BANK[19]
ProgKill:
INCBIN "c/kill.bin"
SECTION "prog_spin", ROMX[$4000], BANK[20]
ProgSpin:
INCBIN "c/spin.bin"
; -----------------------------------------------------------------------------
; PROG_SH (bank 3) - the shell, now written in C (c/sh.c): parses >/</| and
; drives fork+exec+wait with I/O redirection. Command lookup + StrEqual/SkipName
; live in the kernel now (sys_lookup + NameTable + shell_lib).
; -----------------------------------------------------------------------------
SECTION "prog_sh", ROMX[$4000], BANK[3]
ProgSh:
INCBIN "c/sh.bin"
; -----------------------------------------------------------------------------
; Shell string helpers (ROM0, always mapped).
; -----------------------------------------------------------------------------
SECTION "shell_lib", ROM0
; StrEqual(HL, DE) - compare NUL-terminated strings. Z set if equal.
; Clobbers A, B; advances HL and DE.
StrEqual::
.l
ld a, [de]
ld b, a
ld a, [hl]
cp b
ret nz
or a
ret z ; both NUL -> equal
inc hl
inc de
jr .l
; SkipName(DE) - advance DE to its NUL terminator.
SkipName::
.l
ld a, [de]
or a
ret z
inc de
jr .l
; -----------------------------------------------------------------------------
; Program table (ROM0). Index = program id. Entry: bank (2) + entry addr (2).
; -----------------------------------------------------------------------------
SECTION "progtab", ROM0
ProgramTable::
db LOW(BANK(ProgWorker)), HIGH(BANK(ProgWorker))
dw ProgWorker
db LOW(BANK(ProgSh)), HIGH(BANK(ProgSh))
dw ProgSh
db LOW(BANK(ProgHello)), HIGH(BANK(ProgHello))
dw ProgHello
db LOW(BANK(ProgChello)), HIGH(BANK(ProgChello))
dw ProgChello
db LOW(BANK(ProgEcho)), HIGH(BANK(ProgEcho))
dw ProgEcho
db LOW(BANK(ProgTrue)), HIGH(BANK(ProgTrue))
dw ProgTrue
db LOW(BANK(ProgFalse)), HIGH(BANK(ProgFalse))
dw ProgFalse
db LOW(BANK(ProgUname)), HIGH(BANK(ProgUname))
dw ProgUname
db LOW(BANK(ProgPid)), HIGH(BANK(ProgPid))
dw ProgPid
db LOW(BANK(ProgCat)), HIGH(BANK(ProgCat))
dw ProgCat
db LOW(BANK(ProgWc)), HIGH(BANK(ProgWc))
dw ProgWc
db LOW(BANK(ProgHead)), HIGH(BANK(ProgHead))
dw ProgHead
db LOW(BANK(ProgArgs)), HIGH(BANK(ProgArgs))
dw ProgArgs
db LOW(BANK(ProgLs)), HIGH(BANK(ProgLs))
dw ProgLs
db LOW(BANK(ProgSave)), HIGH(BANK(ProgSave))
dw ProgSave
db LOW(BANK(ProgRm)), HIGH(BANK(ProgRm))
dw ProgRm
db LOW(BANK(ProgPs)), HIGH(BANK(ProgPs))
dw ProgPs
db LOW(BANK(ProgKill)), HIGH(BANK(ProgKill))
dw ProgKill
db LOW(BANK(ProgSpin)), HIGH(BANK(ProgSpin))
dw ProgSpin
; -----------------------------------------------------------------------------
; NameTable (ROM0) - command name -> program id, searched by sys_lookup.
; -----------------------------------------------------------------------------
SECTION "nametab", ROM0
NameTable::
db "worker", 0
db PROG_WORKER
db "hello", 0
db PROG_HELLO
db "chello", 0
db PROG_CHELLO
db "echo", 0
db PROG_ECHO
db "true", 0
db PROG_TRUE
db "false", 0
db PROG_FALSE
db "uname", 0
db PROG_UNAME
db "pid", 0
db PROG_PID
db "cat", 0
db PROG_CAT
db "wc", 0
db PROG_WC
db "head", 0
db PROG_HEAD
db "args", 0
db PROG_ARGS
db "ls", 0
db PROG_LS
db "save", 0
db PROG_SAVE
db "rm", 0
db PROG_RM
db "sh", 0
db PROG_SH
db "ps", 0
db PROG_PS
db "kill", 0
db PROG_KILL
db "spin", 0
db PROG_SPIN
db 0
|