Tools for working with Cidco Mailstations
at master 320 lines 7.0 kB view raw
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) 67dunno: 68 .db #0 69zip: 70 .dw #0 71zilch: 72 .dw #0 73caption: 74 .dw #0x0001 75 .dw (endcap - caption - 6) ; num of chars 76 .dw #0x0006 ; offset to first char 77 .ascii "FlashLoader" ; the caption string 78endcap: 79 80icons: 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) 85icon0: 86 .dw #0x0 ; icon width 87 .db #0x0 ; icon height 88 89icon1: 90 .dw #0 ; icon width 91 .db #0 ; icon height 92 93eventhandler: 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 114get_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 121size_too_big: 122 jp 0x0000 123size_ok: 124 di ; prevent things from touching RAM 125 call sdp 126 ld a, (#SDP_UNLOCK) 127read_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 133ingest_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 147done_ingesting: 148 ld -7(ix), b ; update bytes remaining to fetch on 149 ld -8(ix), c ; next iteration 150move_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) 158sector_erase: 159 ld (hl), #0x20 ; 28SF040 Sector-Erase Setup 160 ld (hl), #0xd0 ; 28SF040 Execute 161sector_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 167byte_program_loop: 168 ld a, (de) 169 ld (hl), #0x10 ; 28SF040 Byte-Program Setup 170 ld (hl), a ; 28SF040 Execute 171byte_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 182sector_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 192flash_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) 199bail: 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 216sdp: 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 228getbyte: 229 push hl 230getbyte_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) 241lptrecv_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 247wait_for_strobe: 248 in a, (STATUS) 249 and #LPT_STROBE_IN ; inb(STATUS) & stbin 250 jr nz, got_strobe 251 djnz wait_for_strobe 252strobe_failed: 253 ld h, #1 254 ld l, #0 255 jr lptrecv_tribble_out 256got_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 266wait_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 272lptrecv_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 314lptrecv_out: 315 pop bc 316 ret 317lptrecv_err: 318 pop bc 319 ld hl, #0x0100 320 ret