1540 memory write

Basic and Machine Language

Moderator: Moderators

User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

1540 memory write

Post by bjonte »

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.
Vic20-Ian
Vic 20 Scientist
Posts: 1214
Joined: Sun Aug 24, 2008 1:58 pm

Re: 1540 memory write

Post by Vic20-Ian »

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
tlr
Vic 20 Nerd
Posts: 567
Joined: Mon Oct 04, 2004 10:53 am

Re: 1540 memory write

Post by tlr »

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.
Just to clarify: it works in xvic with 1541 emulation, but not with 1540 emulation?

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.
User avatar
srowe
Vic 20 Scientist
Posts: 1341
Joined: Mon Jun 16, 2014 3:19 pm

Re: 1540 memory write

Post by srowe »

What happens with an emulated 1541 when you set it to use VIC-20 timing using UI-?
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: 1540 memory write

Post by bjonte »

Vic20-Ian wrote: Thu Jul 22, 2021 4:08 pm Try true drive emulation, it might fix the timing issue.
I ran with true drive emulation.
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: 1540 memory write

Post by bjonte »

tlr wrote: Fri Jul 23, 2021 4:44 am Just to clarify: it works in xvic with 1541 emulation, but not with 1540 emulation?
Yes.
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.
Hmm, OK. Thanks for the explanation of the slower mode. It's probably my code doing something odd then.

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.
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: 1540 memory write

Post by bjonte »

srowe wrote: Fri Jul 23, 2021 6:07 am What happens with an emulated 1541 when you set it to use VIC-20 timing using UI-?
Interesting question! I should try that.
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: 1540 memory write

Post by bjonte »

bjonte wrote: Sat Jul 24, 2021 11:17 am
srowe wrote: Fri Jul 23, 2021 6:07 am What happens with an emulated 1541 when you set it to use VIC-20 timing using UI-?
Interesting question! I should try that.
It works on a 1541 after sending the UI- command to the drive as well.
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: 1540 memory write

Post by bjonte »

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.
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: 1540 memory write

Post by bjonte »

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.
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: 1540 memory write

Post by bjonte »

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!
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: 1540 memory write

Post by bjonte »

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.
tlr
Vic 20 Nerd
Posts: 567
Joined: Mon Oct 04, 2004 10:53 am

Re: 1540 memory write

Post by tlr »

Sounds weird... could you post some example code?
User avatar
srowe
Vic 20 Scientist
Posts: 1341
Joined: Mon Jun 16, 2014 3:19 pm

Re: 1540 memory write

Post by srowe »

Are you signalling EOI correctly? The timing before the first bit of the last byte is special, see

https://www.pagetable.com/?p=1135
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: 1540 memory write

Post by bjonte »

tlr wrote: Tue Dec 14, 2021 12:41 pm Sounds weird... could you post some example code?
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
}
Removing 'wait()' (which translates to jsr wait) will trigger the bug (sometimes). As I wrote earlier, I also rewrote this to use listen/second/ciout/unlisten, but with the same issue. I haven't tried adding wait to that version.
Post Reply