-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathchat.mu4
160 lines (123 loc) · 5 KB
/
chat.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
| This file is part of muforth: https://muforth.dev/
|
| Copyright 2002-2025 David Frech. (Read the LICENSE for details.)
loading 8051 chat (target)
| Since we don't yet have a meta/target/cross compiler for the 8051, and
| may never, let's make it easy to write "label" words in assembler.
hex
assembler
: bank3 ( reg - dir)
dup \a r0 \a a within if 7 and 18 + ^ then
error" only r0 to r7 allowed" ;
forth
__meta
| Taking inspiration from the wildly successful HC08 serial chat protocol.
|
| Responds to the following commands. NOTE: these are hex values!
|
| 00 - 0f idle - these command bytes are ignored
| 1a - ff idle - these command bytes are ignored
|
| 10 version-addr - get the address of the version commit
| 11 set-addr - set dptr to 16-bit address
| 12 run - set the machine SP, pop R1, PSW, and PC
| 13 get-status - get the machine SP
|
| 14 read-flash - read one byte of flash, inc dptr
| 15 read-ram - read one byte of ram, inc dptr
| 16 read-xram - read one byte of xram, inc dptr
|
| 17 write-flash - erase a page or program one byte,
| - inc dptr, return status byte
| 18 write-ram - write one byte to ram, inc dptr
| 19 write-xram - write one byte to xram, inc dptr
| Like all chat code, we have do the following:
|
| * set up the clock or clocks;
| * turn off the watchdog
| * set up the uart
| * enter a chat loop, interpreting commands from the host
( Reset vector.)
label reset-vector 2 allot
| 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,
( Host uses send and recv. Let's do the same here.)
label recv-byte
begin SCON0 .0 ( RI) bset? until
SCON0 .0 clr SBUF0 r7 mov ret ;c
( This assumes that reset code has set TI.)
label send-byte
begin SCON0 .1 ( TI) bset? until
SCON0 .1 clr r7 SBUF0 mov ret ;c
( Return word value in r6:r7)
label recv-word recv-byte acall r7 bank3 r6 mov recv-byte ajmp ;c
( Byte is in A.)
label inc-and-put
dptr inc a r7 mov send-byte ajmp ;c
( RAM variables. Why not put these directly into regs?) comment %%
18 3 + equ flash-command ( r3, bank 3)
18 4 + equ flash-key1 ( r4, bank 3)
18 5 + equ flash-key2 ( r5, bank 3) %%
label do-command
r7 decz? if ( version-addr) version # dptr mov ret then
r7 decz? if ( set-addr) recv-word acall r6 DPH mov r7 DPL mov ret then
r7 decz? if ( run)
recv-byte acall ( SP) r7 SP mov PSW pop ret then
r7 decz? if ( get-status)
SP r7 mov send-byte ajmp then
r7 decz? if ( read-flash)
a clr @a+dptr a movc inc-and-put ajmp then
r7 decz? if ( read-ram)
DPL r0 mov @r0 a mov inc-and-put ajmp then
r7 decz? if ( read-xram)
@dptr a movx inc-and-put ajmp then
r7 decz? if ( write-flash)
recv-byte acall r7 a mov a cpl 0!= if ( only prog if not ff)
r3 ( flash-command) PSCTL mov ( set program and/or erase bits)
r4 ( key1) FLKEY mov r5 ( key2) FLKEY mov ( unlock flash)
r7 a mov a @dptr movx
0 # PSCTL mov ( clear program and erase bits)
then inc-and-put ajmp then ( send byte back to say we are done)
r7 decz? if ( write-ram)
recv-byte acall DPL r0 mov r7 bank3 @r0 mov dptr inc ret then
r7 decz? if ( write-xram)
recv-byte acall r7 a mov a @dptr movx dptr inc then ( fall thru)
( unknown command) ret ;c
label process
recv-byte acall ( cmd)
r7 a mov -0f # a add a r7 mov
do-command ajmp ;c
( Push registers and start conversing with host.)
label chat-entry
( call has already pushed PC)
PSW push 18 # PSW orl ( switch to reg bank 3)
| We no longer disable interrupts by default when entering chat.
begin process acall again ;c
| This creates a slot for the PC which can be replaced with the address of
| native code to execute. That code can end with a return instruction, which
| will return to the call to interact below, and then re-enter chat with
| the same stack layout: a PC slot below a "protective" return address. It's
| easier to visualize than to explain. ;-)
label interact
begin chat-entry acall again ;c
label do-reset
| set SP to end of RAM - #64 - 1
#ram #64 - 1- # SP mov
| disable watchdog timer
0de # WDTCN mov
0ad # WDTCN mov
| Execute the device-specific initialization code, which is copied
| *inline* here. This will set up ports, clocks, UART, etc, and flash
| leds, if any.
| XXX eventually, protect this with an .ifdef when we have multiple chips
| to support.
ld target/8051/silabs/efm8/bb1/chat-support.mu4
| This is here so that native code can simply return and it will
| re-enter the chat code with a proper stack.
begin interact acall again ;c
| here
reset-vector goto __asm do-reset ajmp ;c
here /page negate and 01fe + ( signature byte) goto 0a5 c,
| goto