The following text is an assembler listing generated with AS V1.41 from Alfred Arnold. AS is an easily customizable cross assembler for many systems to which I have added a code generator for the PALM processor.
This program should be a small demonstration of the machine. Several obstacles
(walls) are created on the screen. A ball bounces within the screen boundaries
and reflects either at one of the screen borders or at a wall. Each collision
will be accompanied with a short sound. This program is loaded like any other
machine program with LINK or )LINK. The load address is fixed to $0B00. The
program is held as simple as possible so it's not using sophisticated
algorithms.
Source code and binary in downloadable form will be found on these pages
later.
1/ 0 : ; ***********************************************************
2/ 0 : ;
3/ 0 : ; Moves a "ball" within the screen boundaries. In addition
4/ 0 : ; some walls as obstacles are added.
5/ 0 : ;
6/ 0 : ; ***********************************************************
7/ 0 :
8/ 0 : cpu IBM5110
9/ 0 :
10/ 0 : include "ebcdic.inc"
11/ 0 :
12/ B00 : org $0B00
13/ B00 :
14/ B00 : Start:
15/ B00 : ; Set processor state
16/ B00 : 2152 MOVE R1, $A4
17/ B02 : DF01 0CCE LWI R15, #Status_Save
18/ B06 : 51F8 MOVE (R15), R1
19/ B08 :
20/ B08 : 021C MHL R2, R1
21/ B0A : 9204 CLR R2, #$04
22/ B0C : B201 SET R2, #$01
23/ B0E : 012D MLH R1, R2
24/ B10 : 3152 MOVE $A4, R1
25/ B12 :
26/ B12 : 1077 CTRL $0, #$77 ; turn screen on
27/ B14 :
28/ B14 : Main:
29/ B14 :
30/ B14 : =$400 SCREENSIZE equ 16*64
31/ B14 :
32/ B14 : 0203 D021 0B66 CALL ClrScr, R2
33/ B1A : 0203 D021 0B7E CALL BuildWalls, R2
34/ B20 :
35/ B20 : 2150 MOVE R1, $A0
36/ B22 : D201 0CC8 LWI R2, #XPos
37/ B26 : 8111 LBI R1, #17
38/ B28 : 5121 MOVE (R2)+, R1 ; XPos
39/ B2A : 8103 LBI R1, #3
40/ B2C : 5121 MOVE (R2)+, R1 ; YPos
41/ B2E : 8111 LBI R1, #$11
42/ B30 : 5128 MOVE (R2), R1 ; direction
43/ B32 :
44/ B32 : Loop:
45/ B32 : D701 0200 LWI R7, #$0200
46/ B36 :
47/ B36 : ; Calculate a screen address from line and column
48/ B36 : D401 0CCA LWI R4, #YPos
49/ B3A : D345 MOVE R3, (R4)-
50/ B3C : C30B SNZ R3
51/ B3E : A007 BRA l2
52/ B40 : A73F l1: ADD R7, #64
53/ B42 : 0331 DEC R3, R3
54/ B44 : C303 SZ R3
55/ B46 : F007 BRA l1
56/ B48 :
57/ B48 : D347 l2: MOVE R3, (R4)--
58/ B4A : 0738 ADD R7, R3
59/ B4C :
60/ B4C : D341 MOVE R3, (R4)+
61/ B4E :
62/ B4E : 6678 MOVB R6, (R7) ; save contents of prev. location
63/ B50 : 7378 MOVB (R7), R3 ; writes "ball" into location
64/ B52 :
65/ B52 : 0203 D021 0BD6 CALL Delay, R2
66/ B58 : 0203 D021 0BE6 CALL CalcNewPos, R2
67/ B5E :
68/ B5E : ;
69/ B5E : ;
70/ B5E : 7678 MOVB (R7), R6 ; restore prev. location
71/ B60 :
72/ B60 : F02F BRA Loop
73/ B62 :
74/ B62 : D001 0CAA JMP Ende
75/ B66 :
76/ B66 : ; ********
As the name suggests this routine clears the screen. This is done by writing blanks into locations $0200 to $05FF.
77/ B66 :
78/ B66 : ClrScr:
79/ B66 : D501 0200 LWI R5, #$0200
80/ B6A : D601 0400 LWI R6, #SCREENSIZE
81/ B6E : 8740 LBI R7, #' '
82/ B70 : 7750 cs_1: MOVB (R5)+, R7
83/ B72 : 0661 DEC R6, R6
84/ B74 : 086C MHL R8, R6
85/ B76 : 0866 OR R8, R6
86/ B78 : C803 SZ R8
87/ B7A : F00B BRA cs_1
88/ B7C : 0024 RET R2
89/ B7E :
90/ B7E : ; ********
The routine BuildWalls creates some "walls". Position and size are hard coded, the character $FF is taken as brick element (filled character).
91/ B7E :
92/ B7E : BuildWalls:
93/ B7E : D501 04CA LWI R5, #$0200+(11*64)+10
94/ B82 : 8605 LBI R6, #5
95/ B84 : D701 FFFF LWI R7, #$FFFF
96/ B88 :
97/ B88 : 5758 bw_1: MOVE (R5), R7
98/ B8A : F600 SUB R6, #1
99/ B8C : C60B SNZ R6
100/ B8E : A003 BRA bw_2
101/ B90 : A53F ADD R5, #64
102/ B92 : F00B BRA bw_1
103/ B94 :
104/ B94 : D501 02B2 bw_2: LWI R5, #$0200+(2*64)+50
105/ B98 : 8603 LBI R6, #3
106/ B9A : 5758 bw_4: MOVE (R5), R7
107/ B9C : F600 SUB R6, #1
108/ B9E : C60B SNZ R6
109/ BA0 : A003 BRA bw_5
110/ BA2 : A53F ADD R5, #64
111/ BA4 : F00B BRA bw_4
112/ BA6 :
113/ BA6 : D501 031E bw_5: LWI R5, #$0200+(4*64)+30
114/ BAA : 8608 LBI R6, #8
115/ BAC : 5758 bw_6: MOVE (R5), R7
116/ BAE : F600 SUB R6, #1
117/ BB0 : C60B SNZ R6
118/ BB2 : A003 BRA bw_7
119/ BB4 : A53F ADD R5, #64
120/ BB6 : F00B BRA bw_6
121/ BB8 :
122/ BB8 : D501 0526 bw_7: LWI R5, #$0200+(12*64)+38
123/ BBC : 8604 LBI R6, #4
124/ BBE : 5751 bw_8: MOVE (R5)+, R7
125/ BC0 : F600 SUB R6, #1
126/ BC2 : C603 SZ R6
127/ BC4 : F007 BRA bw_8
128/ BC6 :
129/ BC6 : D501 0414 bw_9: LWI R5, #$0200+(8*64)+20
130/ BCA : 8603 LBI R6, #3
131/ BCC : 5751 bw_10: MOVE (R5)+, R7
132/ BCE : F600 SUB R6, #1
133/ BD0 : C603 SZ R6
134/ BD2 : F007 BRA bw_10
135/ BD4 :
136/ BD4 : 0024 bw_99: RET R2
137/ BD6 :
138/ BD6 : ; ********
Delay is called after each new ball position to prevent the ball from moving too fast over the screen. The delay value has been determined manually.
139/ BD6 :
140/ BD6 : Delay:
141/ BD6 : DF01 0BB8 LWI R15, #3000
142/ BDA : FF00 del_1: SUB R15, #1
143/ BDC : 0EFC MHL R14, R15
144/ BDE : 0EF6 OR R14, R15
145/ BE0 : CE03 SZ R14
146/ BE2 : F009 BRA del_1
147/ BE4 : 0024 RET R2
148/ BE6 :
149/ BE6 : ; ********
CalcNewPos calculates the next position of the ball. Along with the current moving direction (var. "Richt") a collision either with a screen border or with a wall is taken into account. In case of a collision the "Sound" routine will be called. Several collision may occur e.g. when the ball flies into a corner.
150/ BE6 :
151/ BE6 : CalcNewPos:
152/ BE6 : D501 0CCC LWI R5, #Richt
153/ BEA : DF58 MOVE R15, (R5)
154/ BEC :
155/ BEC : ; X-Position
156/ BEC :
157/ BEC : D501 0CC8 LWI R5, #XPos
158/ BF0 : DA58 MOVE R10, (R5)
159/ BF2 : 0DA4 MOVE R13, R10 ; store old X-pos.
160/ BF4 : 8310 LBI R3, #$10
161/ BF6 : CF3D SNBS R15, R3
162/ BF8 : A011 BRA cnp1
163/ BFA :
164/ BFA : AA00 ADD R10, #1
165/ BFC : 8C3F LBI R12, #63
166/ BFE : CAC9 SGE R10, R12
167/ C00 : A017 BRA cnp2
168/ C02 : BF10 SET R15, #$10
169/ C04 : 0803 D081 0C9C CALL Sound, R8
170/ C0A : A00D BRA cnp2
171/ C0C :
172/ C0C : FA00 cnp1: SUB R10, #1
173/ C0E : CA03 SZ R10
174/ C10 : A007 BRA cnp2
175/ C12 : 9F10 CLR R15, #$10
176/ C14 : 0803 D081 0C9C CALL Sound, R8
177/ C1A :
178/ C1A : cnp2:
179/ C1A : ; Check if ball touched the side of a wall
180/ C1A : CAD8 SGT R10, R13
181/ C1C : A003 BRA cnp2_1
182/ C1E : 0E72 INC R14, R7
183/ C20 : A001 BRA cnp2_2
184/ C22 : 0E71 cnp2_1: DEC R14, R7
185/ C24 : cnp2_2:
186/ C24 : 68E8 MOVB R8, (R14)
187/ C26 : 89FF LBI R9, #$FF
188/ C28 : C892 SE R8, R9
189/ C2A : A00D BRA cnp2_3
190/ C2C :
191/ C2C : ; Collision with wall
192/ C2C : 0AD4 MOVE R10, R13 ; return to old X-pos.
193/ C2E : 8910 LBI R9, #$10
194/ C30 : 0F97 XOR R15, R9 ; reverse X direction
195/ C32 : 0803 D081 0C9C CALL Sound, R8
196/ C38 : A059 BRA cnp5 ; keep Y-pos.
197/ C3A :
198/ C3A : 5A58 cnp2_3: MOVE (R5), R10
199/ C3C :
200/ C3C :
201/ C3C :
202/ C3C : ; Y-Position
203/ C3C :
204/ C3C : D501 0CCA LWI R5, #YPos
205/ C40 : DA58 MOVE R10, (R5)
206/ C42 : 8301 LBI R3, #$01
207/ C44 : CF3D SNBS R15, R3
208/ C46 : A011 BRA cnp3
209/ C48 :
210/ C48 : AA00 ADD R10, #1
211/ C4A : 8C0F LBI R12, #15
212/ C4C : CAC9 SGE R10, R12
213/ C4E : A017 BRA cnp4
214/ C50 : BF01 SET R15, #$01
215/ C52 : 0803 D081 0C9C CALL Sound, R8
216/ C58 : A00D BRA cnp4
217/ C5A :
218/ C5A : FA00 cnp3: SUB R10, #1
219/ C5C : CA03 SZ R10
220/ C5E : A007 BRA cnp4
221/ C60 : 9F01 CLR R15, #$01
222/ C62 : 0803 D081 0C9C CALL Sound, R8
223/ C68 :
224/ C68 : cnp4:
225/ C68 : ; Check if ball touched the top or bottom of a wall
226/ C68 : DB58 MOVE R11, (R5) ; store old Y-pos.
227/ C6A : CAB8 SGT R10, R11
228/ C6C : A003 BRA cnp4_1
229/ C6E : AE3F ADD R14, #64
230/ C70 : A001 BRA cnp4_2
231/ C72 : FE3F cnp4_1: SUB R14, #64
232/ C74 : cnp4_2:
233/ C74 : 68E8 MOVB R8, (R14)
234/ C76 : 89FF LBI R9, #$FF
235/ C78 : C892 SE R8, R9
236/ C7A : A015 BRA cnp4_3
237/ C7C :
238/ C7C : ; Collision with wall
239/ C7C : D501 0CC8 LWI R5, #XPos
240/ C80 : 5D58 MOVE (R5), R13 ; return to old X-pos.
241/ C82 : D501 0CCA LWI R5, #YPos
242/ C86 : 0AB4 MOVE R10, R11 ; return to old Y-pos.
243/ C88 : 8901 LBI R9, #$01
244/ C8A : 0F97 XOR R15, R9 ; reverse Y direction
245/ C8C : 0803 D081 0C9C CALL Sound, R8
246/ C92 :
247/ C92 : 5A58 cnp4_3: MOVE (R5), R10
248/ C94 :
249/ C94 :
250/ C94 : D501 0CCC cnp5: LWI R5, #Richt
251/ C98 : 5F58 MOVE (R5), R15
252/ C9A :
253/ C9A : 0024 RET R2
254/ C9C :
255/ C9C : ; ********
As the IBM 5110 has only a piezo beeper the only way of effectfully varying the tone is changing its duration. The 255 loop iterations used here just make a short "plick" sound (don't know how to call it). I haven't been successful in varying the frequency of the sound.
256/ C9C :
257/ C9C : Sound:
258/ C9C : 89FF LBI R9, #255
259/ C9E : 107E CTRL $0, #$7E
260/ CA0 : F900 snd1: SUB R9, #1
261/ CA2 : C903 SZ R9
262/ CA4 : F005 BRA snd1
263/ CA6 : 107D CTRL $0, #$7D
264/ CA8 :
265/ CA8 : 0084 RET R8
266/ CAA :
267/ CAA : ; ********
This point of the program will never be reached but it shows how a machine program can return to the interpreter.
268/ CAA :
269/ CAA : Ende:
270/ CAA : ; restore processor status
271/ CAA : DF01 0CCE LWI R15, #Status_Save
272/ CAE : D1F8 MOVE R1, (R15)
273/ CB0 : 3152 MOVE $A4, R1
274/ CB2 :
275/ CB2 : ; select APL- or BASIC-ROS
276/ CB2 : 28FC MOVE R8, $1F8
277/ CB4 : 8220 LBI R2, #$20
278/ CB6 : C82E SNBC R8, R2
279/ CB8 : 1104 CTRL $1, #$04 ; select APL-ROS
280/ CBA :
281/ CBA : 28E7 MOVE R8, $1CE
282/ CBC : 3868 MOVE $D0, R8
283/ CBE :
284/ CBE : ; jump back to the interpreter
285/ CBE : 2867 MOVE R8, $CE
286/ CC0 : 0880 DEC2 R8, R8
287/ CC2 : 2056 JMP ($AC)
This is the data area. "XPos" and "YPos" give the starting location of the ball in screen coordinates. "Ball" contains the screen character of the ball. "Richt" stores the current direction of the ball movement.
288/ CC4 :
289/ CC4 : 00 FD Ball: dw $FD
290/ CC6 : 00 40 Blank: dw ' '
291/ CC8 : 00 0A XPos: dw 10
292/ CCA : 00 0A YPos: dw 10
293/ CCC : 00 11 Richt: dw $11
294/ CCE :
295/ CCE :
296/ CCE : 00 00 Status_Save: dw 0
297/ CD0 :
298/ CD0 : end