print80.inc 26 KB

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