Example program for the Cidco MailStation Z80 computer
at main 453 lines 9.3 kB view raw
1; vim:syntax=z8a:ts=8 2; 3; MailStation example program 4; Copyright (c) 2019-2021 joshua stein <jcs@jcs.org> 5; 6; Permission to use, copy, modify, and distribute this software for any 7; purpose with or without fee is hereby granted, provided that the above 8; copyright notice and this permission notice appear in all copies. 9; 10; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17; 18 19 .module crt0 20 21 .include "mailstation.inc" 22 .globl _main 23 .globl l__INITIALIZER 24 .globl s__INITIALIZER 25 .globl s__INITIALIZED 26 27 .area _HEADER (ABS) 28 29 .org RUN_ADDR 30start: 31 jp boot 32 33 .dw (icons) 34 .dw (caption) 35 .dw (dunno) 36 37dunno: 38 .db #0 39xpos: 40 .dw #0 41ypos: 42 .dw #0 43caption: 44 .dw #0x0001 ; ? 45 .dw (endcap - caption - 6) ; number of chars 46 .dw #0x0006 ; offset to first char 47 .ascii "Example" ; the caption string 48endcap: 49 50icons: 51 .dw (icon2 - icon1) ; size of icon1 52 .dw (icon1 - icons) ; offset to icon1 53 .dw (iconend - icon2) ; size of icon2 54 .dw (icon2 - icons) ; offset to icon2 55 56icon1: 57 .dw #0x0022 ; icon width (34, 5 bytes per row) 58 .db #0x22 ; icon height (34) 59 60 .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 61 .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 62 .db #0x00, #0xc0, #0x0f, #0x00, #0x00 ; ..............######.............. 63 .db #0x00, #0x30, #0x30, #0x00, #0x00 ; ............##......##............ 64 .db #0x00, #0x0c, #0xc0, #0x00, #0x00 ; ..........##..........##.......... 65 .db #0x00, #0x02, #0x00, #0x01, #0x00 ; .........#..............#......... 66 .db #0x00, #0x01, #0x00, #0x02, #0x00 ; ........#................#........ 67 .db #0x80, #0x00, #0x00, #0x04, #0x00 ; .......#..................#....... 68 .db #0x40, #0x00, #0x00, #0x08, #0x00 ; ......#....................#...... 69 .db #0x20, #0x00, #0x00, #0x10, #0x00 ; .....#......................#..... 70 .db #0x10, #0x00, #0x00, #0x20, #0x00 ; ....#........................#.... 71 .db #0x10, #0x00, #0x00, #0x20, #0x00 ; ....#........................#.... 72 .db #0x08, #0x30, #0x30, #0x40, #0x00 ; ...#........##......##........#... 73 .db #0x08, #0x78, #0x78, #0x40, #0x00 ; ...#.......####....####.......#... 74 .db #0x08, #0x78, #0x78, #0x40, #0x00 ; ...#.......####....####.......#... 75 .db #0x04, #0x30, #0x30, #0x80, #0x00 ; ..#.........##......##.........#.. 76 .db #0x04, #0x00, #0x00, #0x80, #0x00 ; ..#............................#.. 77 .db #0x04, #0x00, #0x00, #0x80, #0x00 ; ..#............................#.. 78 .db #0x04, #0x00, #0x00, #0x80, #0x00 ; ..#............................#.. 79 .db #0x08, #0x00, #0x00, #0x40, #0x00 ; ...#..........................#... 80 .db #0x08, #0x00, #0x00, #0x40, #0x00 ; ...#..........................#... 81 .db #0x08, #0x04, #0x80, #0x40, #0x00 ; ...#......#............#......#... 82 .db #0x10, #0x04, #0x80, #0x20, #0x00 ; ....#.....#............#.....#.... 83 .db #0x10, #0x08, #0x40, #0x20, #0x00 ; ....#......#..........#......#.... 84 .db #0x20, #0x70, #0x38, #0x10, #0x00 ; .....#......###....###......#..... 85 .db #0x40, #0x80, #0x07, #0x08, #0x00 ; ......#........####........#...... 86 .db #0x80, #0x00, #0x00, #0x04, #0x00 ; .......#..................#....... 87 .db #0x00, #0x01, #0x00, #0x02, #0x00 ; ........#................#........ 88 .db #0x00, #0x02, #0x00, #0x01, #0x00 ; .........#..............#......... 89 .db #0x00, #0x0c, #0xc0, #0x00, #0x00 ; ..........##..........##.......... 90 .db #0x00, #0x30, #0x30, #0x00, #0x00 ; ............##......##............ 91 .db #0x00, #0xc0, #0x0f, #0x00, #0x00 ; ..............######.............. 92 .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 93 .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 94 95icon2: 96 ; not used 97 .dw #0x0000 ; width 98 .db #0x00 ; height 99iconend: 100 101boot: 102 xor a 103 out (#0x0d), a ; put the cpu in its highest speed 104 105 ; all of our code expects to run in ram so when we're running from 106 ; dataflash, we have to copy our page of flash into ram, then jump to 107 ; it 108 109 ; swap in a page of ram 110 ld a, #DEVICE_RAM 111 out (#SLOT_DEVICE), a 112 out (#SLOT_PAGE), a 113 114 ; copy ourselves into ram 115 ld de, #SLOT_ADDR 116 ld hl, #RUN_ADDR 117 ld bc, #0x4000 118 ldir ; ld (de), (hl), de++, hl++, bc-- 119 120 jp SLOT_ADDR + (hijump - start) 121 122hijump: 123 ; PC is now in SLOT_ADDR, put our new RAM page into RUN_DEVICE/PAGE 124 out (#RUN_DEVICE), a 125 out (#RUN_PAGE), a 126 127 ; then jump back there 128 jp RUN_ADDR + (lojump - start) 129 130lojump: 131 call gsinit 132 call find_shadows 133 call _main ; main c code 134 jp _exit 135 136 137 .area _DATA 138 139; shadow locations 140p2shadow: 141 .dw #0xdba2 142p3shadow: 143 .dw #0xdba3 144p28shadow: 145 .dw #0xdba0 146delay_func: 147 jp 0x0a5c 148 149_debug0:: 150 .db #0 151_debug1:: 152 .db #0 153_debug2:: 154 .db #0 155_debug3:: 156 .db #0 157_debug4:: 158 .db #0 159 160 161 .area _GSINIT 162gsinit: 163 ld bc, #l__INITIALIZER 164 ld a, b 165 or a, c 166 jr z, gsinit_next 167 ld de, #s__INITIALIZED 168 ld hl, #s__INITIALIZER 169 ldir 170gsinit_next: 171 172 .area _GSFINAL 173 ret 174 175 176 .area _CODE 177 178; set location of port shadow variables depending on firmware version 179find_shadows: 180 ld a, (#0x0037) ; firmware major version 181 cp #0x1 182 jr z, ver_1 183 cp #0x2 184 jr z, ver_2 185 cp #0x3 186 jr z, ver_3 187unrecognized_firmware: ; we can't blink because that requires 188 jp 0x0 ; port and fw function addresses 189ver_1: 190 ld a, (#0x0036) ; firmware minor version 191 cp #0x73 192 jr z, ver_1_73 193 jr unrecognized_firmware 194ver_1_73: ; eMessage 1.73CID 195 ld hl, #p2shadow 196 ld (hl), #0xdb9f 197 ld hl, #p3shadow 198 ld (hl), #0xdba0 ; TODO: verify 199 ret 200ver_2: 201 ld a, (#0x0036) ; firmware minor version 202 cp #0x54 203 jr z, ver_2_54 204 jr unrecognized_firmware 205ver_2_54: ; MailStation 2.54 206 ld hl, #p2shadow 207 ld (hl), #0xdba2 208 ld hl, #p3shadow 209 ld (hl), #0xdba3 210 ld hl, #p28shadow 211 ld (hl), #0xdba0 212 ret 213ver_3: 214 ld a, (#0x0036) ; firmware minor version 215 cp #0x0d3 216 jr z, ver_3_03 217 jr unrecognized_firmware 218ver_3_03: ; MailStation 3.03 219 ld hl, #p2shadow 220 ld (hl), #0xdba5 221 ld hl, #p3shadow 222 ld (hl), #0xdba6 223 ret 224 225; exit handler, restart 226_exit:: 227 call _reboot 228 229_powerdown:: 230 ; TODO: figure out what else needs to be set before shutting down to 231 ; prevent it going to the "Reset System Data" screen on next startup 232 ld hl, (#p28shadow) 233 ld a, (hl) 234 set 1, a ; 74c74 pin4 235 set 0, a ; modem reset 236 ld (hl), a 237 di 238 out (#0x28), a 239 halt 240 ret 241 242_reboot:: 243 jp 0x0000 244 245; new_mail(unsigned char on) 246; toggles 'new mail' light 247_new_mail:: 248 di 249 push ix 250 ld ix, #0 251 add ix, sp 252 push hl 253 push af 254 ld a, 4(ix) 255 cp #0 256 ld hl, (p2shadow) 257 jr z, light_off 258light_on: 259 ld a, (hl) 260 set 4, a 261 jr write_p2 262light_off: 263 ld a, (hl) 264 res 4, a 265write_p2: 266 ld (hl), a 267 out (#0x02), a ; write p2shadow to port2 268 pop af 269 pop hl 270 pop ix 271 ei 272 ret 273 274; delay(unsigned int millis) 275; call mailstation function that delays (stack) milliseconds 276_delay:: 277 push ix 278 ld ix, #0 279 add ix, sp 280 push af 281 push bc 282 push hl 283 ld l, 4(ix) 284 ld h, 5(ix) 285 push hl 286 call delay_func 287 pop hl 288 pop hl 289 pop bc 290 pop af 291 pop ix 292 ret 293 294; blink(unsigned int millis) 295; turn new mail LED on, wait millis, turn it off, wait millis 296_blink:: 297 push ix 298 ld ix, #0 299 add ix, sp 300 push hl 301 ld l, #1 302 push hl 303 call _new_mail ; turn it on 304 pop hl 305 ld l, 4(ix) 306 ld h, 5(ix) 307 push hl 308 call _delay ; wait 309 pop hl 310 ld l, #0 311 push hl 312 call _new_mail ; turn it off 313 pop hl 314 ld l, 4(ix) 315 ld h, 5(ix) 316 push hl 317 call _delay ; wait 318 pop hl 319 pop af 320 pop ix 321 ret 322 323; void lcd_sleep(void) 324; turn the LCD off 325_lcd_sleep:: 326 di 327 push hl 328 ld hl, (p2shadow) 329 ld a, (hl) 330 and #0b01111111 ; LCD_ON - turn port2 bit 7 off 331 ld (hl), a 332 out (#0x02), a ; write p2shadow to port2 333 pop hl 334 ei 335 ret 336 337 338; void lcd_wake(void) 339; turn the LCD on 340_lcd_wake:: 341 di 342 push hl 343 ld hl, (p2shadow) 344 ld a, (hl) 345 or #0b10000000 ; LCD_ON - turn port2 bit 7 on 346 ld (hl), a 347 out (#0x02), a ; write p2shadow to port2 348 pop hl 349 ei 350 ret 351 352; unsigned char read_port(unsigned char port) 353; return a byte read from a port 354_read_port:: 355 push ix 356 ld ix, #0 357 add ix, sp 358 push af 359 push bc 360 ld b, #0 361 ld c, 4(ix) 362 in l, (C) 363 ld h, #0 364 pop bc 365 pop af 366 pop ix 367 ret 368 369 370; 8-bit multiplication 371; de * a = hl 372mult8:: 373 ld b, #8 374 ld hl, #0 375mult8_loop: 376 add hl, hl 377 rlca 378 jr nc, mult8_noadd 379 add hl, de 380mult8_noadd: 381 djnz mult8_loop 382mult8_out: 383 ret 384 385; 16-bit multiplication 386; bc * de = hl 387mult16: 388 ld a, b 389 ld b, #16 390 ld hl, #0 391mult16_loop: 392 add hl, hl 393 sla c 394 rla 395 jr nc, mult16_noadd 396 add hl, de 397mult16_noadd: 398 djnz mult16_loop 399 ret 400 401 402; 8-bit division 403; divide e by c, store result in a and remainder in b 404div8: 405 xor a 406 ld b, #8 407div8_loop: 408 rl e 409 rla 410 sub c 411 jr nc, div8_noadd 412 add a, c 413div8_noadd: 414 djnz div8_loop 415 ld b,a 416 ld a,e 417 rla 418 cpl 419 ret 420 421; 16-bit division 422; divide bc by de, store result in bc, remainder in hl 423div16: 424 ld hl, #0 425 ld a, b 426 ld b, #8 427div16_loop1: 428 rla 429 adc hl, hl 430 sbc hl, de 431 jr nc, div16_noadd1 432 add hl, de 433div16_noadd1: 434 djnz div16_loop1 435 rla 436 cpl 437 ld b, a 438 ld a, c 439 ld c, b 440 ld b, #8 441div16_loop2: 442 rla 443 adc hl, hl 444 sbc hl, de 445 jr nc, div16_noadd2 446 add hl, de 447div16_noadd2: 448 djnz div16_loop2 449 rla 450 cpl 451 ld b, c 452 ld c, a 453 ret