-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathchat3.mu4
189 lines (137 loc) · 4.98 KB
/
chat3.mu4
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
| This file is part of muforth: https://muforth.dev/
|
| Copyright 2002-2025 David Frech. (Read the LICENSE for details.)
| Calling this "chat3". It's really just an experiment to see if the style
| that I wrote the USB chat firmware in works in this context too. The main
| difference is that the original chat code was a big loop, where the USB
| "loop" was a subroutine - which meant that to return the "top" from any
| piece of code all you do is _return_. And using tail calls, it's easy to
| code in a Forth-like style that is very efficient.
loading S08 Chat v3 (target - tail-recursive version ;-)
hex
__meta
.ifdef in-ram ram
.else
trims "14 allot | ffac - ffbf: trims and security bytes
vectors "40 allot | ffc0 - ffff
| Memory code (wipe) has set boot and commit to reasonable defaults.
commit
.then
| Compile the first 32 bits of the current muforth Git commit. When asked
| for the version, return these four bytes, in big-endian order.
label version
muforth-commit drop 8 evaluate >0123 c, c, c, c,
.ifndef in-ram boot .then
| The SCI code is identical between 908 and S08 except for the names - and
| offsets - of the SCI status and data regs ... so let's abstract them.
.ifdef S08
aka SCIS1 SciStatus
aka SCID SciData
.else | 908
aka SCS1 SciStatus
aka SCDR SciData
.then
label get-byte ( returns char in A)
begin SciStatus 5 ( recvr full) bset? until
SciData ) lda rts ;c
label read-byte
0 ,x lda 1 # aix ( fall thru) ;c
label put-byte ( transmits char in A)
begin SciStatus 7 ( xmit empty) bset? until
SciData ) sta rts ;c
( chat3 protocol)
| Commands:
| 0 Idle - ignored by chat; force other command loops to return to chat;
| can be used as an Idle
| 1 Version - sets HX to point to version string:
| - 4 bytes of muforth commit, big-endian
| 2 Run - does an RTI - pops stack frame and runs
| 3 GetSP - sets HX from SP, then returns HX
| 4 SetHX - reads two bytes from SCI, writes them into H & X registers
| 5 ReadNext - reads a byte from memory @ HX, writes it to SCI, incrs HX
| 6 WriteNext - reads a byte from SCI, writes into memory @ HX, incrs HX
|
| ~~ The following are S08-only commands ~~
|
| 7 ReadN - reads a count from SCI, reads that many bytes from
| memory, and writes them to SCI
| 8 FlashNext - reads a byte from SCI, writes to flash @ HX, incrs HX
| - calls a routine in ram that host downloads to device
| - returns FSTAT
label process-serial
SciStatus 5 ( recvr full) bclr? if rts then ( nothing to do)
SciData ) lda ( command)
( map 0 -> ff - ignore)
.a decz? if ( Version) version # ldhx rts then
.a decz? if ( Run) 2 # ais ( skip return addr) .h pul rti then
.a decz? if ( GetSP)
tsx 2 # aix ( skip return addr)
.h psh .a pul put-byte c ( send H)
txa put-byte j ( send X) then
.a decz? if ( SetHX)
get-byte c .a psh .h pul ( set H)
get-byte c tax ( set X) rts then
.a decz? if ( ReadNext) read-byte j then
.a decz? if ( WriteNext)
get-byte c 0 ,x sta 1 # aix
.ifdef S08
( end WriteNext) rts then
.a decz? if ( ReadN)
get-byte c .a psh ( count)
begin read-byte c 0 ,s decz? until
.a pul rts then
.a decz? if ( FlashNext)
get-byte c flash-byte c 1 # aix ( call flash routine in RAM)
FSTAT ) lda put-byte j
.then
then
( unknown command) rts ;c
| If compiling into RAM and using 908 flash control block, check to make
| sure we haven't "run into" the control block, then jump forward over it
| and continue compiling there.
.def in-ram .def control-block .and .if
__host
: ?fits
control-block 'zram @ u< if
error" Code too long - ran into Flash control block"
then ;
?fits
__meta
09c org | continue compiling there
.then
| USB code defines its own versions of swi and clock code, so we needn't
| repeat them here.
.ifndef usb-debug-via-serial
.ifdef in-ram
label emulated-swi
( jsr/bsr has already pushed PC)
.x psh .a psh tpa ( flags to A) .a psh sei
.else
Vswi handler
.then
.h psh
.ifdef S08
flash-command ) clr ( do what we can to prevent spurious writes/erases)
.then
begin process-serial c again ;c
| If the chat interaction changes the PC on this stack frame to point
| somewhere other than _after_ the __swi, not all is lost - since we got
| here via a _call_ from reset, we'll return to _that_ loop, and re-enter
| the SWI.
|
| On the other hand, if the PC remains unaltered, an RTI from the SWI's
| stack frame wil simply return here, and we'll take the "exception" again.
label interact
.ifdef in-ram
begin emulated-swi c again ;c
.else
begin swi again ;c
.then
Vreset handler
@ram #ram + # ldhx
txs
.ifndef in-ram ( don't compile clock/UART code for RAM-based versions)
ld target/S08/chat-init.mu4
.then
begin interact c again ;c
.then ( usb-debug-via-serial)