SMOLNET PORTAL home about changes
                                        
                                   * * * * *
                                        
         The difficulties in supporting “write-only memory” in assembly
                                        
When I last wrote about this [1], I had one outstanding problem with static
analysis of read-only/write-only memory, and that was with hardware that
could be input or output only. It was only after I wrote that that I realized
the solution—it's the same as a hardware register having different semantics
on read vs. write—just define two labels with the semantics I want. So for
the MC6821 [2], I could have:

-----[ Assembly ]-----
		org	$FF00
PIA0.A		rmb/r	1	; read only
		org	$FF00
PIA0.Adir	rmb/w	1	; write only, to set the direction of each IO pin
PIA0.Acontrol	rmb	1	; control for port A
-----[ END OF LINE ]-----

So that was a non-issue. It was then I started looking over some existing
code I had to see how it might look. I didn't want to just jump into an
implementation without some forethought, and I quickly found some issues with
the idea by looking at my maze generation program [3]. The code in question
initializes the required video mode (in this case 64×64 with four colors).
Step one involves writing a particular value to the MC6821:

-----[ Assembly ]-----
		lda	#G1C.PIA ; 64x64x4
		sta	PIA1.B
-----[ END OF LINE ]-----

So far so good. I can mark PIA1.B as write-only (technically, it also has
some input pins so I really can't, but in theory I could).

Now, the next bit requires some explaining. There's another 3-bit value that
needs to be configured on the MC6883 [4], but it's not as simple as writing
the 3-bit value to a hardware register—each bit requires writing to a
different address, and worse—it's a different address if the bit is 0 or 1.
So that's six different addresses required. It's not horrible though—the
addresses are sequential:

Table: 6883 VDG (Video Display Generator) Addressing Mode
bit	0/1	address
------------------------------
V0	0	$FFC0
V0	1	$FFC1
V1	0	$FFC2
V1	1	$FFC3
V2	0	$FFC4
V2	1	$FFC5

Yeah, to a software programmer, hardware can be weird. To set bit 0 to 0, you
do a write (and it does not matter what the value is) to address $FFC0. If
bit 0 is 1, then it's a write to $FFC1. So with that in mind, I have:

-----[ Assembly ]-----
		sta	SAM.V0 + (G1C.V & 1<<0 <> 0)
		sta	SAM.V1 + (G1C.V & 1<<1 <> 0)
		sta	SAM.V2 + (G1C.V & 1<<2 <> 0)
-----[ END OF LINE ]-----

OOh. Yeah.

I wrote it this way so I wouldn't have to look up the appropriate value and
write the more opaque (to me):

-----[ Assembly ]-----
		sta	$FFC1
		sta	SFFC2
		sta	$FFC4
-----[ END OF LINE ]-----

The expression (G1C.V & 1<<n <> 0) checks bit n to see if it's set or not,
and returns 0 (for not set) or 1 (for set). This is then added to the base
address for bit n, and it all works out fine. I can change the code for, say,
the 128×192 four color mode by using a different constant:

-----[ Assembly ]-----
		lda	#G6C.PIA
		sta	PIA1.B
		sta	SAM.V0 + (G6C.V & 1<<0 <> 0)
		sta	SAM.V1 + (G6C.V & 1<<1 <> 0)
		sta	SAM.V2 + (G6C.V & 1<<2 <> 0)
-----[ END OF LINE ]-----

But I digress.

This is a bit harder to support. The address being written is part of an
expression, and only the label (defining the address) would have the
read/write attribute associated with it. At least, that was my intent. I
suppose I could track the read/write attribute by address, which would solve
this particular segment of code.

And the final bit of code to set the address of the video screen (or frame
buffer):

-----[ Assembly ]-----
		ldx	#SAM.F6		; point to frame buffer address bits
		lda	ECB.grpram	; get MSB of frame buffer
mapframebuf	clrb
		lsla
		rolb
		sta	b,x		; next bit of address
		leax	-2,x
		cmpx	#SAM.F0
		bhs	mapframebuf
-----[ END OF LINE ]-----

Like the VDG Address Mode bits, the bits for the VDG Address Offset have
unique addresses, and because the VDG Address Offset has seven bits, the
address is aligned to a 512 byte boundary. Here, the code loads the X
register with the address of the upper end of the VDG Address Offset, and the
seven top most bits of the video address is sent, one at a time, to the B
register, which is used as an offset to the X register to set the appropriate
address for the appropriate bit. So now I would have to track the read/write
attributes via the index registers as well.

That is not so easy.

I mean, here, it could work, as the code is all in one place, but what if
instead it was:

-----[ Assembly ]-----
		ldx	#SAM.F6
		lda	ECB.grpram
		jsr	mapframebuf
-----[ END OF LINE ]-----

Or an even worse example:

-----[ Assembly ]-----
costmessage	fcc/r	"A constant message" ; read only text
buffer		rmb	18

		ldx	#constmessage
		ldy	#buffer
		lda	#18
		jsr	memcpy
-----[ END OF LINE ]-----

The subroutine memcpy might not even be in the same source unit, so how would
the read/write attribute even be checked? This is for static analysis, not
runtime.

I have one variation on the maze generation program that generates multiple
mazes at the same time, on the same screen (it's fun to watch) and as such, I
have the data required for each “maze generator” stored in a structure:

-----[ Assembly ]-----
explorec	equ	0	; read-only
backtrackc	equ	1	; read-only
xmin		equ	2	; read-only
ymin		equ	3	; read-only
xstart		equ	4	; read-only
ystart		equ	5	; read-only
xmax		equ	6	; read-only
ymax		equ	7	; read-only
xpos		equ	8	; read-write
ypos		equ	9	; read-write
color		equ	10	; read-write
func		equ	11	; read-write
-----[ END OF LINE ]-----

This is from the source code, but I've commented each “field” as being “read-
only” or “read-write.” That's another aspect of this that I didn't consider:

-----[ Assembly ]-----
		lda	explorec,x	; this is okay
		sta	explorec,x	; this is NOT okay
-----[ END OF LINE ]-----

Not only would I have to track read/write attributes for addresses, but for
field accesses to a structure as well. I'm not saying this is impossible,
it's just going to take way more thought than I thought. I don't think I'll
have this feature done any time soon … 

[1] gopher://gopher.conman.org/0Phlog:2024/01/31.3
[2] https://en.wikipedia.org/wiki/Peripheral_Interface_Adapter
[3] gopher://gopher.conman.org/0Phlog:2023/11/27.1
[4] https://archive.org/details/Motorola_MC6883_Synchronous_Address_Multiplexer_Advance_Sheet_19xx_Motorola

Email author at sean@conman.org

.
Response: text/plain
Original URLgopher://gopher.conman.org/0Phlog%3A2024/02/05.1
Content-Typetext/plain; charset=utf-8