blob: e894e423e15a0014e66f9aa78439f02425947b6a (
plain)
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
|
## Copyright (C) 2016 Jeremiah Orians
## This file is part of stage0.
##
## stage0 is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## stage0 is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with stage0. If not, see <http://www.gnu.org/licenses/>.
# :start 0
E0002D2B0200 # LOADUI R11 0x200 ; Where we are putting our address pointers
0D00003C # TRUE R12 ; Our toggle
0D00002D # FALSE R13 ; Our PC counter
E0002D2E0050 # LOADUI R14 $getLables_2 ; our first iterator
# ;; We will be using R15 for holding our processed nybbles
# ;; Prep TAPE_01
E0002D201100 # LOADUI R0 0x1100
42100000 # FOPEN_READ
# ;; Prep TAPE_02
E0002D201101 # LOADUI R0 0x1101
42100001 # FOPEN_WRITE
E0002D211100 # LOADUI R1 0x1100 ; Read from tape_01
# ;; Function for collecting the address of all labels
# :getLables 2e
42100100 # FGETC ; Read a Char
# ;; Check for EOF
E0002CC00052 # JUMP.NP R0 @stage2
# ;; Check for Label
E000A030003a # CMPSKIPI.NE R0 58 ; If the Char is : the next char is the label
3C000036 # JUMP @storeLabel
# ;; Check for pointer to label
E000A0300040 # CMPSKIPI.NE R0 64 ; If the Char is @ the next char is the pointer to a label
3C00001e # JUMP @ignorePointer
# ;; Otherwise attempt to process
3C000100 # JUMP @hex ; Convert it
# :getLables_2 50
E0002CC0ffd8 # JUMP.NP R0 @getLables ; Don't record, nonhex values
090006CC # NOT R12 R12 ; Flip the toggle
E0002C9Cffce # JUMP.Z R12 @getLables ; First half doesn't need anything
# ;; Deal with case of second half of byte
E1000FDD0001 # ADDUI R13 R13 1 ; increment PC now that we have a full byte
3C00ffc4 # JUMP @getLables
# :ignorePointer 6a
# ;; Ignore the pointer for now
42100100 # FGETC ; Read a Char
E1000FDD0002 # ADDUI R13 R13 2 ; The pointer will end up taking 2 bytes
3C00ffb6 # JUMP @getLables
# ;; Function for storing the address of the label
# :storeLabel 78
# ;; Get the char of the Label
42100100 # FGETC ; Read a Char
# ;; We require 2 bytes to store the pointer values
E0002D500001 # SL0I R0 1 ; Thus we multiply our label by 2
# ;; Store the current Program counter
0504ADB0 # STOREX16 R13 R11 R0
# ;; Label is safely stored, return
3C00ffa4 # JUMP @getLables
# ;; Now that we have all of the label addresses,
# ;; We can process input to produce our output
# :stage2 8a
# ;; We first need to rewind tape_01 to perform our second pass
E0002D201100 # LOADUI R0 0x1100
42100003 # REWIND
# ;; Reset our toggle and counter
E0002D291101 # LOADUI R9 0x1101 ; Where to write the combined byte
0D00003C # TRUE R12 ; Our toggle
0D00002D # FALSE R13 ; Our PC counter
E0002D2E00ca # LOADUI R14 $loop_hex ; The hex return target
# :loop a8
42100100 # FGETC ; Read a Char
# ;; Check for EOF
E0002CC0010e # JUMP.NP R0 @finish
# ;; Check for Label
E000A030003a # CMPSKIPI.NE R0 58 ; Make sure we jump over the label
3C00004e # JUMP @ignoreLabel
# ;; Check for Pointer
E000A0300040 # CMPSKIPI.NE R0 64 ; If it is a pointer Deal with it
3C00004c # JUMP @storePointer
# ;; Process Char
3C000086 # JUMP @hex ; Convert it
# :loop_hex ca
E0002CC0ffd8 # JUMP.NP R0 @loop ; Don't use nonhex chars
090006CC # NOT R12 R12 ; Flip the toggle
E0002CAC000a # JUMP.NZ R12 @loop_second_nybble ; Jump if toggled
# ;; Process first byte of pair
E100B0F0000f # ANDI R15 R0 0xF ; Store First nibble
3C00ffc4 # JUMP @loop
# :loop_second_nybble e4
E0002D5F0004 # SL0I R15 4 ; Shift our first nibble
E100B000000f # ANDI R0 R0 0xF ; Mask out top
0500000F # ADD R0 R0 R15 ; Combine nibbles
09000319 # SWAP R1 R9 ; Set to write to tape_2
42100200 # FPUTC ; To TAPE_02
09000319 # SWAP R1 R9 ; Restore from tape_1
E1000FDD0001 # ADDUI R13 R13 1 ; increment PC now that we have a full byte
3C00ff9e # JUMP @loop ; Try to get more bytes
# :ignoreLabel 10a
# ;; Consume next char
42100100 # FGETC ; Read a Char
3C00ff96 # JUMP @loop
# :storePointer 112
# ;; Correct the PC to reflect the size of the pointer
E1000FDD0002 # ADDUI R13 R13 2 ; Exactly 2 bytes
# ;; Get the char of the Label
42100100 # FGETC ; Read a Char
# ;; Since we stored a short pointer taking up 2 bytes
E0002D500001 # SL0I R0 1 ; Thus we multiply our label by 2 to get where it is stored
0503C3B0 # LOADXU16 R3 R11 R0 ; Load the address of the label
# ;; We now have to calculate the distance and store the 2 bytes
0500233D # SUB R3 R3 R13 ; First determine the difference between the current PC and the stored PC of the label
# ;; Store Upper byte
E100B003ff00 # ANDI R0 R3 0xFF00 ; Mask out everything but top byte
E0002D400008 # SARI R0 8 ; Drop the bottom 8 bits
09000319 # SWAP R1 R9 ; Write the byte
42100200 # FPUTC ; To TAPE_02
# ;; Store Lower byte
E100B00300ff # ANDI R0 R3 0xFF ; Preserve bottom half for later
42100200 # FPUTC ; Write the byte to TAPE_02
09000319 # SWAP R1 R9 ; Restore Read
3C00ff58 # JUMP @loop
# ;; Hex function
# ;; Returns hex value of ascii char
# ;; Or -1 if not a hex char
# :hex 150
# ;; Deal with line comments starting with #
E000A0300023 # CMPSKIPI.NE R0 35
3C000050 # JUMP @ascii_comment
# ;; Deal with line comments starting with ;
E000A030003b # CMPSKIPI.NE R0 59
3C000046 # JUMP @ascii_comment
# ;; Deal with all ascii less than '0'
E000A0100030 # CMPSKIPI.GE R0 48
3C00004a # JUMP @ascii_other
# ;; Deal with '0'-'9'
E000A0000039 # CMPSKIPI.G R0 57
3C00001e # JUMP @ascii_num
# ;; Deal with all ascii less than 'A'
E000A0100041 # CMPSKIPI.GE R0 65
3C000036 # JUMP @ascii_other
# ;; Unset high bit to set everything into uppercase
E100B00000df # ANDI R0 R0 0xDF
# ;; Deal with 'A'-'F'
E000A0000046 # CMPSKIPI.G R0 70
3C00000e # JUMP @ascii_high
# ;; Ignore the rest
3C000022 # JUMP @ascii_other
# :ascii_num 196
E10011000030 # SUBUI R0 R0 48
0D01000E # JSR_COROUTINE R14
# :ascii_high 1a0
E10011000037 # SUBUI R0 R0 55
0D01000E # JSR_COROUTINE R14
# :ascii_comment 1aa
42100100 # FGETC ; Read another char
E000A020000a # CMPSKIPI.E R0 10 ; Stop at the end of line
3C00fff2 # JUMP @ascii_comment ; Otherwise keep looping
# :ascii_other 1b8
0D000030 # TRUE R0
0D01000E # JSR_COROUTINE R14
# :finish 1c0
E0002D201100 # LOADUI R0 0x1100 ; Close TAPE_01
42100002 # FCLOSE
E0002D201101 # LOADUI R0 0x1101 ; Close TAPE_02
42100002 # FCLOSE
FFFFFFFF # HALT
# ;; Where all of our pointers will be stored for our locations
# :table 1d8
|