Tools for working with Cidco Mailstations

Add dataflashloader

This can be executed by loader.asm, and then anything sent to it
will be written to dataflash in page 0.

lpt routines come from msTERM which are needed instead of the
"brecvbyte" routine in the stock firmware.

+332 -1
+12 -1
Makefile
··· 22 22 .endif 23 23 .endif 24 24 25 - all: objdir loader.bin codedump.bin datadump.bin memdump.bin \ 25 + all: objdir \ 26 + loader.bin codedump.bin datadump.bin memdump.bin dataflashloader.bin \ 26 27 recvdump sendload tribble_getty 27 28 28 29 objdir: ··· 40 41 $(SDCC) --no-std-crt0 -o $@ $> 41 42 42 43 loader.bin: loader.ihx 44 + objcopy -Iihex -Obinary $> $@ 45 + 46 + # dataflash loader 47 + dataflashloader.rel: dataflashloader.asm 48 + $(ASZ80) -o $@ $> 49 + 50 + dataflashloader.ihx: dataflashloader.rel 51 + $(SDCC) --no-std-crt0 -o $@ $> 52 + 53 + dataflashloader.bin: dataflashloader.ihx 43 54 objcopy -Iihex -Obinary $> $@ 44 55 45 56
+320
dataflashloader.asm
··· 1 + ; vim:syntax=z8a:ts=8 2 + ; 3 + ; dataflash loader 4 + ; 5 + ; works as a "stage 2" loader, so type in loader.asm and then run Loader from 6 + ; the Yahoo! menu, then use sendload to upload this compiled binary, then 7 + ; use sendload to upload your actual binary to be written to the dataflash at 8 + ; DATAFLASH_PAGE 9 + ; 10 + ; Copyright (c) 2019 joshua stein <jcs@jcs.org> 11 + ; 12 + ; Permission to use, copy, modify, and distribute this software for any 13 + ; purpose with or without fee is hereby granted, provided that the above 14 + ; copyright notice and this permission notice appear in all copies. 15 + ; 16 + ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 17 + ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 18 + ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 19 + ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20 + ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 21 + ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 22 + ; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23 + ; 24 + 25 + .module dataflashloader 26 + 27 + ; which page (Yahoo! menu slot) to save an uploaded program to 28 + ; page 0 is 0x0000, page 1 0x4000, page 2, 0x8000, etc. 29 + .equ DATAFLASH_PAGE, #0 30 + 31 + 32 + ; when running from Loader, we are loaded at 0x8000 and use slot 4 33 + .equ SLOT_ADDR, #0x4000 34 + .equ RUN_ADDR, #0x8000 35 + .equ SLOT_DEVICE, #0x6 36 + .equ SLOT_PAGE, #0x5 37 + 38 + ; where we'll buffer the 256 bytes we receive before writing to flash 39 + .equ RAM_ADDR, #0xd000 40 + 41 + .equ SDP_LOCK, #SLOT_ADDR + 0x040a 42 + .equ SDP_UNLOCK, #SLOT_ADDR + 0x041a 43 + 44 + ; lpt 45 + .equ CONTROL, #0x2c 46 + .equ DATA, #0x2d 47 + .equ STATUS, #0x21 48 + 49 + .equ LPT_BUSY_IN, #0x40 50 + .equ LPT_BUSY_OUT, #0x08 51 + .equ LPT_STROBE_IN, #0x80 52 + .equ LPT_STROBE_OUT, #0x10 53 + .equ LPT_TRIB_MASK, #0x07 54 + .equ LPT_DIB_MASK, #0x03 55 + 56 + 57 + .area _DATA 58 + .area _HEADER (ABS) 59 + 60 + .org #RUN_ADDR 61 + 62 + jp eventhandler 63 + 64 + .dw (icons) 65 + .dw (caption) 66 + .dw (dunno) 67 + dunno: 68 + .db #0 69 + zip: 70 + .dw #0 71 + zilch: 72 + .dw #0 73 + caption: 74 + .dw #0x0001 75 + .dw (endcap - caption - 6) ; num of chars 76 + .dw #0x0006 ; offset to first char 77 + .ascii "FlashLoader" ; the caption string 78 + endcap: 79 + 80 + icons: 81 + .dw #0x0 ; size icon0 82 + .dw (icon0 - icons) ; offset to icon0 83 + .dw #0 ; size icon1 84 + .dw (icon1 - icons) ; offset to icon1 (0x00b5) 85 + icon0: 86 + .dw #0x0 ; icon width 87 + .db #0x0 ; icon height 88 + 89 + icon1: 90 + .dw #0 ; icon width 91 + .db #0 ; icon height 92 + 93 + eventhandler: 94 + push ix 95 + ld ix, #0 96 + add ix, sp 97 + push bc 98 + push de 99 + push hl 100 + ld hl, #-8 ; stack bytes for local storage 101 + add hl, sp 102 + ld sp, hl 103 + in a, (#SLOT_DEVICE) 104 + ld -3(ix), a ; stack[-3] = slot 8 device 105 + in a, (#SLOT_PAGE) 106 + ld -4(ix), a ; stack[-4] = slot 8 device 107 + ld a, #3 ; slot 8 device = dataflash 108 + out (#SLOT_DEVICE), a 109 + xor a ; slot 8 page = 0 110 + out (#SLOT_PAGE), a 111 + ld hl, #SLOT_ADDR 112 + ld -5(ix), h 113 + ld -6(ix), l ; stack[-5,-6] = data flash location 114 + get_size: 115 + call getbyte ; low byte of total bytes to download 116 + ld -8(ix), a 117 + call getbyte ; high byte of total bytes to download 118 + ld -7(ix), a 119 + cp #0x40 ; we can't write more than 0x3fff 120 + jr c, size_ok 121 + size_too_big: 122 + jp 0x0000 123 + size_ok: 124 + di ; prevent things from touching RAM 125 + call sdp 126 + ld a, (#SDP_UNLOCK) 127 + read_chunk_into_ram: 128 + ; read 256 bytes at a time into ram, erase the target flash sector, 129 + ; then program it with those bytes 130 + ld b, -7(ix) 131 + ld c, -8(ix) 132 + ld hl, #RAM_ADDR 133 + ingest_loop: 134 + call getbyte 135 + ld (hl), a 136 + inc hl 137 + dec bc 138 + ld a, l 139 + cp #0 140 + jr z, done_ingesting ; on 256-byte boundary 141 + ld a, b 142 + cp #0 143 + jr nz, ingest_loop ; bc != 0, keep reading input 144 + ld a, c 145 + cp #0 146 + jr nz, ingest_loop ; bc != 0, keep reading input 147 + done_ingesting: 148 + ld -7(ix), b ; update bytes remaining to fetch on 149 + ld -8(ix), c ; next iteration 150 + move_into_flash: 151 + ld a, #3 ; slot 8 device = dataflash 152 + out (#SLOT_DEVICE), a 153 + ld a, #DATAFLASH_PAGE 154 + out (#SLOT_PAGE), a 155 + ld de, #RAM_ADDR 156 + ld h, -5(ix) ; data flash write location 157 + ld l, -6(ix) 158 + sector_erase: 159 + ld (hl), #0x20 ; 28SF040 Sector-Erase Setup 160 + ld (hl), #0xd0 ; 28SF040 Execute 161 + sector_erase_wait: 162 + ld a, (hl) ; wait until End-of-Write 163 + ld b, a 164 + ld a, (hl) 165 + cp b 166 + jr nz, sector_erase_wait 167 + byte_program_loop: 168 + ld a, (de) 169 + ld (hl), #0x10 ; 28SF040 Byte-Program Setup 170 + ld (hl), a ; 28SF040 Execute 171 + byte_program: 172 + ld a, (hl) 173 + ld b, a 174 + ld a, (hl) ; End-of-Write by reading it 175 + cp b 176 + jr nz, byte_program ; read until writing succeeds 177 + inc hl ; next flash byte 178 + inc de ; next RAM byte 179 + ld a, l 180 + cp #0 181 + jr nz, byte_program_loop 182 + sector_done: 183 + ld -5(ix), h ; update data flash write location 184 + ld -6(ix), l 185 + ld a, -7(ix) 186 + cp #0 187 + jp nz, read_chunk_into_ram ; more data to transfer 188 + ld a, -8(ix) 189 + cp #0 190 + jp nz, read_chunk_into_ram ; more data to transfer 191 + ; all done 192 + flash_out: 193 + ld a, #3 ; slot 8 device = dataflash 194 + out (#SLOT_DEVICE), a 195 + xor a ; slot 8 page = 0 196 + out (#SLOT_PAGE), a 197 + call sdp 198 + ld a, (#SDP_LOCK) 199 + bail: 200 + ld a, -3(ix) ; restore slot 8 device 201 + out (#SLOT_DEVICE), a 202 + ld a, -4(ix) ; restore slot 8 page 203 + out (#SLOT_PAGE), a 204 + ld hl, #8 ; remove stack bytes 205 + add hl, sp 206 + ld sp, hl 207 + pop hl 208 + pop de 209 + pop bc 210 + ld sp, ix 211 + pop ix 212 + ei 213 + jp 0x0000 214 + 215 + 216 + sdp: 217 + ld a, (#SLOT_ADDR + 0x1823) ; 28SF040 Software Data Protection 218 + ld a, (#SLOT_ADDR + 0x1820) 219 + ld a, (#SLOT_ADDR + 0x1822) 220 + ld a, (#SLOT_ADDR + 0x0418) 221 + ld a, (#SLOT_ADDR + 0x041b) 222 + ld a, (#SLOT_ADDR + 0x0419) 223 + ret 224 + ; caller needs to read final SDP_LOCK or SDP_UNLOCK address 225 + 226 + 227 + ; loop until we get a byte, return it in a 228 + getbyte: 229 + push hl 230 + getbyte_loop: 231 + call _lptrecv 232 + ld a, h 233 + cp #0 234 + jp nz, getbyte_loop 235 + ld a, l 236 + pop hl 237 + ret 238 + 239 + 240 + ; receive a tribble byte from host, return h=1 l=0 on error, else h=0, l=(byte) 241 + lptrecv_tribble: 242 + push bc 243 + ld hl, #0 ; h will contain error, l result 244 + xor a 245 + out (DATA), a ; drop busy/ack, wait for strobe 246 + ld b, #0xff ; try a bunch before bailing 247 + wait_for_strobe: 248 + in a, (STATUS) 249 + and #LPT_STROBE_IN ; inb(STATUS) & stbin 250 + jr nz, got_strobe 251 + djnz wait_for_strobe 252 + strobe_failed: 253 + ld h, #1 254 + ld l, #0 255 + jr lptrecv_tribble_out 256 + got_strobe: 257 + in a, (STATUS) 258 + sra a 259 + sra a 260 + sra a 261 + and #LPT_TRIB_MASK ; & tribmask 262 + ld l, a 263 + ld a, #LPT_BUSY_OUT ; raise busy/ack 264 + out (DATA), a 265 + ld b, #0xff ; retry 255 times 266 + wait_for_unstrobe: 267 + in a, (STATUS) 268 + and #LPT_STROBE_IN ; inb(STATUS) & stbin 269 + jr z, lptrecv_tribble_out 270 + djnz wait_for_unstrobe 271 + ; if we never get unstrobe, that's ok 272 + lptrecv_tribble_out: 273 + ld a, #LPT_BUSY_OUT ; raise busy/ack 274 + out (DATA), a 275 + pop bc 276 + ret 277 + 278 + 279 + ; unsigned char lptrecv(void) 280 + ; receive a full byte from host in three parts 281 + ; return h=1 l=0 on error, otherwise h=0, l=(byte) 282 + _lptrecv:: 283 + push bc 284 + call lptrecv_tribble 285 + ld a, h 286 + cp #1 287 + jr z, lptrecv_err ; bail early if h has an error 288 + ld b, l 289 + call lptrecv_tribble 290 + ld a, h 291 + cp #1 292 + jr z, lptrecv_err 293 + ld a, l 294 + sla a 295 + sla a 296 + sla a 297 + add b 298 + ld b, a ; += tribble << 3 299 + call lptrecv_tribble 300 + ld a, h 301 + cp #1 302 + jr z, lptrecv_err 303 + ld a, l 304 + and #LPT_DIB_MASK ; dibmask 305 + sla a 306 + sla a 307 + sla a 308 + sla a 309 + sla a 310 + sla a 311 + add b ; += (tribble & dibmask) << 6 312 + ld h, #0 313 + ld l, a 314 + lptrecv_out: 315 + pop bc 316 + ret 317 + lptrecv_err: 318 + pop bc 319 + ld hl, #0x0100 320 + ret