module ZXUtils::MultitaskingIO::Macros
ZXUtils::MultitaskingIO
Macros
for tasks.¶ ↑
Most of the routines created by MultitaskingIO::Macros
expects an I/O buffer handle in the hl
register pair. The buffer handle may be obtained by calling one of the kernel functions:
Public Instance Methods
Drains the I/O buffer.
Options:
disable_intr
-
a boolean flag indicating that the routine should disable interrupts. Provide
false
only if you have already disabled the interrupts.
enable_intr
-
a boolean flag indicating that the routine should enable interrupts. Provide
false
if you need to perform more atomic actions.
Expects:
hl
-
an I/O buffer handle.
Removes all the pending data from an I/O buffer.
Modifies: af
, preserves: hl
.
# File lib/zxutils/multitasking_io.rb, line 438 def mtio_drain(disable_intr:true, enable_intr:true) isolate do |eoc| dec hl di if disable_intr ld a, [hl] # outoffs inc hl ei if enable_intr ld [hl], a # inpoffs end end
Reads a single character from the I/O buffer. Arguments:
char
-
an 8 bit register which should receive a code if the character read.
Options:
tt
-
an 16 bit register for temporary use.
not_ready
-
what to do when a character can't be read. A symbol
:eoc
to just signal the failure with the CF flag reset (NC) and the ZF flag set (Z). A symbol:wait
to wait for the character to become available. A label or an address to jump to when the character is not available.
subroutine
-
if the routine should terminate with a
ret
instruction.
preserve_hl
-
if the routine should preserve the
hl
register via the stack.
disable_intr
-
a boolean flag indicating that the routine should disable interrupts. Provide
false
only if you have already disabled the interrupts.
enable_intr
-
a boolean flag indicating that the routine should enable interrupts. Provide
false
if you need to perform more atomic actions.
mtyield
-
should contain an address of the kernel routine:
task_yield
.
Expects:
hl
-
an I/O buffer handle.
On success the CF flag is set and a register char
contains a read character.
Modifies: af
, hl
, tt
, char
, optionally preserves: hl
on the machine stack.
# File lib/zxutils/multitasking_io.rb, line 472 def mtio_getc(char=e, tt:bc, not_ready: :eoc, subroutine: true, preserve_hl:true, disable_intr:true, enable_intr:true, mtyield: task_yield) th, tl = tt.split raise ArgumentError, "char must not be a tl or th or h or l" if [h,l,th,tl].include?(char) isolate do push hl if preserve_hl repeat label di if disable_intr ld tl, [hl] # inpoffs dec hl ld a, [hl] # outoffs cp tl case not_ready when :eoc if subroutine && !enable_intr && !preserve_hl ret Z else jr Z, eop end when :wait if subroutine jr Z, wait_busy else jr NZ, skip call mtyield di unless disable_intr inc hl jr repeat end else jp Z, not_ready end skip inc tl inc hl ld [hl], tl # inpoffs dec hl # outoffs ld th, -1 add hl, tt # CF=1 ld char, [hl] eop label ei if enable_intr pop hl if preserve_hl if subroutine ret if not_ready == :wait wait_busy call mtyield di unless disable_intr inc hl jr repeat end end end end
Reads a string of characters from the I/O buffer.
Arguments:
nchars
-
a number 1..255 or accumulator with a number of characters to read.
Options:
tt
-
an 16 bit register for temporary use.
check_nchars_zero
-
a boolean indicating if the accumulator should be checked against 0.
subroutine
-
if the routine should terminate with a
ret
instruction.
disable_intr
-
a boolean flag indicating that the routine should disable interrupts. Provide
false
only if you have already disabled the interrupts.
enable_intr
-
a boolean flag indicating that the routine should enable interrupts. Provide
false
if you need to perform more atomic actions.
mtyield
-
should contain an address of the kernel routine:
task_yield
.
Expects:
hl
-
an I/O buffer handle.
de
-
an address where the string will be stored.
On success accumulator contains the number of characters successfully read. If its value is 0 the ZF flag is also set indicating that no characters has been read at all. Preserves hl
registers. de
will be incremented by the number of characters read.
Modifies: af
, af'
, de
, bc
and uses stack to preserve hl
.
# File lib/zxutils/multitasking_io.rb, line 625 def mtio_gets(nchars=a, check_nchars_zero:true, subroutine:true, disable_intr:true, enable_intr:true, mtyield: task_yield) raise ArgumentError, "nchars must be accumulator or an integer: 1..255" unless nchars == a or (1..255).include?(nchars) isolate do |eoc| if nchars == a if check_nchars_zero anda a # nchars == 0 if subroutine ret Z else jr Z, eoc end end ex af, af end di if disable_intr dec hl # -> outoffs ld a, [hl] # outoffs inc hl # -> inpoffs ld c, [hl] # inpoffs sub c # a: nchars ready jr Z, eop # nothing to read inc c # inpoffs + 1 push hl # -> inpoffs dec hl # -> outoffs ld b, -1 add hl, bc ld b, a # b: nchars ready if nchars == a ex af, af else ld a, nchars end cp b # nchars < nchars ready jr NC, nchars_not_less ld b, a # counter = nchars nchars_not_less ld a, c # a: inpoffs ld c, b # c: counter min(nchars, nchars ready) dec b # b: counter - 1 add b # inpoffs = (inpoffs + counter - 1) % 256 jr NC, one_pass_only ld b, a # save inpoffs cpl # (-inpoffs - 1) % 256 add c # ((-inpoffs - 1) % 256 + counter) % 256, CF: 1 ld c, a # reduced counter to the end of the i/o buffer ld a, b # restore inpoffs one_pass_only ld b, 0 ldir # HL: -> buffer, DE: -> target jr NC, no_2nd_pass ld c, a inc c # counter = inpoffs + 1 dec h # rewind buffer ldir # DE: -> source + min(nchars, nchars ready) no_2nd_pass pop hl # -> inpoffs ld c, [hl] # prev inpoffs ld [hl], a # new inpoffs sub c # written = new inpoffs - prev inpoffs eop label ei if enable_intr ret if subroutine end end
Writes a single character to the I/O buffer.
Arguments:
char
-
a number or an 8 bit register with the character code to be written.
Options:
tt
-
an 16 bit register for temporary use.
not_ready
-
what to do when a character can't be written. A symbol
:eoc
to just signal the failure with the CF flag reset (NC) and the ZF flag set (Z). A symbol:wait
to wait until a character gets written. A label or an address to jump to when the character can't be written.
subroutine
-
if the routine should terminate with a
ret
instruction.
preserve_hl
-
if the routine should preserve the
hl
register via the stack.
disable_intr
-
a boolean flag indicating that the routine should disable interrupts. Provide
false
only if you have already disabled the interrupts.
enable_intr
-
a boolean flag indicating that the routine should enable interrupts. Provide
false
if you need to perform more atomic actions.
mtyield
-
should contain an address of the kernel routine:
task_yield
.
Expects:
hl
-
an I/O buffer handle.
On success the CF flag is set and the ZF flag is clear (NZ).
Modifies: af
, hl
, tt
, preserves: char
, optionally preserves: hl
on the machine stack.
# File lib/zxutils/multitasking_io.rb, line 549 def mtio_putc(char=e, tt:bc, not_ready: :eoc, subroutine: true, preserve_hl:true, disable_intr:true, enable_intr:true, mtyield: task_yield) th, tl = tt.split raise ArgumentError, "char must not be a tl or th or h or l" if [h,l,th,tl].include?(char) isolate do push hl if preserve_hl ld th, a if char==a repeat label di if disable_intr ld a, [hl] # inpoffs dec hl ld tl, [hl] # outoffs inc tl cp tl case not_ready when :eoc if subroutine && !enable_intr && !preserve_hl ret Z else jr Z, eop end when :wait if subroutine jr Z, wait_busy else jr NZ, skip call mtyield di unless disable_intr inc hl jr repeat end else jp Z, not_ready end skip ld [hl], tl # outoffs ld a, th if char==a ld th, -1 add hl, tt ld [hl], char eop label ei if enable_intr pop hl if preserve_hl if subroutine ret if not_ready == :wait wait_busy call mtyield di unless disable_intr inc hl jr repeat end end end end
Sends a string of characters to the I/O buffer.
Arguments:
nchars
-
a number 1..255 or accumulator with a number of characters to be sent.
Options:
tt
-
an 16 bit register for temporary use.
check_nchars_zero
-
a boolean indicating if the accumulator should be checked against 0.
subroutine
-
if the routine should terminate with a
ret
instruction.
disable_intr
-
a boolean flag indicating that the routine should disable interrupts. Provide
false
only if you have already disabled the interrupts.
enable_intr
-
a boolean flag indicating that the routine should enable interrupts. Provide
false
if you need to perform more atomic actions.
mtyield
-
should contain an address of the kernel routine:
task_yield
.
Expects:
hl
-
an I/O buffer handle.
de
-
an address of the string to be send.
On success accumulator contains the number of characters successfully sent. If its value is 0 the ZF flag is also set indicating that no characters has been sent at all. Preserves hl
registers. de
will be incremented by the number of characters sent.
Modifies: af
, af'
, de
, bc
and uses stack to preserve hl
.
# File lib/zxutils/multitasking_io.rb, line 710 def mtio_puts(nchars=a, check_nchars_zero:true, subroutine:true, disable_intr:true, enable_intr:true, mtyield: task_yield) raise ArgumentError, "nchars must be accumulator or an integer: 1..255" unless nchars == a or (1..255).include?(nchars) isolate do |eoc| if nchars == a if check_nchars_zero anda a # nchars == 0 if subroutine ret Z else jr Z, eoc end end ex af, af end di if disable_intr ld a, [hl] # -> inpoffs dec hl ld c, [hl] # -> outoffs inc c # c: outoffs + 1 sub c # a: buffer free jr Z, eop # no room to write push hl # -> outoffs ld b, -1 add hl, bc ld b, a # b: buffer free if nchars == a ex af, af else ld a, nchars end cp b # nchars < buffer free jr NC, nchars_not_less ld b, a # counter = nchars nchars_not_less ld a, c # a: outoffs ld c, b # c: counter min(nchars, buffer free) dec b # b: counter - 1 add b # outoffs = (outoffs + counter - 1) % 256 jr NC, one_pass_only ld b, a # save outoffs cpl # (-outoffs - 1) % 256 add c # ((-outoffs - 1) % 256 + counter) % 256, CF: 1 ld c, a # reduced counter to the end of the i/o buffer ld a, b # restore outoffs one_pass_only ld b, 0 ex de, hl # DE: -> buffer, HL: -> source ldir jr NC, no_2nd_pass ld c, a inc c # counter = outoffs + 1 dec d # rewind buffer ldir no_2nd_pass ex de, hl # DE: -> source + min(nchars, buffer free) pop hl # -> outoffs ld c, [hl] # prev outoffs ld [hl], a # new outoffs sub c # written = new outoffs - prev outoffs eop inc hl # -> inpoffs ei if enable_intr ret if subroutine end end
Checks I/O buffer's data availability.
Arguments:
action
-
a symbol
:read
to get the information if the data is ready to be read, a symbol:write
to get the information if the data can be written.
nchars
-
nil
to get a simple boolean answer or a number or an 8 bit register which should contain a number of characters that should be available for reading or writing.
Options:
disable_intr
-
a boolean flag indicating that the routine should disable interrupts. Provide
false
only if you have already disabled the interrupts.
enable_intr
-
a boolean flag indicating that the routine should enable interrupts. Provide
false
if you need to perform more atomic actions.
Expects:
hl
-
an I/O buffer handle.
Depending on the selected action and whether nchars
option was nil
or not, on return:
action nchars status flags accumulator *any* nil not ready ZF=1 (Z) 0 :read nil ready ZF=0 (NZ) no of characters ready to be read <= 255 :write nil ready ZF=0 (NZ) no of characters already written + 1 <= 255 :read number not ready CF=1 (C) no of characters ready to be read < nchars :read number ready CF=0 (NC) no of characters ready to be read >= nchars :write number not ready CF=1 (C) no of characters that won't fit into the buffer - 1 < nchars :write number ready CF=0 (NC) no of characters already written + nchars <= 255
Modifies: af
, preserves: hl
and nchars
.
# File lib/zxutils/multitasking_io.rb, line 369 def mtio_ready?(action, nchars:nil, disable_intr:true, enable_intr:true) raise ArgumentError, "action must be one of: :read or :write" unless action==:read or action==:write raise ArgumentError, "nchars must not be one of: a, h nor l" if [a, h, l].include?(nchars) isolate do dec hl di if disable_intr ld a, [hl] # outoffs inc hl ei if enable_intr sub [hl] # inpoffs if nchars case action when :read cp nchars when :write add nchars end else inc a if action == :write end end end
Waits for the I/O buffer's data availability.
Arguments:
action
-
a symbol
:read
to wait for the data to be read, a symbol:write
to wait for the data to be written.
nchars
-
a number or an 8 bit register which should contain a number of characters that should be available for reading or writing.
Options:
disable_intr
-
a boolean flag indicating that the routine should disable interrupts. Provide
false
only if you have already disabled the interrupts.
enable_intr
-
a boolean flag indicating that the routine should enable interrupts. Provide
false
if you need to perform more atomic actions.
mtyield
-
should contain an address of the kernel routine:
task_yield
.
Expects:
hl
-
an I/O buffer handle.
On return a CF flag always cleared and accumulator contains a number of characters ready to be read or a number of characters already written + nchars.
Modifies: af
, preserves: hl
and nchars
.
# File lib/zxutils/multitasking_io.rb, line 413 def mtio_wait(action, nchars=1, disable_intr:true, enable_intr:true, mtyield:task_yield) raise ArgumentError, "nchars must not be nil" if nchars.nil? isolate do |eoc| check_ready mtio_ready?(action, nchars:nchars, disable_intr:disable_intr, enable_intr:enable_intr) jr NC, eoc call mtyield di unless disable_intr jr check_ready end end