It works!
This commit is contained in:
parent
cea66fe916
commit
a356f6a3a7
|
@ -118,7 +118,7 @@ def audio_bytestream(data: numpy.ndarray, step: int, lookahead_steps: int,
|
|||
|
||||
clicks = 0
|
||||
min_lookahead_steps = lookahead_steps
|
||||
while i < dlen // 10:
|
||||
while i < dlen // 1:
|
||||
if i >= next_tick:
|
||||
eta.print_status()
|
||||
next_tick = int(eta.i * dlen / 1000)
|
||||
|
@ -164,12 +164,12 @@ def audio_bytestream(data: numpy.ndarray, step: int, lookahead_steps: int,
|
|||
numpy.mean(data[i:i + opcode_length]))
|
||||
|
||||
# print(frame_offset, i / sample_rate, opcode)
|
||||
for v in all_positions[0]:
|
||||
yield (v * sp.scale).astype(numpy.float32)
|
||||
# for v in all_positions[0]:
|
||||
# yield
|
||||
# # print(v * sp.scale)
|
||||
# if frame_offset == 2047:
|
||||
# print(opcode)
|
||||
# yield opcode
|
||||
yield opcode, (all_positions * sp.scale).astype(numpy.float32)
|
||||
|
||||
i += opcode_length
|
||||
frame_offset = (frame_offset + 1) % 2048
|
||||
|
@ -244,6 +244,7 @@ def main():
|
|||
parser.add_argument("--norm_percentile", default=100,
|
||||
help="Normalize to specified percentile value of input "
|
||||
"audio")
|
||||
parser.add_argument("--wav_output", type=str, help="output audio file")
|
||||
parser.add_argument("--noise_output", type=str, help="output audio file")
|
||||
parser.add_argument("input", type=str, help="input audio file to convert")
|
||||
parser.add_argument("output", type=str, help="output audio file")
|
||||
|
@ -262,8 +263,13 @@ def main():
|
|||
output_buffer = []
|
||||
input_offset = 0
|
||||
|
||||
output_context = sf.SoundFile(
|
||||
args.output, "w", output_rate, channels=1, format='WAV')
|
||||
opcode_context = open(args.output, "wb+")
|
||||
|
||||
if args.wav_output:
|
||||
wav_context = sf.SoundFile(
|
||||
args.wav_output, "w", output_rate, channels=1, format='WAV')
|
||||
else:
|
||||
wav_context = contextlib.nullcontext
|
||||
|
||||
if args.noise_output:
|
||||
noise_context = sf.SoundFile(
|
||||
|
@ -273,12 +279,19 @@ def main():
|
|||
# We're not creating a file but still need a context
|
||||
noise_context = contextlib.nullcontext
|
||||
|
||||
with output_context as output_f, noise_context as noise_f:
|
||||
for idx, sample in enumerate(audio_bytestream(
|
||||
with wav_context as wav_f, noise_context as noise_f, opcode_context\
|
||||
as opcode_f:
|
||||
for idx, sample_data in enumerate(audio_bytestream(
|
||||
input_audio, args.step_size, args.lookahead_cycles,
|
||||
sample_rate)):
|
||||
output_buffer.append(sample)
|
||||
input_offset += 1
|
||||
opcode, samples = sample_data
|
||||
# print(hex(idx), opcode, hex(opcode.byte))
|
||||
opcode_f.write(bytes([opcode.byte]))
|
||||
|
||||
output_buffer.extend(samples)
|
||||
input_offset += len(samples)
|
||||
|
||||
# TODO: don't bother computing if we're not writing wavs
|
||||
|
||||
# Keep accumulating as long as we have <10MB in the buffer, or are
|
||||
# within 10MB from the end. This ensures we have enough samples to
|
||||
|
@ -291,7 +304,8 @@ def main():
|
|||
output_buffer, input_audio[input_offset - len(output_buffer):],
|
||||
sample_rate, output_rate, bool(args.noise_output)
|
||||
)
|
||||
output_f.write(resampled_output_buffer)
|
||||
if args.wav_output:
|
||||
wav_f.write(resampled_output_buffer)
|
||||
if args.noise_output:
|
||||
noise_f.write(resampled_noise_buffer)
|
||||
|
||||
|
@ -302,11 +316,12 @@ def main():
|
|||
output_buffer, input_audio[input_offset - len(output_buffer):],
|
||||
sample_rate, output_rate, bool(args.noise_output)
|
||||
)
|
||||
output_f.write(resampled_output_buffer)
|
||||
if args.wav_output:
|
||||
wav_f.write(resampled_output_buffer)
|
||||
if args.noise_output:
|
||||
noise_f.write(resampled_noise_buffer)
|
||||
|
||||
# with open(args.output, "wb+") as f:
|
||||
# with as f:
|
||||
# for opcode in audio_bytestream(
|
||||
# preprocess(args.input, sample_rate, args.normalization,
|
||||
# args.norm_percentile), args.step_size,
|
||||
|
|
|
@ -83,12 +83,12 @@ def eof_trampoline_stage2(cycles) -> List[opcodes_6502.Opcode]:
|
|||
ops = [
|
||||
opcodes_6502.Opcode(4, 3, "LDA WDATA"),
|
||||
opcodes_6502.Opcode(4, 3, "STA @0+1"),
|
||||
opcodes_6502.Literal("@0:", indent=0),
|
||||
opcodes_6502.Opcode(
|
||||
6, 3, "JMP (eof_trampoline_%d_stage3_page)" % cycles)
|
||||
]
|
||||
if cycles < 7 or cycles == 8:
|
||||
return label + ops
|
||||
return label + ops[:-1] + [opcodes_6502.Literal("@0:", indent=0)] + [
|
||||
ops[-1]]
|
||||
|
||||
# For cycles == 7 or > 8 we need to interleave a STA $C030 into stage 2
|
||||
# because we couldn't fit it in stage 1
|
||||
|
@ -97,7 +97,12 @@ def eof_trampoline_stage2(cycles) -> List[opcodes_6502.Opcode]:
|
|||
opcodes_6502.STA_C030,
|
||||
opcodes_6502.padding(100)
|
||||
]
|
||||
return label + list(opcodes_6502.interleave_opcodes(interleave_ops, ops))
|
||||
res = label + list(opcodes_6502.interleave_opcodes(interleave_ops, ops))
|
||||
# We can't insert the label before interleaving because we might have
|
||||
# NOP/STA inserted after it
|
||||
# TODO: this is a bit of a hack - add support for binding the literal to
|
||||
# the following opcode so it can't be split
|
||||
return res[:-1] + [opcodes_6502.Literal("@0:", indent=0)] + [res[-1]]
|
||||
|
||||
|
||||
EOF_TRAMPOLINE_STAGE2 = {
|
||||
|
|
|
@ -8,7 +8,7 @@ objects = $(patsubst %.s,%.o,$(src_files))
|
|||
all: $(DISKIMAGE)
|
||||
|
||||
%.o : %.s
|
||||
ca65 -t apple2 --cpu 6502 -o $@ $<
|
||||
ca65 -t apple2 --cpu 6502 -o $@ -l player.lst $<
|
||||
|
||||
%.system : %.o
|
||||
cl65 -t apple2 -C make/apple2-asm-system.cfg -u __EXEHDR__ --start-addr 0x2000 -o $@ $<
|
||||
|
|
|
@ -18,5 +18,6 @@ SEGMENTS {
|
|||
CODE: load = MAIN, type = rw;
|
||||
RODATA: load = MAIN, type = ro, optional = yes;
|
||||
DATA: load = MAIN, type = rw, optional = yes;
|
||||
DATA256: load = MAIN, type = rw, optional = yes, align = $100;
|
||||
BSS: load = BSS, type = bss, optional = yes, define = yes;
|
||||
}
|
||||
|
|
Binary file not shown.
372
player/player.s
372
player/player.s
|
@ -36,8 +36,6 @@
|
|||
; speaker is in a known trajectory. We can compensate for this in the audio encoder.
|
||||
|
||||
.proc main
|
||||
.org $2000
|
||||
|
||||
init:
|
||||
JMP bootstrap
|
||||
|
||||
|
@ -53,10 +51,10 @@ MAC: .byte $00,$08,$DC,$01,$02,$03 ; W5100 MAC ADDRESS
|
|||
; TODO: make slot I/O addresses customizable at runtime - would probably require somehow
|
||||
; compiling a list of all of the binary offsets at which we reference $C09x and patching
|
||||
; them in memory or on-disk.
|
||||
WMODE = $C094
|
||||
WADRH = $C095
|
||||
WADRL = $C096
|
||||
WDATA = $C097
|
||||
WMODE = $C0b4
|
||||
WADRH = $C0b5
|
||||
WADRL = $C0b6
|
||||
WDATA = $C0b7
|
||||
|
||||
; W5100 LOCATIONS
|
||||
MACADDR = $0009 ; MAC ADDRESS
|
||||
|
@ -271,12 +269,23 @@ setup:
|
|||
lda #$00
|
||||
sta RXRD
|
||||
|
||||
; to restore after checkrecv
|
||||
LDY #>RXBASE
|
||||
LDX #>S0RXRSR
|
||||
STX WADRH
|
||||
LDX #<S0RXRSR
|
||||
JMP checkrecv
|
||||
|
||||
fill_socket:
|
||||
LDA #$07 ; 2
|
||||
@0:
|
||||
STX WADRL ; #<S0RXRSR
|
||||
CMP WDATA ; High byte of received size
|
||||
BCS @0 ; in common case when there is already sufficient data waiting.
|
||||
; There is data to read - we don't care exactly how much because it's at least 2K
|
||||
; point to start of socket buffer
|
||||
LDX #>RXBASE
|
||||
STX WADRH
|
||||
LDX #$00
|
||||
STX WADRL
|
||||
JMP (WDATA) ; Start playing!
|
||||
|
||||
real_exit:
|
||||
INC RESET_VECTOR+2 ; Invalidate power-up byte
|
||||
|
@ -291,10 +300,13 @@ exit_parmtable:
|
|||
.BYTE 0 ; Byte reserved for future use
|
||||
.WORD 0000 ; Pointer reserved for future use
|
||||
|
||||
; The actual player code, which will be copied to $3xx for execution
|
||||
;
|
||||
; opcode cycle counts are for 65c02, for 6502 they are 1 less because JMP (indirect) is 5 cycles instead of 6.
|
||||
RXRD:
|
||||
.byte 00
|
||||
|
||||
; Stage 2 and 3 player code
|
||||
.include "player_stage2_3_generated.s"
|
||||
|
||||
; Stage 1 player code, which will be copied to $3xx for execution
|
||||
begin_copy_page1:
|
||||
; generated audio playback code
|
||||
.include "player_generated.s"
|
||||
|
@ -302,339 +314,11 @@ begin_copy_page1:
|
|||
; Quit to ProDOS
|
||||
exit:
|
||||
JMP real_exit
|
||||
|
||||
; Manage W5100 socket buffer and ACK TCP stream.
|
||||
;
|
||||
; In order to simplify the buffer management we expect this ACK opcode to consume the last 4 bytes in a 2K "TCP frame".
|
||||
; i.e. we can assume that we need to consume exactly 2K from the W5100 socket buffer.
|
||||
;
|
||||
; While during this we need to keep ticking the speaker at a regular cadence to maintain the same net position of the
|
||||
; speaker cone. We choose to tick every 14 cycles, which requires adding in minimal NOP padding.
|
||||
;
|
||||
; We end up ticking 8 times with 10 cycles left over, assuming we don't stall waiting for the socket buffer to refill.
|
||||
;
|
||||
; From the point of view of speaker voltages this slowpath is equivalent to the following opcode sequence:
|
||||
; TICK_6 (TICK_14 * 7) with 4 cycles left over, adding 4 to the effective n of the next TICK_n we jump to (as chosen by
|
||||
; the encoder). XXX timing
|
||||
;
|
||||
; If we do stall waiting for data then there is no need to worry about maintaining an even cadence, because audio
|
||||
; will already be disrupted (since the encoder won't have predicted it, so will be tracking wrong). The speaker will
|
||||
; resynchronize within a few hundred microseconds though.
|
||||
end_of_frame_10_10:
|
||||
STA TICK ; 4
|
||||
JMP _end_of_frame_10_10 ; 3 rest of end_of_frame doesn't fit in page 3
|
||||
|
||||
end_of_frame_20_4:
|
||||
STA TICK ; 4
|
||||
JMP _end_of_frame_10_10 ; 3 rest of end_of_frame doesn't fit in page 3
|
||||
|
||||
end_copy_page1:
|
||||
;
|
||||
;_end_of_frame:
|
||||
; STA zpdummy ; 3
|
||||
; ; Save the W5100 address pointer so we can come back here later
|
||||
; ; We know the low-order byte is 0 because Socket RX memory is page-aligned and so is 2K frame.
|
||||
; ; IMPORTANT - from now on until we restore this below, we can't trash the Y register!
|
||||
; STA TICK ; 4 [10]
|
||||
; LDY WADRH ; 4
|
||||
;
|
||||
; ; Read Received Read pointer
|
||||
; LDA #>S0RXRD ; 2
|
||||
; STA TICK ; 4 [10]
|
||||
; STA WADRH ; 4
|
||||
;
|
||||
; LDX #<S0RXRD ; 2
|
||||
; STA TICK ; 4 [10]
|
||||
;
|
||||
; STX WADRL ; 4
|
||||
; NOP ; 2
|
||||
; STA TICK ; 4 [10]
|
||||
; LDA WDATA ; 4 Read high byte
|
||||
;
|
||||
; ; No need to read low byte since it's guaranteed to be 0 since we're at the end of a 2K frame.
|
||||
;
|
||||
; ; Update new Received Read pointer
|
||||
; ; We have received an additional 2KB
|
||||
; CLC ; 2
|
||||
; STA TICK ; 4 [10]
|
||||
; ADC #$08 ; 2
|
||||
;
|
||||
; STX WADRL ; 4 Reset address pointer, X still has #<S0RXRD
|
||||
; STA TICK ; 4 [10]
|
||||
; ; No need to store low byte since it's unchanged at 0
|
||||
; STA WDATA ; 4 Store new high byte
|
||||
;
|
||||
; ; Send the Receive command
|
||||
; LDA #<S0CR ; 2
|
||||
; STA TICK ; 4 [10]
|
||||
; STA WADRL ; 4
|
||||
;
|
||||
; LDA #SCRECV ; 2
|
||||
; STA TICK ; 4 [10]
|
||||
; STA WDATA ; 4
|
||||
;
|
||||
;checkrecv:
|
||||
; LDA #<S0RXRSR ; 2 Socket 0 Received Size register
|
||||
; STA TICK ; 4 [10]
|
||||
; LDX #$07 ; 2
|
||||
; NOP ; 2
|
||||
; NOP ; 2
|
||||
; STA TICK ; 4 [10]
|
||||
; ; we might loop an unknown number of times here waiting for data but the default should be to fall
|
||||
; ; straight through
|
||||
;@0:
|
||||
; STA WADRL ; 4
|
||||
; NOP ; 2
|
||||
; STA TICK ; 4 [10]
|
||||
; CPX WDATA ; 4 High byte of received size
|
||||
; BCS @0 ; 2 in common case when there is already sufficient data waiting.
|
||||
; STA TICK ; 4 [10]
|
||||
;
|
||||
; ; point W5100 back into the RX buffer where we left off
|
||||
; ; There is data to read - we don't care exactly how much because it's at least 2K
|
||||
; ;
|
||||
; ; Restore W5100 address pointer where we last found it.
|
||||
; ;
|
||||
; ; It turns out that the W5100 automatically wraps the address pointer at the end of the 8K RX/TX buffers
|
||||
; ; Since we're using an 8K socket, that means we don't have to do any work to manage the read pointer!
|
||||
; STY WADRH ; 4
|
||||
; LDX #$00 ; 2
|
||||
; STA TICK ; 4 [10]
|
||||
;
|
||||
; STX WADRL ; 4
|
||||
; NOP ; 2
|
||||
; STA TICK ; 4 [10]
|
||||
; JMP (WDATA) ; 6
|
||||
;.endproc
|
||||
|
||||
.segment "DATA256"
|
||||
begin_copy_page8:
|
||||
.include "player_stage3_table_generated.s"
|
||||
end_copy_page8:
|
||||
|
||||
; 72 cycles --> 133 with tick padding
|
||||
; + 7 from dispatcher = 140 total
|
||||
_end_of_frame_10_10:
|
||||
; Save the W5100 address pointer so we can come back here later
|
||||
; We know the low-order byte is 0 because Socket RX memory is page-aligned and so is 2K frame.
|
||||
; IMPORTANT - from now on until we restore this below, we can't trash the Y register!
|
||||
STA zpdummy ; 3
|
||||
STA TICK ; 4
|
||||
LDY WADRH ; 4
|
||||
|
||||
; Update new Received Read pointer
|
||||
; We know we have received an additional 2KB, so we don't need to read the current value from the hardware. We can
|
||||
; track it ourselves instead.
|
||||
LDA #>S0RXRD ; 2
|
||||
STA TICK ; [10]
|
||||
STA WADRH ; 4
|
||||
LDX #<S0RXRD ; 2
|
||||
STA TICK ; [10]
|
||||
STX WADRL ; 4
|
||||
|
||||
CLC ; 2
|
||||
STA TICK ; [10]
|
||||
LDA RXRD ; 4
|
||||
ADC #$08 ; 2
|
||||
STA TICK ; [10]
|
||||
STA WDATA ; 4 Store new high byte
|
||||
LDX #<S0CR ; 2 prepare to reset WADRL
|
||||
STA TICK ; [10]
|
||||
STA RXRD ; 4
|
||||
|
||||
; Send the Receive command
|
||||
LDA #SCRECV ; 2
|
||||
STA TICK ; [10]
|
||||
STX WADRL ; 4
|
||||
LDX #<S0RXRSR ; 2 Socket 0 Received Size register
|
||||
STA TICK ; [10]
|
||||
STA WDATA ; 4 #SCRECV
|
||||
|
||||
checkrecv:
|
||||
LDA #$07 ; 2
|
||||
; we might loop an unknown number of times here waiting for data but the default should be to fall
|
||||
; straight through
|
||||
@0:
|
||||
STA TICK ; [10]
|
||||
STX WADRL ; 4 #<S0RXRSR
|
||||
NOP ; 2
|
||||
STA TICK ; [10]
|
||||
CMP WDATA ; 4 High byte of received size
|
||||
BCS @0 ; 2 in common case when there is already sufficient data waiting.
|
||||
STA TICK ; [10]
|
||||
; point W5100 back into the RX buffer where we left off
|
||||
; There is data to read - we don't care exactly how much because it's at least 2K
|
||||
;
|
||||
; Restore W5100 address pointer where we last found it.
|
||||
;
|
||||
; It turns out that the W5100 automatically wraps the address pointer at the end of the 8K RX/TX buffers
|
||||
; Since we're using an 8K socket, that means we don't have to do any work to manage the read pointer!
|
||||
STY WADRH ; 4
|
||||
LDX #$00 ; 2
|
||||
STA TICK ; [10]
|
||||
STX WADRL ; 4
|
||||
NOP ; 2
|
||||
STA TICK ; [10]
|
||||
JMP (WDATA) ; 6
|
||||
|
||||
; 74 cycles + 7 from dispatcher = 81 total
|
||||
_end_of_frame:
|
||||
; Save the W5100 address pointer so we can come back here later
|
||||
; We know the low-order byte is 0 because Socket RX memory is page-aligned and so is 2K frame.
|
||||
; IMPORTANT - from now on until we restore this below, we can't trash the Y register!
|
||||
LDY WADRH ; 4
|
||||
|
||||
; Update new Received Read pointer
|
||||
; We know we have received an additional 2KB, so we don't need to read the current value from the hardware. We can
|
||||
; track it ourselves instead.
|
||||
LDA #>S0RXRD ; 2
|
||||
STA WADRH ; 4
|
||||
LDA #<S0RXRD ; 2
|
||||
STA WADRL ; 4
|
||||
|
||||
; TODO: in principle we could prepare this outside of the EOF path
|
||||
LDA RXRD ; 4
|
||||
CLC ; 2
|
||||
ADC #$08 ; 2
|
||||
STA WDATA ; 4 Store new high byte
|
||||
STA RXRD ; 4 Save for next time
|
||||
|
||||
; Send the Receive command
|
||||
LDA #<S0CR ; 2 prepare to reset WADRL
|
||||
STA WADRL ; 4
|
||||
LDA #SCRECV ; 2
|
||||
STA WDATA ; 4 #SCRECV
|
||||
|
||||
LDA #$07 ; 2
|
||||
; we might loop an unknown number of times here waiting for data but the default should be to fall
|
||||
; straight through
|
||||
LDX #<S0RXRSR ; 2 Socket 0 Received Size register
|
||||
@0:
|
||||
STX WADRL ; 4 #<S0RXRSR
|
||||
CMP WDATA ; 4 High byte of received size
|
||||
BCS @0 ; 2 in common case when there is already sufficient data waiting.
|
||||
; point W5100 back into the RX buffer where we left off
|
||||
; There is data to read - we don't care exactly how much because it's at least 2K
|
||||
;
|
||||
; Restore W5100 address pointer where we last found it.
|
||||
;
|
||||
; It turns out that the W5100 automatically wraps the address pointer at the end of the 8K RX/TX buffers
|
||||
; Since we're using an 8K socket, that means we don't have to do any work to manage the read pointer!
|
||||
STY WADRH ; 4
|
||||
LDA #$00 ; 2
|
||||
STA WADRL ; 4
|
||||
JMP (WDATA) ; 6
|
||||
|
||||
; 4 20 4 20 4 20 4 20 4 20 4 6 = 130
|
||||
_end_of_frame_4_20:
|
||||
; Save the W5100 address pointer so we can come back here later
|
||||
; We know the low-order byte is 0 because Socket RX memory is page-aligned and so is 2K frame.
|
||||
; IMPORTANT - from now on until we restore this below, we can't trash the Y register!
|
||||
LDY WADRH ; 4
|
||||
STA zpdummy ; 3
|
||||
|
||||
; Update new Received Read pointer
|
||||
; We know we have received an additional 2KB, so we don't need to read the current value from the hardware. We can
|
||||
; track it ourselves instead.
|
||||
LDA #>S0RXRD ; 2
|
||||
STA WADRH ; 4
|
||||
STA TICK ; 4 [20]
|
||||
STA TICK ; 4 [4]
|
||||
LDA #<S0RXRD ; 2
|
||||
STA WADRL ; 4
|
||||
|
||||
; TODO: in principle we could prepare this outside of the EOF path
|
||||
LDA RXRD ; 4
|
||||
CLC ; 2
|
||||
ADC #$08 ; 2
|
||||
NOP ; 2 XXX
|
||||
STA TICK ; 4 [20]
|
||||
STA TICK ; 4 [4]
|
||||
STA WDATA ; 4 Store new high byte
|
||||
STA RXRD ; 4 Save for next time
|
||||
|
||||
; Send the Receive command
|
||||
LDA #<S0CR ; 2 prepare to reset WADRL
|
||||
STA WADRL ; 4
|
||||
LDA #SCRECV ; 2
|
||||
STA TICK ; 4 [20]
|
||||
STA TICK ; 4 [4]
|
||||
STA WDATA ; 4 #SCRECV
|
||||
|
||||
LDA #$07 ; 2
|
||||
; we might loop an unknown number of times here waiting for data but the default should be to fall
|
||||
; straight through
|
||||
LDX #<S0RXRSR ; 2 Socket 0 Received Size register
|
||||
@0:
|
||||
STX WADRL ; 4 #<S0RXRSR
|
||||
CMP WDATA ; 4 High byte of received size
|
||||
STA TICK ; 4 [20]
|
||||
STA TICK ; 4 [4]
|
||||
BCS @0 ; 2 in common case when there is already sufficient data waiting.
|
||||
; point W5100 back into the RX buffer where we left off
|
||||
; There is data to read - we don't care exactly how much because it's at least 2K
|
||||
;
|
||||
; Restore W5100 address pointer where we last found it.
|
||||
;
|
||||
; It turns out that the W5100 automatically wraps the address pointer at the end of the 8K RX/TX buffers
|
||||
; Since we're using an 8K socket, that means we don't have to do any work to manage the read pointer!
|
||||
STY WADRH ; 4
|
||||
LDA #$00 ; 2
|
||||
STA WADRL ; 4
|
||||
NOP ; 2
|
||||
NOP ; 2
|
||||
STA TICK ; 4 [20]
|
||||
STA TICK ; 4 [4]
|
||||
JMP (WDATA) ; 6
|
||||
|
||||
; 4
|
||||
_end_of_frame_4_10:
|
||||
; Save the W5100 address pointer so we can come back here later
|
||||
; We know the low-order byte is 0 because Socket RX memory is page-aligned and so is 2K frame.
|
||||
; IMPORTANT - from now on until we restore this below, we can't trash the Y register!
|
||||
STA zpdummy ; 3
|
||||
STA TICK ; [10]
|
||||
STA TICK ; [4]
|
||||
LDY WADRH ; 4
|
||||
|
||||
; Update new Received Read pointer
|
||||
; We know we have received an additional 2KB, so we don't need to read the current value from the hardware. We can
|
||||
; track it ourselves instead.
|
||||
LDA #>S0RXRD ; 2
|
||||
STA WADRH ; 4
|
||||
LDA #<S0RXRD ; 2
|
||||
STA WADRL ; 4
|
||||
|
||||
; TODO: in principle we could prepare this outside of the EOF path
|
||||
LDA RXRD ; 4
|
||||
CLC ; 2
|
||||
ADC #$08 ; 2
|
||||
STA WDATA ; 4 Store new high byte
|
||||
STA RXRD ; 4 Save for next time
|
||||
|
||||
; Send the Receive command
|
||||
LDA #<S0CR ; 2 prepare to reset WADRL
|
||||
STA WADRL ; 4
|
||||
LDA #SCRECV ; 2
|
||||
STA WDATA ; 4 #SCRECV
|
||||
|
||||
LDA #$07 ; 2
|
||||
; we might loop an unknown number of times here waiting for data but the default should be to fall
|
||||
; straight through
|
||||
LDX #<S0RXRSR ; 2 Socket 0 Received Size register
|
||||
@0:
|
||||
STX WADRL ; 4 #<S0RXRSR
|
||||
CMP WDATA ; 4 High byte of received size
|
||||
BCS @0 ; 2 in common case when there is already sufficient data waiting.
|
||||
; point W5100 back into the RX buffer where we left off
|
||||
; There is data to read - we don't care exactly how much because it's at least 2K
|
||||
;
|
||||
; Restore W5100 address pointer where we last found it.
|
||||
;
|
||||
; It turns out that the W5100 automatically wraps the address pointer at the end of the 8K RX/TX buffers
|
||||
; Since we're using an 8K socket, that means we don't have to do any work to manage the read pointer!
|
||||
STY WADRH ; 4
|
||||
LDA #$00 ; 2
|
||||
STA WADRL ; 4
|
||||
JMP (WDATA) ; 6
|
||||
|
||||
|
||||
RXRD:
|
||||
.byte 00
|
||||
.endproc
|
||||
|
|
|
@ -90,35 +90,35 @@ eof_trampoline_16_stage2:
|
|||
eof_trampoline_17_stage2:
|
||||
LDA WDATA ; 4 cycles
|
||||
STA @0+1 ; 4 cycles
|
||||
@0:
|
||||
NOP ; 2 cycles
|
||||
STA $C030 ; 4 cycles
|
||||
@0:
|
||||
JMP (eof_trampoline_17_stage3_page) ; 6 cycles
|
||||
|
||||
eof_trampoline_18_stage2:
|
||||
LDA WDATA ; 4 cycles
|
||||
STA @0+1 ; 4 cycles
|
||||
@0:
|
||||
STA zpdummy ; 3 cycles
|
||||
STA $C030 ; 4 cycles
|
||||
@0:
|
||||
JMP (eof_trampoline_18_stage3_page) ; 6 cycles
|
||||
|
||||
eof_trampoline_19_stage2:
|
||||
LDA WDATA ; 4 cycles
|
||||
STA @0+1 ; 4 cycles
|
||||
@0:
|
||||
NOP ; 2 cycles
|
||||
NOP ; 2 cycles
|
||||
STA $C030 ; 4 cycles
|
||||
@0:
|
||||
JMP (eof_trampoline_19_stage3_page) ; 6 cycles
|
||||
|
||||
eof_trampoline_20_stage2:
|
||||
LDA WDATA ; 4 cycles
|
||||
STA @0+1 ; 4 cycles
|
||||
@0:
|
||||
NOP ; 2 cycles
|
||||
STA zpdummy ; 3 cycles
|
||||
STA $C030 ; 4 cycles
|
||||
@0:
|
||||
JMP (eof_trampoline_20_stage3_page) ; 6 cycles
|
||||
|
||||
eof_trampoline_21_stage2:
|
||||
|
@ -130,11 +130,11 @@ eof_trampoline_21_stage2:
|
|||
eof_trampoline_22_stage2:
|
||||
LDA WDATA ; 4 cycles
|
||||
STA @0+1 ; 4 cycles
|
||||
@0:
|
||||
NOP ; 2 cycles
|
||||
NOP ; 2 cycles
|
||||
STA zpdummy ; 3 cycles
|
||||
STA $C030 ; 4 cycles
|
||||
@0:
|
||||
JMP (eof_trampoline_22_stage3_page) ; 6 cycles
|
||||
|
||||
eof_stage_2_10_10:
|
||||
|
|
Loading…
Reference in New Issue