1540 memory write
Moderator: Moderators
1540 memory write
I was trying to add support for the 1540 drive in my loader code and it looks like memory write operations aren't reliable. I don't have the drive so I'm only doing this in VICE. Is there something I need to do to make the operation work reliably? I read that there's some kind of speed difference between 1540 and 1541 but 1540 should work well on VIC20 but in my case it doesn't work. I run the same well tested code on a 1541 and that works.
Re: 1540 memory write
Try true drive emulation, it might fix the timing issue.
Vic20-Ian
The best things in life are Vic-20
Upgrade all new gadgets and mobiles to 3583 Bytes Free today! Ready
The best things in life are Vic-20
Upgrade all new gadgets and mobiles to 3583 Bytes Free today! Ready
Re: 1540 memory write
Just to clarify: it works in xvic with 1541 emulation, but not with 1540 emulation?bjonte wrote: ↑Thu Jul 22, 2021 3:18 am I was trying to add support for the 1540 drive in my loader code and it looks like memory write operations aren't reliable. I don't have the drive so I'm only doing this in VICE. Is there something I need to do to make the operation work reliably? I read that there's some kind of speed difference between 1540 and 1541 but 1540 should work well on VIC20 but in my case it doesn't work. I run the same well tested code on a 1541 and that works.
The hardware of a 1540 is identical to an early 1541 but on the 1541 there are relaxed timings in the IEC bus code to allow for badline DMA interruptions on a c64. Running a 1540 or a 1541 with a vic-20 should work always although the 1541 would have slightly slower transfer speeds.
Re: 1540 memory write
What happens with an emulated 1541 when you set it to use VIC-20 timing using UI-?
Re: 1540 memory write
Yes.
Hmm, OK. Thanks for the explanation of the slower mode. It's probably my code doing something odd then.tlr wrote: ↑Fri Jul 23, 2021 4:44 am The hardware of a 1540 is identical to an early 1541 but on the 1541 there are relaxed timings in the IEC bus code to allow for badline DMA interruptions on a c64. Running a 1540 or a 1541 with a vic-20 should work always although the 1541 would have slightly slower transfer speeds.
I think I better make a small test case with just memory write+read to avoid all other things that could potentially be causing problems.
Re: 1540 memory write
I'm convinced I need to put some more work into making a clean test program. It's too many moving parts right now to prove anything really.
Re: 1540 memory write
I made a shorter test program that only write 32 bytes to drive memory and read them back. It works perfectly on the 1540 so I must be doing something wrong in my code.
Re: 1540 memory write
I made another pass over this problem again now. I rewrote how I send commands to the drive to use listen/talk instead of open/close but with no success. The problem remained. I tested by swapping the 1541 ROM with a 1540 ROM in VICE to see if the ROM itself is the cause and it triggers the problem. I also had a friend reproduce the problem on real hardware with a 1541 using 1540 ROM.
Then I added a bit of wait after each written byte and the problem disappeared! Finally I only added a delay after the last byte sent to the drive before unlisten or clrchn is called. This workaround works.
I dug a bit to see what others are doing and Veni Vidi Vic! uses a mysterious delay loop after each byte sent claiming it's for the 1581 drive (which I have no problems with). This demo works flawlessly on 1540. The demo Robotic Liberation doesn't have wait loops when sending its data to the drive and this demo crashes exactly like my program with some bytes in the drive corrupted in the transfer!
Then I added a bit of wait after each written byte and the problem disappeared! Finally I only added a delay after the last byte sent to the drive before unlisten or clrchn is called. This workaround works.
I dug a bit to see what others are doing and Veni Vidi Vic! uses a mysterious delay loop after each byte sent claiming it's for the 1581 drive (which I have no problems with). This demo works flawlessly on 1540. The demo Robotic Liberation doesn't have wait loops when sending its data to the drive and this demo crashes exactly like my program with some bytes in the drive corrupted in the transfer!
Re: 1540 memory write
The corrupt byte is always the last in the transfer and affects even other commands, like M-E, which may execute some other address if the corruption occurs.
Re: 1540 memory write
Sounds weird... could you post some example code?
Re: 1540 memory write
Are you signalling EOI correctly? The timing before the first bit of the last byte is special, see
https://www.pagetable.com/?p=1135
https://www.pagetable.com/?p=1135
Re: 1540 memory write
Yes. It will be a bit of a wall of text though since the chunk upload takes a bit of space.
Code: Select all
// Send turboloader code to disk drive and execute it.
// <- C: set on error
subroutine send_code_to_drive
{
declare .source_addr
declare .bytes_left_low
declare .bytes_left_high
lda #<drive_loader::drive_code
sta .source_addr
lda #>drive_loader::drive_code
sta .source_addr + 1
lda #<DRIVE_CODE_ADDR
sta memory_write_addr
lda #>DRIVE_CODE_ADDR
sta memory_write_addr + 1
lda #<(drive_loader::drive_code_end - drive_loader::drive_code)
sta .bytes_left_low
lda #>(drive_loader::drive_code_end - drive_loader::drive_code)
sta .bytes_left_high
{
ldx #FILE
jsr kernal_chkout_with_check
bcs .error
// determine how large chunk we should send based on amount left and max chunk size
lda .bytes_left_high
bne .full
lda .bytes_left_low
cmp #DRIVE_MEM_CHUNK_SIZE
bcc .set_chunk_size
.full:
lda #DRIVE_MEM_CHUNK_SIZE
.set_chunk_size:
sta memory_write_chunk_length
// send m-w command
ldx #0
{
lda memory_write_command,x
jsr kernal_chrout_with_check
bcs .error
inx
cpx #memory_write_command_end - memory_write_command
bne @loop
}
// send chunk payload
ldx #0
{
lda .source_addr:$ffff,x
jsr kernal_chrout_with_check
bcs .error
inx
cpx memory_write_chunk_length
bne @loop
}
wait()
jsr CLRCHN
// add chunks size to source address
lda .source_addr
clc
adc memory_write_chunk_length
sta .source_addr
bcc .no_inc
inc .source_addr + 1
.no_inc:
lda memory_write_addr
clc
adc memory_write_chunk_length
sta memory_write_addr
bcc .no_inc_2
inc memory_write_addr + 1
.no_inc_2:
// subtract chunk size from bytes left
lda .bytes_left_low
sec
sbc memory_write_chunk_length
sta .bytes_left_low
bcs .no_dec
dec .bytes_left_high
.no_dec:
const .bytes_left_low = * + 1
lda #0
const .bytes_left_high = * + 1
ora #0
bne @loop
}
// memory filled with code, now execute
ldx #FILE
jsr kernal_chkout_with_check
bcc .no_error
.error:
jsr CLRCHN
sec
rts
.no_error:
ldx #0
{
lda memory_exec_command,x
jsr kernal_chrout_with_check
bcs .error
inx
cpx #memory_exec_command_end - memory_exec_command
bne @loop
}
wait()
jsr CLRCHN
clc
rts
}
if (USE_1540) {
subroutine wait
{
pha
txa
pha
ldx #50
{
dex
bne @loop
}
pla
tax
pla
rts
}
} else {
macro wait()
{
}
}
// Call kernal chkout and report errors
// -> X: file number
// <- C: set on error
kernal_chkout_with_check:
{
jsr CHKOUT
bcs .error
jmp status_check
// Call kernal chrout and report errors
// -> A: byte to write
// <- C: set on error
kernal_chrout_with_check:
jsr CHROUT
bcs .error
// |
// | falling through here
// v
// Read disk status.
// <- C: set on error
// <- Z: clear on end of file
// <> X: preserved
// <> Y: preserved
status_check:
jsr READST
pha
and #STATUS_SERIAL_TIMEOUT_WRITE | STATUS_SERIAL_TIMEOUT_READ | STATUS_SERIAL_NO_DEVICE
bne .pla_error
pla
and #STATUS_SERIAL_END_OR_IDENTIFY
clc
rts
.pla_error:
pla
.error:
sec
rts
}