6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 4:04 am

All times are UTC




Post new topic Reply to topic  [ 52 posts ]  Go to page Previous  1, 2, 3, 4  Next
Author Message
 Post subject: Re: ACIA sense check
PostPosted: Wed May 04, 2016 8:05 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
Quote:
I'd put SEI as part of reset vector code

You only need to do that if you're going to be jumping to it without the hardware RST\ input going low. Setting the interrupt-disable bit is an automatic part of the RST sequence. But yes, you do need to do CLI after the I/O IC is set up and you're ready to accept interrupts.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Wed May 04, 2016 8:18 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
I've been mostly working on the hardware and not on software and no interrupts which is why I didn't spot it. Sorry for wasting your time on a silly mistake :oops: .


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Wed May 04, 2016 8:24 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
No need to apologize. It's a common mistake. It's fun to make code as efficient as possible, and it also helps expose bugs, including ones that may not have otherwise shown up until after you've forgotten what you were doing which would make them harder to fix.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Wed May 04, 2016 9:25 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
Well, I got there in the end (with much help)

This is my ISR which receives a key and stores it in a buffer. I hope that it's not too illegible as I cannot currently put comments on the same lines as commands. This is something that I'm going to fix in my 6502 Code Assembler app when I have time.

Notes:

- The keyboard buffer is stored in RAM between $0900 and $09FF
- It operates by storing the incoming bytes from $09FF down to $0900
- $08FF stores the keyboard buffer index/counter.
- If the counter is $FF then the buffer is empty. If it's $0 then it's full.
- The latest byte stored is always at the value of the counter plus 1. So if the counter is at $FE (so 1 byte in the buffer) then that byte will be at $09FF ($09FE + 1)

Code:
# IRQ handler
PC = startcodeIRQ
PHA
# Did the ACIA cause the interrupt?
LDA ACIA_Status
BMI Source_Is_ACIA

# All interrupts service so exit
.ISR_done
PLA
RTI

.Source_Is_ACIA
# Did a received byte cause the interrupt?
AND #8
BEQ ISR_done
# we've detected a received byte so inject it into the keyboard buffer

# To do this: load the buffer counter
LDA buffer_counter
# ensure that it isn't full. The buffer operates in reverse from $09FF down to $0900 and the buffer counter is in $8FF.
BEQ buffer_full
#We'll now use the buffer counter as an index (in X)
TAX
# Grab the byte in the ACIA receive buffer
LDA ACIA_Transfer
# Store it in the keyboard buffer
STA buffer,X
# Decrement the buffer counter (remember- it starts at $FF (nothing) and decrements as characters are added
DEC buffer_counter
.buffer_full
BRA ISR_done


This is the main code which runs all the time. It repeatedly checks the keyboard buffer and sends anything in it out of the ACIA for display..
Code:
.sendstuff
# load the buffer counter and ensure that the buffer isn't empty
LDA buffer_counter
CMP #$FF
BEQ sendstuff
# convert the counter to an index (in X) and increase by 1
TAX
INX
# get the byte out of the buffer and send it to the ACIA for output
LDA buffer,X
# check for a carriage return. if so, we need to send aq line feed as well
CMP #13
BNE not_carriage_return
LDA #10
STA ACIA_Transfer
JSR delay40
LDA #13
.not_carriage_return
STA ACIA_Transfer
# increment the buffer counter value (which actually decrements the true value of the counter)
INC buffer_counter
BRA sendstuff


And here's the results :) :

Attachment:
ACIA_kbd_buffer_working.gif
ACIA_kbd_buffer_working.gif [ 20.27 KiB | Viewed 894 times ]


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Wed May 04, 2016 10:34 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8514
Location: Midwestern USA
banedon wrote:
- The keyboard buffer is stored in RAM between $0900 and $09FF
- It operates by storing the incoming bytes from $09FF down to $0900
- $08FF stores the keyboard buffer index/counter.
- If the counter is $FF then the buffer is empty. If it's $0 then it's full.

Ultimately a circular buffer (aka FIFO) will be more efficient, as you won't have to look at the specific index value to make decisions. With a FIFO, two indices are used: one to point to where the next datum (byte) is to be stored in the FIFO, and the other to point to where the next datum is to be gotten from the FIFO. For performance reasons, the two indices should be on zero page. At boot time, both indices would be initialized to $00—STZ is good for that sort of thing.

The logic would go something like this:

  • When a datum is to be written into the FIFO the write index is fetched, temporarily incremented and compared to the read index. If they are the same, the FIFO is full. Otherwise, the write index is decremented to what it was when fetched and used to tell the MPU where to store the datum. Following that, the write index is permanently incremented.

  • When a datum is to be gotten from the FIFO the read index is fetched and compared to the write index. If they are the same, the FIFO is empty. Otherwise, the read index is used to tell the MPU from where to get the next datum. After the datum has been gotten, the read index is incremented.

In the above, "incremented" implies that an index will eventually wrap to $00. Hence the "circular" moniker.

The read sequence could be coded as follows:

Code:
         ldx read_ix           ;FIFO read index
         cpx writ_ix           ;write index
         beq next              ;no data available
;
         lda fifo,x            ;read datum
         inc read_ix           ;bump read index
         clc                   ;datum was read
;
next     rts                   ;return to caller

In the above, a return with carry clear means a datum was fetched and returned in the accumulator. If carry is set, no data was available and the accumulator remains unchanged.

Writing to the FIFO involves a teensy bit more code, but is straightforward:

Code:
         ldx writ_ix           ;FIFO write index
         inx                   ;temporarily increment it
         cpx read_ix           ;read index
         beq next              ;FIFO is full
;
         dex                   ;realign write index &...
         sta fifo,x            ;write datum
         inc writ_ix           ;permanently bump index
         clc                   ;datum was written
;
next     rts                   ;return to caller

In the write function, which would be called with the datum to be written in the accumulator, a return with carry clear means the datum was written to the FIFO. If carry is set, the FIFO is full.

That's all there is to it!

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


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Fri May 06, 2016 12:00 am 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
Cheers, BDD. I'll give this a go.
BTW is there a bug with LDA (zp),Y in 65C02's? I'm having a lot of issues using this with the wrong address being ready.
For example
Code:
.
.
.
LDX msg MOD 256  ; load address of the message
LDY msg DIV 256  ; into the x and y registers
JSR sendtext     ; call the send text routine
.
.
.
.

.msg             ; the text to be printed
"Hello World"
EQUB $FF         ; terminating character (never sent)

.
.
.
.
.
.

.sendtext
STX $80          ; store X and Y in zero page, little endian style
STY $81
LDY #0           ; we're using Y as an index so zero it
.loop
LDA ($80),Y      ; load a byte from the message offset by Y
CMP #$FF         ; check to see if the byte is $FF
BEQ alldone      ; if it is then exit out by jumping to alldone
STA ACIA_xfer    ; send the byte to the transfer buffer of the ACIA
INY              ; increment the index (Y)
BRA loop         ; now loop back
.alldone
RTS              ; return from the sendtext routine


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Fri May 06, 2016 12:29 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
Quote:
BTW is there a bug with LDA (zp),Y in 65C02's?

There are no bugs in the 'c02. Assuming you're using MOD and DIV properly for your assembler, it looks like you need to make the LDX and LDY before the JSR sendtext to be immediate.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Fri May 06, 2016 4:59 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8514
Location: Midwestern USA
banedon wrote:
Cheers, BDD. I'll give this a go.
BTW is there a bug with LDA (zp),Y in 65C02's?

As Garth said, no. Reexamine how you are setting the zero page pointer. In most assemblers, you would do something like LDX #<addr to get the least significant byte of the desired address and LDY #>addr to get the most significant byte.

Incidentally, a null byte makes a better string terminator than $FF. With the latter, you have to check for that specific value. With $00, the act of loading it into the accumulator will tell you that it's the null byte. Your code will be a bit shorter and faster.

One more thing: there is a booby trap built into your printing subroutine. Hint: it has to do with the use of BRA to branch after sending the byte.

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


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Fri May 06, 2016 5:43 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
The branching is the common Forth structure BEGIN...WHILE...REPEAT which I adapted in my 6502 macros. REPEAT assembles the BRA instruction back to the top of the loop which is marked by BEGIN. (BEGIN is just a marker and does not lay down any code. WHILE_NOT_ZERO lays down the BEQ to the first instruction after REPEAT.) I wrote it here with the #< and #> which the C32 assembler I use also uses, and changed the string to have a null terminator, removed the now-unnecessary comparison to $FF, and added a line to watch for when the ACIA is ready to accept another byte (which there are several ways to do).

Code:
           LDX  #<msg          ; Load address of the message
           LDY  #>msg          ; into the x and y registers.
           JSR sendtext        ; Call the send text routine.
           .
           .
           .
msg:       BYTE  "Hello World", 0      ; null-terminated print string
           .
           .
           .
sendtext:  STX  $80            ; addr input lo byte
           STY  $81            ; addr input hi byte

           LDY  #0             ; Start with 1st data byte
           BEGIN
              LDA  ($80),Y
           WHILE_NOT_ZERO
              JSR  WAIT_BUSY   ; (must preserve A and Y)
              STA  ACIA_xfer
              INY
           REPEAT

           RTS
 ;-------------

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Fri May 06, 2016 12:07 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
Sorry guys: I should have copied/pasted. I did indeed put hashes ('#') in my original code.
I.e.
Code:
LDX #msg MOD 256  ; load address of the message
LDY #msg DIV 256  ; into the x and y registers
JSR sendtext     ; call the send text routine


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Fri May 06, 2016 6:26 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8514
Location: Midwestern USA
GARTHWILSON wrote:
The branching is the common Forth structure BEGIN...WHILE...REPEAT which I adapted in my 6502 macros. REPEAT assembles the BRA instruction back to the top of the loop which is marked by BEGIN. (BEGIN is just a marker and does not lay down any code. WHILE_NOT_ZERO lays down the BEQ to the first instruction after REPEAT.) I wrote it here with the #< and #> which the C32 assembler I use also uses, and changed the string to have a null terminator, removed the now-unnecessary comparison to $FF, and added a line to watch for when the ACIA is ready to accept another byte (which there are several ways to do).

Code:
           LDX  #<msg        ; Load address of the message
           LDY  #>msg        ; into the x and y registers.
           JSR sendtext      ; Call the send text routine.
           .
           .
           .
msg:       BYTE  "Hello World", 0    ; null-terminated print string
           .
           .
           .
sendtext:  STX  $80          ; addr input low byte
           STY  $81          ; addr input hi  byte

           LDY  #0           ; Start with 1st data byte
           BEGIN
              LDA  ($80),Y
           WHILE_NOT_ZERO
              JSR  WAIT_BUSY
              STA  ACIA_xfer
              INY
           REPEAT

           RTS
 ;-------------

The same booby trap exists in your code. :D

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


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Fri May 06, 2016 6:30 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8514
Location: Midwestern USA
banedon wrote:
Sorry guys: I should have copied/pasted. I did indeed put hashes ('#') in my original code.
I.e.
Code:
LDX #msg MOD 256  ; load address of the message
LDY #msg DIV 256  ; into the x and y registers
JSR sendtext     ; call the send text routine

Doesn't your assembler support the < and > convention for extracting the LSB and MSB from the address?

Incidentally, I see something in your code that could be an issue:

Code:
.sendtext
STX $80          ; store X and Y in zero page, little endian style
STY $81
LDY #0           ; we're using Y as an index so zero it
.loop
LDA ($80),Y      ; load a byte from the message offset by Y
CMP #$FF         ; check to see if the byte is $FF
BEQ alldone      ; if it is then exit out by jumping to alldone
STA ACIA_xfer    ; send the byte to the transfer buffer of the ACIA
INY              ; increment the index (Y)
BRA loop         ; now loop back

Shouldn't BRA loop be BRA .loop?

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


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Fri May 06, 2016 6:38 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
BigDumbDinosaur wrote:
Doesn't your assembler support the < and > convention for extracting the LSB and MSB from the address?

'fraid not. I wrote this assembler and it was originally based off of the one in the BBC Micro which didn't support that way of doing things.

BigDumbDinosaur wrote:
Incidentally, I see something in your code that could be an issue:

Code:
.sendtext
STX $80          ; store X and Y in zero page, little endian style
STY $81
LDY #0           ; we're using Y as an index so zero it
.loop
LDA ($80),Y      ; load a byte from the message offset by Y
CMP #$FF         ; check to see if the byte is $FF
BEQ alldone      ; if it is then exit out by jumping to alldone
STA ACIA_xfer    ; send the byte to the transfer buffer of the ACIA
INY              ; increment the index (Y)
BRA loop         ; now loop back

Shouldn't BRA loop be BRA .loop?


Again, just a peculiarity of my assembler. A label is defined with a '.' (so '.loop') and is referred to simply by its name (i.e. 'JSR loop')


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Fri May 06, 2016 6:47 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
On a hunch I've just removed all the ICs, very lightly sandpapered the legs and put them back.
So far the above code now seems to behave. I'll continue testing.

[edit] Nope still acting up so still working on it. Now checking out zero page, the stack and the ISR.

[edit] Disabled ISR - $AA successfully written to ZP and read back. So not the RAM and not the ISR. Onwards!

[edit] I think that I've found the problem and it looks like it's a bug in my assembler.

My test code has two temporary test routines which both write to an area of RAM and read it back to ensure that the RAM is working ok at that address.
The only difference is that the first one writes/reads the value $AA (10101010) and the second $55 (01010101).
Both use labels with similar names and here is where the problem lies: The assembler seems to think that variables/labels with the same base name are the same.
An example:
JIM = $8000
JIM2 = $1FFF
JIM3 = $40AA
The assembler will create all three variables/labels and assign the correct values, but when it encounters a reference to JIM-whatever it may well decide it is simply JIM rather than JIM2 or JIM3 - even if JIM2 or JIM3 has been specified.
Here's a snap shot (see below). The red line/arrows show how the program flow should occur. The blue arrow shows what actually happens.
So you can see :
BRA at $F02F jumps to 'm' at $F039
BRA at $F04F *should* jump to 'm2' at $F059, but instead jumps back to $F039.
And yes, my test sprint code uses similar named label and variables elsewhere in my code.

Time to do some surgery on my assembler methinks!

Attachment:
foundtheissue.gif
foundtheissue.gif [ 94.08 KiB | Viewed 835 times ]


Top
 Profile  
Reply with quote  
 Post subject: Re: ACIA sense check
PostPosted: Fri May 06, 2016 9:54 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
OK. I've rewritten the variable detection and processing routine in my assembler and now things seem a little better:

Attachment:
foundtheissue_resolved.gif
foundtheissue_resolved.gif [ 92.99 KiB | Viewed 830 times ]


I'm off to bed so will re-assemble and test my sprint code tomorrow.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 52 posts ]  Go to page Previous  1, 2, 3, 4  Next

All times are UTC


Who is online

Users browsing this forum: Google [Bot] and 40 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: