6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 9:10 am

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Sat Apr 23, 2022 2:57 pm 
Offline

Joined: Sat Feb 19, 2022 2:18 am
Posts: 47
I'm relatively new to 65816 assembly, and I'm wondering if I'm missing a simpler way to write to 8-bit registers on devices such as VIAs and PSGs. I have some code where the logic really benefits from the 16-bit accumulator. However, I need to write to a VIA and some PSGs which have 8-bit registers. I am switching my accumulator to 8-bit anytime that I write to these registers. Is this the proper approach, or is this some shortcut to STA, while using a 16-bit accumulator, that allows me to write a single byte and not two bytes? If writing two bytes, it updates the desired register plus the register at the next address. Thanks!


Top
 Profile  
Reply with quote  
PostPosted: Sat Apr 23, 2022 4:40 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
Quote:
I have some code where the logic really benefits from the 16-bit accumulator.
Okay, what about X and Y -- is it reasonable to keep those in 8-bit mode? They'd be fine for simple reads and writes to the 8-bit peripheral (but of course with X and Y you can't easily do AND OR EOR etc).

The other solution involves hardware. Just redefine the IO address decoding such that every other address is unused. For example, a 6522 VIA would occupy 32 (not 16) bytes of address space. Within the 32-byte space, all the even addresses would select the VIA, and all the odd addresses would select nothing.

This allows the CPU to do a 16-bit access while only touching the VIA once. On writes, the extra 8 bits get written to nowhere. But remember -- on reads, the extra 8 bits will contain undefined data, so your code will need to be on guard for that.

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Sat Apr 23, 2022 5:01 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
That's a nice solution. And this is probably a bit crazy, but if you were feeling particularly adventurous you could wire up a second 6522 to cover the odd addresses. Between the two of them you'd then have 16-bit wide I/O ports. The timers and shift register wouldn't really extend so naturally though.


Top
 Profile  
Reply with quote  
PostPosted: Sat Apr 23, 2022 5:14 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8508
Location: Midwestern USA
rehsd wrote:
I'm relatively new to 65816 assembly, and I'm wondering if I'm missing a simpler way to write to 8-bit registers on devices such as VIAs and PSGs.

In the I/O primitives of my POC units, I have arranged the code so as much as the precursory 16-bit processing as possible is done before the actual device access. If you find yourself constantly using REP and SEP you should carefully study the program flow to determine how to reduce register size switching. You may find you are unnecessarily using REP and SEP when a slight code change would allow you to keep the register sizes constant for a greater number of instructions.

Something else to consider is this: just because you can do something with 16-bit registers doesn’t mean you should. While 16-bit processing will generally speed up a program and reduce its size to some extent, you have to look at the overall picture. In some cases, keeping register sizes at eight bits may be more efficient, precisely because you aren’t constantly using REP and SEP. Also, a 16-bit load/store incurs a one cycle penalty, which can negatively affect performance in a loop.

Something that I have evolved in my 65C816 code is the concept of using data structures whose sizes are in multiples of words, i.e., 16- and 32-bit pointers, counters, etc. For example, suppose I have a flag that is tested with the BIT instruction and whose possible states are $00, $80 and $C0. If I make that flag a 16-bit location, my possible states are $0000, $8080 and $C0C0. That being the case, I can test the flag with the accumulator set to either size and see identical results. Now it becomes a matter of convenience as to what the accumulator’s size should be when BITing the flag, not a matter of necessity.

The technique of using 16-bits for intermediate storage, even in cases in which an eight-bit value would suffice, works well in functions that use the stack as fugacious workspace. PEA, PEI and PER write 16 bits at a time. So it becomes more efficient to “waste” some stack space so PEA, PEI and PER can be used where they offer the most efficiency.

In the same vein, while indirect-long addressing uses a 24-bit pointer, the reality is such a size is awkward—the 816 doesn't have the ability to atomically load, process or store a 24-bit quantity in a single instruction. Ergo I use 32-bit pointers, which allow me to do pointer arithmetic in word-size chunks, which is convenient with the accumulator is set to 16 bits. Fewer REPs and SEPs are required when manipulating complex data structures, and the code becomes more compact and faster-acting.

Dr Jefyll wrote:
Okay, what about X and Y -- is it reasonable to keep those in 8-bit mode? They'd be fine for simple reads and writes to the 8-bit peripheral (but of course with X and Y you can't easily do AND OR EOR etc).

That’s something I do with regularity in device drivers.

Quote:
The other solution involves hardware. Just redefine the IO address decoding such that every other address is unused. For example, a 6522 VIA would occupy 32 (not 16) bytes of address space. Within the 32-byte space, all the even addresses would select the VIA, and all the odd addresses would select nothing.

If A0 is not used to select device registers, then even-only addressing would see the same register at two adjacent locations, $xx00 and $xx01. That does open the door to a double access of a read-sensitive register, such as the MR register in the 26xxx/28xxx NXP UARTs, which register appears at relative address $00 in the address space occupied by the UART.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Sat Apr 23, 2022 5:19 pm 
Offline

Joined: Sat Feb 19, 2022 2:18 am
Posts: 47
Dr Jefyll wrote:
Quote:
I have some code where the logic really benefits from the 16-bit accumulator.
Okay, what about X and Y -- is it reasonable to keep those in 8-bit mode?

Sorry, I should have included more info about X, Y. I would like to use 16-bit X and Y registers, as I'm indexing values above 255.

The addressing change is clever, and I think it would work well. I'll have to think about whether I can manage that with my current PCB design, or if I'll have to wait for a future version of my PCB before I can leverage it.

Thank you!


Top
 Profile  
Reply with quote  
PostPosted: Sat Apr 23, 2022 5:23 pm 
Offline

Joined: Sat Feb 19, 2022 2:18 am
Posts: 47
BigDumbDinosaur wrote:
...you should carefully study the program flow to determine how to reduce register size switching.

Something else to consider is this: just because you can do something with 16-bit registers doesn’t mean you should.

Very good points -- and something to which I am paying close attention. Thank you for the tips!


Top
 Profile  
Reply with quote  
PostPosted: Sat Apr 23, 2022 6:38 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
BigDumbDinosaur wrote:
Quote:
The other solution involves hardware. Just redefine the IO address decoding such that every other address is unused. For example, a 6522 VIA would occupy 32 (not 16) bytes of address space. Within the 32-byte space, all the even addresses would select the VIA, and all the odd addresses would select nothing.

If A0 is not used to select device registers, then even-only addressing would see the same register at two adjacent locations, $xx00 and $xx01. That does open the door to a double access of a read-sensitive register, such as the MR register in the 26xxx/28xxx NXP UARTs, which register appears at relative address $00 in the address space occupied by the UART.
Although CPU A0 wouldn't connect to the peripheral's A0, it would connect to the chip-enable logic. As I said, all the odd addresses are unused, and would select nothing. This allows the CPU to do a 16-bit access while only touching the VIA once. The register would not appear at two adjacent locations, and there's no threat of a double access.

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 28, 2022 12:10 pm 
Offline
User avatar

Joined: Sat Jul 24, 2021 1:37 pm
Posts: 282
gfoot wrote:
That's a nice solution. And this is probably a bit crazy, but if you were feeling particularly adventurous you could wire up a second 6522 to cover the odd addresses. Between the two of them you'd then have 16-bit wide I/O ports. The timers and shift register wouldn't really extend so naturally though.


It works with a single 6522 as well, PORTA is the high byte, PORTB is the low byte. This works for ORA/ORB and DDRA/DDRB. Timers also kind of work as expected (T1C, T1L, T2C) although there are some gotchas.

_________________
BB816 Computer YouTube series


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 18 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: