You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- check that Sio is in the **ACTIVE** state before continuing
228
-
- use `ld a, [hl+]` to access `wSioState` and advance `hl` to `wSioCount`
229
-
- update `wSioCount` using `dec [hl]`
230
-
- which you might not have seen before?
231
-
- this works out a bit faster than reading number into `a`, decrementing it, storing it again
232
-
233
-
- NOTE: at this point we are avoiding using opcodes that set the zero flag as we want to check the result of decrementing `wSioCount` shortly.
234
-
235
-
- construct a buffer Rx pointer using `wSioBufferOffset`
236
-
- load the value from wram into the `l` register
237
-
- load the `h` register with the constant high byte of the buffer Rx address space
238
-
239
-
- grab the received value from `rSB` and copy it to the buffer Rx
240
-
- we need to increment the buffer offset ...
241
-
- `hl` is incremented here but we know only `l` will be affected because of the buffer alignment
242
-
- the updated buffer pointer is stored
243
-
244
-
- now we check the transfer count remaining
245
-
- the `z` flag was updated by the `dec` instruction earlier -- none of the instructions in between modify the flags.
246
-
247
-
- if the count is more than zero (i.e. more bytes to transfer) start the next byte transfer
248
-
- construct a buffer Tx pointer in `hl` by setting `h` to the high byte of the buffer Tx address. keep `l`, which has the updated buffer position.
249
-
- load the next tx value into `rSB` and activate the serial port!
250
-
251
-
- otherwise the count is zero, we just completed the final byte transfer, so set `SIO_DONE` and return.
252
-
253
-
---
221
+
`SioPortEnd` starts by checking that a transfer was started (the `SIO_ACTIVE` state).
222
+
We're receiving a byte, so the transfer counter (`wSioCount`) is reduced by one.
223
+
The received value is copied from the serial port (`rSB`) to Sio's buffer (`wSioBufferRx`).
224
+
If there are still bytes to transfer (transfer counter is greater than zero) the next value is loaded from `wSioBufferTx` and the transfer is started by `SioPortStart`.
225
+
Otherwise, if the transfer counter is zero, enter the `SIO_DONE` state.
254
226
255
227
`SioPortEnd` must be called once after each byte transfer.
256
228
To do this we'll use the serial interrupt:
@@ -259,21 +231,12 @@ To do this we'll use the serial interrupt:
All this short routine really *does* is `call SioPortEnd`.
263
-
But because this is an interrupt handler we have to do a little dance to prevent *bad things* from happening.
264
-
We need to preserve the values in the registers that will be modified by `SioPortEnd`, `af` and `hl`.
265
-
/// make sure the registers are in the same state as when the interrupt occured so that when the interrupted code is resumed, it can continue as if nothing happened.
266
-
*The stack* is the perfect way to do this.
267
-
`push` copies the value from the register to the top of the stack and `pop` takes the top value off of the stack and moves it to the register.
268
-
Note that a stack is a first-in first-out (FIFO) container, so we push `af` then `hl` -- leaving `hl` on the top -- and pop `hl` then `af`.
234
+
This is an interrupt handler -- a special piece of code that gets called by the CPU under certain conditions.
235
+
The serial interrupt occurs when the serial port completes a transfer.
269
236
270
-
:::tip We interrupt this broadcast to briefly explain what interrupts are
271
-
272
-
An interrupt is a way to run a certain piece of code when an external event occurs.
273
-
Interrupts are requested by *peripherals* (hardware connected to the CPU) and the CPU literally interrupts whatever it was doing to go an execute some different code instead.
274
-
In this case, the event is the serial port counting to eight (meaning a whole byte was transferred), and the code that will be executed is whatever is at memory address `$58` -- the routine above.
275
-
276
-
:::
237
+
All this code does is invoke `SioPortEnd` safely.
238
+
The state of the CPU registers that `SioPortEnd` modifies are preserved by *pushing* them to the stack before the `call`, then restored by *popping* them off the stack afterwards.
239
+
If we didn't do this, the interrupted code would likely break when the registers are suddenly modified out of nowhere.
0 commit comments