print80.inc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296
  1. ;;; -*- asm -*-
  2. ;
  3. ;;; Simple option ROM for printer for ABC80; this is not authentic, but
  4. ;;; uses a hardware interface implementable with an FT232H USB module.
  5. ;;; It is (hopefully) at least similar to an ABC80 printer interface.
  6. ;
  7. ;;; - ABC-bus select code 60 decimal;
  8. ;;; OUT 0 - (OUT) output data
  9. ;;; IN 0 - (INP) input data
  10. ;;; IN 1 - (STAT) bit 0 - Rx data available
  11. ;;; bit 1 - Tx space available
  12. ;;; bit 2 - USB suspended (not ready)
  13. ;;; bit 3 - USB configured (host ready)
  14. ;;; OUT 2 - (C1) flush Tx buffer immediately
  15. ;;; OUT 3 - (C2) discard all input - only supported in some hw versions
  16. ;;;
  17. ;;;
  18. ;;; FF is used as an escape character for the file I/O and console
  19. ;;; interfaces (FF A0..BF for file, FF C0 for console)
  20. ;;;
  21. ;;; FF FE is used to represent an FF character in the printer stream,
  22. ;;; and FF FD is send on CLOSE (end of job).
  23. ;;; For other escape sequences, see print.c.
  24. ;;;
  25. ;;; To auto-initialize this, we need a modified DOS that looks for
  26. ;;; additional ROM entry points (ABC800 has this, but not ABC80.)
  27. #include "z80.inc"
  28. #include "abc80.inc"
  29. #include "auxram.inc"
  30. defc selcode=60 ; ABC-bus select code
  31. defc LARGE=(ROMSIZE >= 2048)
  32. ;; Maximum number of remote volumes
  33. defc MAX_VOLS = 32
  34. ;; Console device, probably doesn't fit anymore
  35. defc console_dev = LARGE
  36. ;; Support strict text file access
  37. defc pra_dev = 0
  38. ;; ABC800-style CON: and NUL: devices
  39. defc connul = LARGE
  40. ;; Quicklib routine
  41. defc quicklib = 1
  42. ;; Return real error codes or always zero?
  43. defc return_real_errors = 0 ; Match UFD-DOS 80
  44. ;; PR: using raw protocol (not a chardev volume?)
  45. defc raw_pr = 0
  46. ;; CMD routine if in IEC area?
  47. defc have_cmd = LARGE && (ROMSTART == 0x7000)
  48. if !have_cmd
  49. defc c_cmd = ERR_8
  50. defc e_cmd = ERR_8
  51. defc e_iec = ERR_8
  52. endif
  53. ;; Device timeout
  54. defc timeout = 100 ; 100/50 Hz = 2 s
  55. .globl _org
  56. _org = ROMSTART
  57. .section .text
  58. .globl _start
  59. _start:
  60. ;; If in the IEC area, add the IEC area entry points
  61. ;; IEC: jump table follows; simply treat it as PR:
  62. if ROMSTART == 0x7000
  63. jp c_cmd
  64. jp e_cmd
  65. jp e_iec
  66. endif
  67. if raw_pr
  68. ; jp table for PR: (if in printer area, should be first)
  69. pr_jptable:
  70. jp trivial ; OPEN
  71. jp trivial ; PREPARE
  72. jp pr_close ; CLOSE
  73. jp notforme ; INPUT
  74. jp pr_print ; PRINT
  75. jp notforme ; RDBLK
  76. jp notforme ; WRBLK
  77. jp notforme ; DELETE
  78. jp notforme ; RENAME
  79. endif
  80. prb_jptable:
  81. jp prb_open ; OPEN
  82. jp prb_prepare ; PREPARE
  83. jp prb_close ; CLOSE
  84. jp prb_input ; INPUT - might be generally useful
  85. jp prb_print ; PRINT
  86. jp prb_rdblk ; RDBLK
  87. jp prb_wrblk ; WRBLK
  88. ; Supporting DELETE and RENAME requires fixes to the DOS ROM;
  89. ; the DOS ROM contains the BASIC interpreter for these and
  90. ; it assumes it only applies to disk files.
  91. jp prx_delete ; DELETE
  92. jp prx_rename ; RENAME
  93. ;; Fixed entry points, reserved for future use
  94. fixfunc:
  95. .org 0x4b, 0xff
  96. ;; Init entry point, same offset as in DOS
  97. jp start
  98. if pra_dev
  99. ; jp table for PRA:
  100. pra_jptable:
  101. jp pra_open ; OPEN
  102. jp pra_prepare ; PREPARE
  103. jp pra_close ; CLOSE
  104. jp pra_input ; INPUT
  105. jp pra_print ; PRINT
  106. jp notforme ; RDBLK
  107. jp notforme ; WRBLK
  108. ; Supporting DELETE and RENAME requires fixes to the DOS ROM;
  109. ; the DOS ROM contains the BASIC interpreter for these and
  110. ; it assumes it only applies to disk files.
  111. jp prx_delete ; DELETE
  112. jp prx_rename ; RENAME
  113. endif
  114. if raw_pr
  115. pr_print:
  116. call select
  117. ld a,0F3h ; Printer data
  118. call send_esc
  119. pr_print_loop:
  120. ld a,b
  121. or c
  122. ld a,0EFh
  123. jr z,done_esc
  124. ld a,(hl)
  125. call send_byte
  126. inc a
  127. jr nz,pr_not_ff
  128. ld a,0FEh
  129. call send_byte
  130. pr_not_ff:
  131. dec bc
  132. inc hl
  133. jr pr_print_loop
  134. pr_close:
  135. call select
  136. ld a,0FDh
  137. jr done_esc
  138. endif
  139. ;; Select the current device, and save the stack pointer
  140. ;; to allow for an error unwind. This should be called from the
  141. ;; topmost stack so that a RET on error returns to BASIC;
  142. ;; if called in a nested context that context will be returned
  143. ;; to on error. After an error the carry flag is set and only
  144. ;; A is defined.
  145. select:
  146. ld (errsp),sp
  147. push af
  148. ld a,(SELECT) ; Old select code
  149. ld (ram_select),a ; Save old select code
  150. ld a,selcode ; Select code
  151. ld (SELECT),a ; Is this correct?
  152. out (1),a
  153. pop af
  154. ret
  155. done_esc:
  156. call send_esc
  157. done_ok:
  158. xor a
  159. done:
  160. ld sp,(errsp) ; Restore stack
  161. inc sp ; Drop return address from select
  162. inc sp
  163. push af
  164. ld a,(ram_select)
  165. ld (SELECT),a
  166. out (1),a
  167. pop af
  168. rlca ; CF <- bit 7
  169. if return_real_errors
  170. srl a ; Strip bit 7 from result but is in CF
  171. else
  172. ld a,0 ; This is what UFD-DOS 80 does?!
  173. endif
  174. ret
  175. if pra_dev
  176. pra_open:
  177. ld a,0xA0
  178. jr prx_open
  179. pra_prepare:
  180. ld a,0xA2
  181. jr prx_open
  182. endif
  183. prb_prepare:
  184. ld a,0xA3
  185. jr prb_open_prepare
  186. prb_open:
  187. ld a,0xA1
  188. prb_open_prepare:
  189. call prb_setup_buf
  190. ;; Fall through...
  191. prx_open:
  192. ;; ABC80-BASIC expects DE to be preserved across this routine,
  193. ;; otherwise .BAC -> .BAS searching does not work.
  194. if pra_dev ; Handled by prb_setup_buf
  195. ld (ix+7),132 ; Line length, seems to be standard?
  196. endif
  197. call select
  198. push af ; Save command code
  199. call send_cmd ; Returns with CF = 0
  200. ld l,(ix+3) ; Get volume name
  201. ld h,(ix+4)
  202. ld bc,3
  203. sbc hl,bc
  204. ld (ix+6),b ; 0
  205. call send_buf
  206. ;; HL <- filename. Do not use EX DE,HL here: if send_buf
  207. ;; aborts we have to have DE intact on return to BASIC.
  208. ld l,e
  209. ld h,d
  210. ld c,11 ; B = 0 already
  211. call send_buf
  212. call recv_reply
  213. pop hl ; H = command
  214. if quicklib
  215. and (iy+14) ; Bit 0 = command mode
  216. add a ; Bit 0 -> bit 1
  217. and h ; Check for PREPARE (bit 1)
  218. ;; bit 1 in A is now set if quicklib
  219. endif
  220. ;; Mark buffer busy if successful, any value other than 0xff
  221. ;; works, so just use zero...
  222. if pra_dev
  223. bit 0,h ; PRA -> no buffer, no quicklib
  224. jr z,nohazbuf
  225. endif
  226. call prb_dosfd
  227. ld (hl),b ; B = 0 on exit here
  228. nohazbuf:
  229. if !quicklib
  230. jr done
  231. else
  232. ;; A is as set up above...
  233. and 2
  234. jr z,done ; Not quicklib (A = 0 here)
  235. ;; -------- Show library listing on screen --------
  236. prx_quicklib:
  237. ;; Restore the original select code in memory. It isn't
  238. ;; necessary to send the select code to the bus, because
  239. ;; the subsequent I/O operations will do that for us.
  240. ld a,(ram_select) ; Restore original select code
  241. ld (SELECT),a
  242. call crlf
  243. ld (ix+6),22 ; 22 lines before wait
  244. ql_getline:
  245. call S_CHECKCTRLC
  246. jr nz,ql_done
  247. ld hl,PCODE_BUF
  248. push hl
  249. ld bc,PCODE_SIZE
  250. call IX_INPUT
  251. pop hl
  252. jr c,ql_done
  253. call S_CUR_MAX_X
  254. ld bc,+(12 << 8) + 13
  255. add c ; Space needed
  256. sub e
  257. jr c,ql_nocrlf
  258. call crlf
  259. dec (ix+6)
  260. jr nz,ql_nocrlf
  261. push ix
  262. call CON_GET
  263. pop ix
  264. ld (ix+6),1 ; <Return> = one line only
  265. cp c
  266. jr z,ql_nocrlf
  267. ld (ix+6),22
  268. ql_nocrlf:
  269. push hl
  270. ql_find_comma:
  271. ld a,(hl)
  272. cp '.' ; Lowest valid filename character
  273. jr c,ql_found_comma ; Comma, CR, or other non-filename character
  274. inc hl
  275. djnz ql_find_comma
  276. ql_found_comma:
  277. inc b
  278. ql_pad_space:
  279. ld (hl),' '
  280. inc hl
  281. djnz ql_pad_space
  282. ql_cleaned_comma:
  283. pop hl
  284. ; BC = 13 here
  285. call CON_PRINT
  286. jr ql_getline
  287. ql_done:
  288. call S_CLOSEFILE
  289. jp S_CMD ; Forcible return to command loop -
  290. ; abort LIST command
  291. crlf:
  292. push bc
  293. call CON_CRLF
  294. pop bc
  295. ret
  296. endif ; quicklib
  297. prx_rename:
  298. call select
  299. ld a,0xAA
  300. call send_cmd
  301. ex de,hl ; HL -> new filename
  302. ld bc,11
  303. call send_buf
  304. jr prx_reply_done
  305. prb_close:
  306. call select
  307. xor a
  308. cp (ix+14)
  309. jr z,pbc_noflush
  310. call prb_getbufaddr
  311. ld b,a
  312. ld a,(ix+10) ; End data
  313. sub l ; Skip non-data at start of buffer
  314. ld c,a
  315. call output_common
  316. pbc_noflush:
  317. call prb_dosfd
  318. ld (hl),255 ; Buffer now free
  319. ;; Returns with B=0
  320. ld (ix+14),b
  321. if pra_dev
  322. pra_close:
  323. ld (ix+5),0
  324. else
  325. ld (ix+5),b
  326. endif
  327. ld a,0xA7
  328. prx_simple_command: ; Just command and response, no data
  329. call send_cmd
  330. prx_reply_done: ; Reply, then done
  331. call recv_reply
  332. done2:
  333. jp done
  334. prx_delete:
  335. ld a,0xAB
  336. call select
  337. jr prx_simple_command
  338. if pra_dev
  339. pra_print:
  340. call select
  341. call output_common
  342. jr done2
  343. endif
  344. output_common:
  345. ld a,0xA6
  346. prx_length_command:
  347. call send_cmd
  348. call send_word
  349. call send_buf
  350. jp recv_reply
  351. if pra_dev
  352. pra_input:
  353. call select
  354. ld a,0xA4 ; INPUT
  355. endif
  356. ;; This routine can be called to handle a command with a
  357. ;; reply + len + data response.
  358. ;; HL -> target_buf, A = command, BC = buffer size
  359. ; XXX: USB is fast enough that INIR/OTIR should be possible
  360. input_command:
  361. call send_cmd
  362. call recv_reply
  363. call recv_byte
  364. ld e,a
  365. call recv_byte
  366. ld d,a
  367. ; Now HL -> target buf; DE -> expected byte count;
  368. ; BC -> buffer size
  369. prai_loop:
  370. ld a,d
  371. or e
  372. ret z
  373. dec de
  374. ld a,b
  375. or c
  376. jr nz,prai_space
  377. ld hl,ram_dummy
  378. inc c
  379. prai_space:
  380. dec bc
  381. call recv_byte
  382. ld (hl),a
  383. inc hl
  384. jr prai_loop
  385. prbr_protoerr:
  386. ld a,128+37
  387. jr done2
  388. prb_rdblk:
  389. call select
  390. prb_rdblk_nosel:
  391. ld a,0xA5
  392. call send_cmd
  393. ld b,253
  394. ld a,b
  395. call send_byte
  396. xor a
  397. call send_byte
  398. call recv_reply
  399. call recv_byte
  400. cp b
  401. jr nz,prbr_protoerr
  402. call recv_byte
  403. and a
  404. jr nz,prbr_protoerr
  405. call prb_getbufaddr
  406. push hl
  407. prbr_recv:
  408. call recv_byte
  409. ld (hl),a
  410. inc hl
  411. djnz prbr_recv
  412. pop hl ; HL -> buf address
  413. jp done_ok
  414. ;; This is a slightly modified version of the BLK_INPUT routine
  415. ;; in the BASIC ROM. It has the following modifications:
  416. ;; 1. Accept <LF> or <CR><LF> line endings as well as just <CR>
  417. ;; 2. Handle a block without an <ETX> terminator
  418. ;; 3. Handle a file without <NUL> terminator
  419. ;; These changes allow a text file in modern Unix/DOS format
  420. ;; to be parsed, as long as it does not have embedded <TAB>
  421. ;; characters. It would be possible to heuristically handle
  422. ;; <TAB> by looking for <LF> or <ETX>; the first block ought to have
  423. ;; at least one <LF> if "modern", or <ETX> if ABC.
  424. ;;
  425. ;; This is intended to be a general routine, usable for other
  426. ;; devices than these.
  427. prb_input:
  428. ex de,hl ; DE -> destination pointer
  429. ld (ix+13),1 ; Inhibit output
  430. ld l,(ix+10) ; HL -> pointer into the buffer
  431. ld h,(ix+11)
  432. pbi_nextchar:
  433. xor a
  434. cp c
  435. jr z,pbi_overlong ; Output buffer overflow?
  436. call pbi_peekchar
  437. cp 9 ; TAB = compressed spaces
  438. jr z,pbi_tab
  439. cp 10 ; LF = convert to CR
  440. jr z,pbi_lf
  441. and a
  442. jr z,pbi_eof ; NUL = end of file
  443. jp m,pbi_badchar ; >= 128 -> error
  444. pbi_emit:
  445. ldi ; (DE) <- (HL), DE++, HL++, BC--
  446. cp 13 ; CR = end of line
  447. jr nz,pbi_nextchar
  448. ;; For a CR character, look to see if the next one if LF,
  449. ;; if so eat the LF rather than having it converted to CR next time.
  450. ;; Only do this exactly once, so <CR><LF><LF> = 2 lines.
  451. call pbi_peekchar
  452. cp 10
  453. jr nz,pbi_done
  454. inc hl ; Skip exactly one LF character
  455. pbi_done:
  456. xor a
  457. pbi_return:
  458. ld (ix+10),l
  459. ld (ix+11),h
  460. ret
  461. pbi_eof:
  462. pbi_err:
  463. scf
  464. jr pbi_return
  465. pbi_overlong:
  466. ld a,128 + 20 ; Line too long
  467. jr pbi_err
  468. pbi_badchar:
  469. ld a,128 + 58 ; Bad character
  470. jr pbi_err
  471. pbi_lf: ; Convert to CR and EOL, but don't eat LF
  472. ld (hl),13
  473. ldi
  474. jr pbi_done
  475. pbi_tab:
  476. inc l ; Next byte; note that 3 = ETX is valid
  477. jr z,pbi_nextchar ; <TAB> at end of block -> ignore
  478. ld b,(hl)
  479. inc l
  480. ld a,c
  481. sub b
  482. jr c,pbi_overlong
  483. ld c,a
  484. ld a,' '
  485. pbi_tab_expand:
  486. ld (de),a
  487. inc de
  488. djnz pbi_tab_expand
  489. jr pbi_nextchar
  490. ;; Get the next character, but don't advance HL beyond
  491. ;; it. However, handle ETX and buffer overrun here.
  492. pbi_peekchar:
  493. xor a
  494. cp l ; 256-byte wrap: assume end of block
  495. jr z,pbi_newblock
  496. ld a,(hl)
  497. cp 3
  498. ret nz
  499. pbi_newblock:
  500. call pbi_eofbuf ; Just in case IX_BLKRD fails silently...
  501. push bc
  502. push de
  503. call IX_BLKRD
  504. pop de
  505. pop bc
  506. ;; HL points to start of buffer here (we hope)
  507. jr nc,pbi_peekchar
  508. ;; On error, return EOF and also set the first byte in the buffer
  509. ;; to EOF in case input gets called again.
  510. ;; Fall through...
  511. pbi_eofbuf:
  512. call prb_getbufaddr
  513. xor a
  514. ld (hl),a
  515. ret
  516. ; Write a binary output block. Similar to
  517. ; pra_print, but with a few different buffer
  518. ; management bits.
  519. prb_wrblk:
  520. call select
  521. call prb_getbufaddr
  522. ld bc,253
  523. call output_common
  524. call prb_empty_buf
  525. done3:
  526. jp done
  527. ;; Blocking PRINT without converting to ABC-DOS text format.
  528. ;; This simply stuffs a buffer full of the PRINT contents;
  529. ;; it also assumes the buffer is full when there is a 256-byte
  530. ;; address wraparound as (ix+13) is not expected to reflect the
  531. ;; buffer length without space for ETX... and is set to 1 on
  532. ;; read (what?!)
  533. prb_print:
  534. ld a,c
  535. or b
  536. ret z ; Nothing to do...
  537. ld e,(ix+10)
  538. ld d,(ix+11)
  539. pbp_output:
  540. xor a
  541. sub e
  542. jr z,pbp_nextbuf ; No space left in buffer
  543. push bc
  544. inc b
  545. ;; A now has the number of free bytes in the buffer
  546. ;; If BC > A need to use the rest of the buffer
  547. djnz pbp_limitlen
  548. cp c
  549. jr c,pbp_limitlen
  550. ld a,c
  551. pbp_limitlen:
  552. ld c,a
  553. xor a ; Assume all good, clear carry
  554. ld b,a
  555. ex (sp),hl
  556. sbc hl,bc ; Decrement bytes left to write
  557. ex (sp),hl
  558. ldir
  559. ld (ix+10),e
  560. ld (ix+11),d
  561. ld (ix+14),1 ; Buffer dirty
  562. pop bc
  563. ret z ; Z still set from SBC HL,BC
  564. pbp_nextbuf:
  565. push hl
  566. push bc
  567. call IX_BLKWR
  568. pop bc
  569. pop hl
  570. jr nc,pbp_output
  571. ret ; Error
  572. pbp_allbuf:
  573. sub e
  574. jr pbp_limitlen
  575. ;; Get the address of the DOS file description corresponding
  576. ;; to the allocated buffer.
  577. ;; Returns with B = 0, C = DOSBUF*16, HL = DOS file description
  578. prb_dosfd:
  579. ld b,0
  580. ld c,(ix+12)
  581. ld hl,0xFD41
  582. add hl,bc
  583. ret
  584. ;; Set up a BUF for PRB: (open/prepare)
  585. ;; This uses routines from UFD-DOS due to space
  586. prb_setup_buf:
  587. push af
  588. push bc
  589. push hl
  590. call 65F4h ; Allocate buffer
  591. call 662Bh ; Initialize buffer pointers
  592. pop hl
  593. pop bc
  594. pop af
  595. ret
  596. ;; This returns with DE -> buffer start. It seems ABC80-BASIC
  597. ;; requires this to work...
  598. prb_empty_buf: ; Returns with A=0, HL->buf
  599. push af
  600. ex de,hl
  601. ld a,(ix+12)
  602. call 662Fh ; Returns with HL -> buffer
  603. ex de,hl
  604. pop af
  605. ret
  606. ;;; Load the address of the start of the current buffer into HL
  607. prb_getbufaddr:
  608. ld l,3
  609. ld h,(ix+9)
  610. ret
  611. ;; Send a command header, A = command
  612. ;; Returns with CF = 0
  613. send_cmd:
  614. push bc
  615. ld (ram_cmd),a
  616. call send_esc
  617. ld a,(ram_serial)
  618. call send_byte
  619. push ix
  620. pop bc
  621. call send_word
  622. pop bc
  623. ret
  624. ;; Send a word in BC, preserves AF
  625. send_word:
  626. push af
  627. ld a,c
  628. call send_byte
  629. ld a,b
  630. call send_byte
  631. pop af
  632. ret
  633. ;; Send FF + byte; reset running checksum
  634. ;; Returns with CF = 0!
  635. send_esc:
  636. push af
  637. ld a,0FFh
  638. call send_byte
  639. ld (ram_csum),a
  640. pop af
  641. ;; Fall through
  642. ;; Send a single byte and add to running checksum
  643. ;; Returns with CF = 0!
  644. send_byte:
  645. push hl
  646. ld l,a
  647. ld a,(ram_csum)
  648. add l
  649. ld (ram_csum),a
  650. in a,(1)
  651. and 2 ; TX space available
  652. call z,wait_for_tx
  653. ld a,l
  654. out (0),a
  655. pop hl
  656. ret
  657. ;; Send a buffer HL->data BC=count
  658. ;; On return HL advanced, BC=0, A clobbered
  659. ;;
  660. ; XXX: USB is fast enough that INIR/OTIR should be possible
  661. send_buf:
  662. ld a,b
  663. or c
  664. ret z
  665. ld a,(hl)
  666. call send_byte
  667. dec bc
  668. inc hl
  669. jr send_buf
  670. ;; Receive a byte. Return with C flag on timeout.
  671. recv_byte:
  672. ;; Optimistically...
  673. in a,(1)
  674. and 0Dh
  675. cp 09h
  676. call nz,wait_for_rx
  677. in a,(0) ; Data immediately available
  678. ret ; C=0 already
  679. ;; This routine waits until the status bit given in A is zero;
  680. ;; if the the high bits of the status are anything other than
  681. ;; xxxx10xx (configured, not suspended) then immediately issue
  682. ;; device not ready.
  683. wait_for_tx:
  684. push hl
  685. ld hl,0x0A0E
  686. jr wait_for
  687. wait_for_rx:
  688. push hl
  689. ld hl,0x090D ; Mask, expected value
  690. wait_for:
  691. push bc
  692. ld b,timeout
  693. wf_ctr:
  694. ld a,(CLOCK)
  695. ld c,a
  696. wf_loop:
  697. in a,(1)
  698. and l
  699. cp h
  700. jr nz,wf_nope
  701. pop bc
  702. pop hl
  703. ret
  704. wf_nope:
  705. and 0x0C ; Invalid status bits?
  706. cp 0x08
  707. jr nz,wf_error ; Not connected
  708. ld a,(CLOCK)
  709. cp c
  710. jr z,wf_loop
  711. djnz wf_ctr
  712. wf_error:
  713. ld a,128+42 ; Device not ready
  714. done4:
  715. jp done
  716. send_endframe:
  717. ld a,0EFh ; End of frame
  718. call send_byte
  719. ld a,(ram_csum)
  720. neg ; Total checksum = 0
  721. call send_byte
  722. out (2),a ; Immediately transmit any pending output
  723. ret
  724. ;; Send end of frame, and receive a reply header.
  725. ;; If the reply is an error, terminate command and return
  726. ;; the error code to BASIC (or other caller) by calling done.
  727. recv_reply:
  728. push bc
  729. call send_endframe
  730. ld bc,(ram_cmd)
  731. rr_loop:
  732. call recv_byte
  733. rr_isff:
  734. inc a ; FF?
  735. jr nz,rr_loop
  736. call recv_byte
  737. cp c ; Command
  738. jr nz,rr_isff
  739. call recv_byte
  740. cp b ; Serial
  741. jr nz,rr_isff
  742. call recv_byte ; Error code (if any)
  743. ;; Got this far, bump sequence number
  744. inc b
  745. ld (ram_cmd),bc
  746. pop bc
  747. and a
  748. ret p ; Bit 7 = 0 -> no error
  749. jr done4
  750. rr_timeout:
  751. dec b ; Drop the sequence number to allow resend
  752. jr wf_error
  753. ;;;
  754. ;;; Discard any (stale) input, if any. Terminate immediately if suspended,
  755. ;;; not configured, or not present. Clobbers A.
  756. ;;;
  757. flush_rx:
  758. in a,(1)
  759. and 0Dh
  760. sub 09h
  761. ret nz
  762. out (3),a ; Fast flush if supported by the hardware
  763. in a,(0) ; Consume byte
  764. jr flush_rx
  765. if console_dev
  766. prc_jptable:
  767. jp trivial ; OPEN
  768. jp trivial ; PREPARE
  769. jp trivial ; CLOSE
  770. jp notforme ; INPUT
  771. jp prc_print ; PRINT
  772. jp notforme ; RDBLK
  773. jp notforme ; WRBLK
  774. jp notforme ; DELETE
  775. jp notforme ; RENAME
  776. prc_print:
  777. call select
  778. ld a,0xFF
  779. call send_byte
  780. ld a,0xc0
  781. call send_byte
  782. prc_print_loop:
  783. ld a,b
  784. or c
  785. jr z,send_byte_done ; A=00 here
  786. ld a,(hl)
  787. and a
  788. jr z,prc_skip
  789. call send_byte
  790. prc_skip:
  791. dec bc
  792. inc hl
  793. jr prc_print_loop
  794. send_byte_done:
  795. call send_byte
  796. jp done_ok
  797. endif ; console_dev
  798. start:
  799. if have_cmd
  800. ld hl,new_basic_jumps
  801. ld bc,old_basic_jumps - new_basic_jumps
  802. ld a,(65h) ; First byte different between old and new
  803. and a
  804. jr z,is_new_basic
  805. add hl,bc
  806. is_new_basic:
  807. ld de,basic_jumps
  808. ldir
  809. endif
  810. call init ; Unwind to here on error or return
  811. ld hl,__end + INIT_OFFS ; Where to search next
  812. ret
  813. init:
  814. call select
  815. ld hl,-256
  816. add hl,sp
  817. ld sp,hl
  818. push hl
  819. ld a,0xA9 ; CLOSE ALL NO REPLY
  820. call send_cmd
  821. call recv_reply
  822. ld a,0xBA ; LIST VOLUMES
  823. pop hl
  824. push hl
  825. ld bc,4*MAX_VOLS+1 ; B=0
  826. call input_command
  827. pop hl
  828. ;; Create device list entries
  829. ;; HL -> CRAD here, A = 0
  830. push hl
  831. ld bc,4*MAX_VOLS
  832. add hl,bc
  833. ld (hl),b ; Make sure it is null-terminated on overflow
  834. pop hl
  835. ld de,voldevs
  836. mk_vols:
  837. ld a,(hl)
  838. and a
  839. jr z,link_volumes ; Done
  840. inc hl
  841. push hl
  842. ld hl,7
  843. add hl,de
  844. ex de,hl
  845. ld (hl),e
  846. inc hl
  847. ld (hl),d
  848. inc hl
  849. ex de,hl
  850. pop hl
  851. ld bc,3 ; Copy volume name
  852. ldir
  853. if pra_dev
  854. ;; This requires pra_jptable and prb_jptable have the same upper bytes
  855. dec a ; Z = 1 if A = 1 = text/PRA
  856. ld a,pra_jptable & 0xff
  857. jr z,have_voltype
  858. endif
  859. ld a,prb_jptable & 0xff
  860. have_voltype:
  861. ld (de),a
  862. inc de
  863. ld a,prb_jptable >> 8
  864. ld (de),a
  865. inc de
  866. jr mk_vols
  867. link_volumes:
  868. ;; A = 0 here
  869. ld hl,-7
  870. add hl,de
  871. ld de,(DEVLIST)
  872. ld (hl),e
  873. inc hl
  874. ld (hl),d
  875. ld hl,device_list
  876. ld (DEVLIST),hl
  877. jp done
  878. notforme:
  879. ld a,128+52 ; Ej till denna enhet
  880. scf
  881. ret
  882. if connul
  883. con_open:
  884. ;; Be nice and initialize the position fields, even though
  885. ;; we aren't really able to keep them updated...
  886. call S_CUR_MAX_X
  887. ld (ix+6),a
  888. ld (ix+7),e
  889. ;; Fall through
  890. endif
  891. trivial: ; Trivially successful call
  892. xor a ; A <- 0 carry <- 0
  893. ret
  894. if connul
  895. alwayseof: ; End of file or file not found
  896. xor a
  897. scf
  898. ret
  899. ;;;
  900. ;;; Simple CON and NUL devices for ABC800 compatibility
  901. ;;;
  902. con_jptable:
  903. jp con_open ; OPEN
  904. jp con_open ; PREPARE
  905. jp trivial ; CLOSE
  906. jp CON_INPUT ; INPUT
  907. jp CON_PRINT ; PRINT
  908. jp notforme ; RDBLK
  909. jp notforme ; WRBLK
  910. jp notforme ; DELETE
  911. jp notforme ; RENAME
  912. nul_jptable:
  913. jp trivial ; OPEN
  914. jp trivial ; PREPARE
  915. jp trivial ; CLOSE
  916. jp alwayseof ; INPUT
  917. jp trivial ; PRINT
  918. jp notforme ; RDBLK
  919. jp notforme ; WRBLK
  920. jp notforme ; DELETE
  921. jp notforme ; RENAME
  922. endif
  923. ;;;
  924. ;;; Support for CMD (via the IEC area)
  925. ;;;
  926. ;;; CMD [#device,] expr [,expr] ...
  927. ;;;
  928. ;;; Similar to PRINT except that each argument is terminated by
  929. ;;; a null byte before sending
  930. ;;;
  931. if have_cmd
  932. defc CMD_BUF = LINE_BUF
  933. defc CMD_BUF_LEN = LINE_SIZE
  934. ;; Need 16 bytes of overflow space for numbers
  935. defc CMD_BUF_END = CMD_BUF + CMD_BUF_LEN - 16
  936. defc e_iec = ERR_8 ; Not implemented
  937. e_cmd:
  938. ld l,0 ; No file number
  939. ld a,(de) ; Next byte code
  940. cp '#'
  941. jr nz,e_cmd_find_file
  942. inc de
  943. rst 56 ; Compute expression
  944. e_cmd_find_file:
  945. ld (iy+13),l
  946. ld ix,0 ; No file map
  947. ld a,l
  948. and a
  949. jr z,e_cmd_start ; Device 0
  950. ;; L = file number to find
  951. ld ix,FILELIST
  952. e_cmd_find_file_next:
  953. ld c,(ix+0) ; Link
  954. ld b,(ix+1)
  955. ld a,c
  956. or b
  957. jp z,ERR_32 ; File not open
  958. push bc
  959. pop ix
  960. ld a,(ix+2) ; File number
  961. cp l
  962. jr nz,e_cmd_find_file_next
  963. ;; IX -> file map
  964. e_cmd_start:
  965. push ix
  966. ld hl,CMD_BUF
  967. ld (e_cmd_buf_ptr),hl
  968. ld (errsp),sp ; SAve stack pointer for reset
  969. e_cmd_start_expr:
  970. ld a,(de)
  971. inc de
  972. cp ','
  973. jr z,e_cmd_start_expr
  974. cp ';'
  975. jr z,e_cmd_start_expr
  976. dec de
  977. cp 192 ; Byte code for expression
  978. jr c,e_cmd_done ; Not an expression?
  979. rst 56 ; Compute expression
  980. push de ; Save P-code pointer
  981. ld de,(e_cmd_buf_ptr)
  982. dec b ; Integer?
  983. jr nz,e_cmd_not_integer
  984. e_cmd_integer:
  985. call INT_TO_STR
  986. jr e_cmd_finish_num
  987. e_cmd_not_integer:
  988. dec b ; String?
  989. jr z,e_cmd_string
  990. e_cmd_float: ;; Floating point
  991. ld hl,2
  992. add hl,sp ; -> exponent on stack
  993. call FLOAT_TO_STR
  994. e_cmd_finish_num:
  995. call e_cmd_check_overflow
  996. e_cmd_finish:
  997. ld (de),a
  998. inc de
  999. ld (e_cmd_buf_ptr),de
  1000. pop de ; P-code pointer
  1001. ld sp,(errsp) ; Reset stack
  1002. jr e_cmd_start_expr
  1003. e_cmd_string:
  1004. pop hl ; P-code pointer
  1005. pop bc ; Stack adjustment (not used)
  1006. pop bc ; String address
  1007. ex (sp),hl ; String length in HL, P-code pointer on stack
  1008. push bc ; String address
  1009. push hl ; String length
  1010. push de ; Output pointer
  1011. add hl,de ; End of string
  1012. ex de,hl
  1013. call e_cmd_check_overflow
  1014. pop de ; Output pointer
  1015. pop bc ; String length
  1016. pop hl ; String pointer
  1017. ldir
  1018. jr e_cmd_finish
  1019. e_cmd_done:
  1020. ;; Output generated, now send it
  1021. pop ix ; Restore IX map pointer
  1022. push de ; P-code pointer
  1023. ld hl,(e_cmd_buf_ptr)
  1024. ld de,CMD_BUF
  1025. xor a
  1026. sbc hl,de
  1027. ex de,hl
  1028. ld c,e
  1029. ld b,d
  1030. pop de
  1031. call select
  1032. ld a,0BBh ; GENERIC COMMAND
  1033. call prx_length_command
  1034. jp done
  1035. e_cmd_check_overflow:
  1036. ;; DE -> end of string data
  1037. push hl
  1038. ld hl,CMD_BUF_END-1 ; -1 for terminal null
  1039. xor a
  1040. sbc hl,de
  1041. pop hl
  1042. ret nc ; All good
  1043. e_cmd_space_overflow:
  1044. rst 10h
  1045. defb 128 + 20 ; "För lång rad"
  1046. endif ; have_cmd
  1047. defc need_device_list = console_dev | connul | raw_pr
  1048. if need_device_list
  1049. device_list:
  1050. if console_dev
  1051. prc_device:
  1052. if connul | raw_pr
  1053. defw . + 7 ; Next entry follows
  1054. else
  1055. defw voldevs
  1056. endif
  1057. defm "PRC"
  1058. defw prc_jptable
  1059. endif
  1060. if connul
  1061. con_device:
  1062. defw . + 7 ; Next entry follows
  1063. defm "CON"
  1064. defw con_jptable
  1065. nul_device:
  1066. if raw_pr
  1067. defw . + 7 ; Next entry follows
  1068. else
  1069. defw voldevs
  1070. endif
  1071. defm "NUL"
  1072. defw nul_jptable
  1073. endif
  1074. if raw_pr
  1075. pr_device:
  1076. defw voldevs
  1077. defm "PR "
  1078. defw pr_jptable
  1079. endif
  1080. endif
  1081. ;; Jump table for BASIC functions that are inconsistent
  1082. new_basic_jumps: ; Checksum 9913, 10042
  1083. if have_cmd
  1084. jp 3392h ; Check space on stack
  1085. jp 1853h ; Integer to string
  1086. jp 1675h ; Float to string
  1087. jp 2152h ; Compile PRINT
  1088. endif
  1089. old_basic_jumps: ; Checksum 11273
  1090. if have_cmd
  1091. jp 339Bh ; Check space on stack
  1092. jp 1855h ; Integer to string
  1093. jp 1679h ; Float to string
  1094. jp 2154h ; Compile PRINT
  1095. endif
  1096. ;; Check for overflow and pad to desired ROM size
  1097. .org ROMSIZE, 0xff
  1098. __end:
  1099. ;;
  1100. ;; In RAM; this is assuming external SRAM or equivalent at 20-22K.
  1101. ;; The top 64 bytes are used by UFD-DOS.
  1102. ;;
  1103. defc ram_end = AUXRAM_PRINTNET_END
  1104. defc ram_start = AUXRAM_PRINTNET_BASE
  1105. .globl _bss
  1106. _bss = AUXRAM_PRINTNET_BASE
  1107. section .bss
  1108. __bss:
  1109. if !need_device_list
  1110. device_list:
  1111. endif
  1112. voldevs:
  1113. defs 7*MAX_VOLS ; Up to 32 volume device entries
  1114. errsp:
  1115. defs 2 ; SP rollback on error return
  1116. e_cmd_buf_ptr:
  1117. defs 2 ; Current data buffer pointer
  1118. ram_select:
  1119. defs 1 ; Previous select code
  1120. ram_csum:
  1121. defs 1 ; Running output checksum
  1122. ram_cmd:
  1123. defs 1 ; Latest sent command
  1124. ram_serial:
  1125. defs 1 ; Latest serial number (must be immediately after ram_cmd)
  1126. ram_dummy:
  1127. defs 1 ; Scratch byte
  1128. basic_jumps:
  1129. if have_cmd
  1130. CHECK_STACK_SPACE: defs 3 ; Check space on stack
  1131. INT_TO_STR: defs 3 ; Integer to string
  1132. FLOAT_TO_STR: defs 3 ; Float to string
  1133. c_cmd: ; Compile CMD = same as PRINT
  1134. C_PRINT: defs 3 ; Compile PRINT
  1135. endif
  1136. ;;; Check for overflow
  1137. .org AUXRAM_PRINTNET_SIZE
  1138. __end_bss: