Dan's 6502 build, aka, The WOPR Jr.
Re: Dan's 6502 build, aka, The WOPR Jr.
Chip is 65C02. No NMOS here.
I'm not sure what interrupt question you want answered. If I'm understanding though, even if I RTS to a garbage location, my ISR should still work. Yet it never goes back high.
I'm not knowingly calling any WAI or BRKs. Don't know what a JAM instruction is.
I don't understand how my calling routine could be effected by my saving the regs on the stack. The subroutine is not reliant on previous register values, and why would that matter anyway? Doesn't push leave the register unchanged?
I'm not sure what interrupt question you want answered. If I'm understanding though, even if I RTS to a garbage location, my ISR should still work. Yet it never goes back high.
I'm not knowingly calling any WAI or BRKs. Don't know what a JAM instruction is.
I don't understand how my calling routine could be effected by my saving the regs on the stack. The subroutine is not reliant on previous register values, and why would that matter anyway? Doesn't push leave the register unchanged?
Re: Dan's 6502 build, aka, The WOPR Jr.
Dan Moos wrote:
Chip is 65C02. No NMOS here.
Quote:
If I'm understanding though, even if I RTS to a garbage location, my ISR should still work. Yet it never goes back high.
Quote:
I'm not sure what interrupt question you want answered.
- "There is a terminal read routine that takes data from the ACIA, and puts it in the COM1_RXBUF string. Every time there is a keypress, that routine checks to see if it was the "enter" key. If it was, it puts a null at the end of the COM1_RXBUF string, and calls the naughty subroutine that's having the problem. That routine's job is to take the string that looks like, for random example, "read 8000 80FF" and turn it into "read<null>8000<null>80FF <null>" It also stores indices in the ARG_INDEX array so that the parser can extract them. The parser would be the next thing called if nothing crashes."
So, does that include the part which involves interrupts? It almost sounds as if the whole thing (except the parser) might be included in the ISR, but you don't say. The summary is helpful, but it seems to omit some key details.
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
https://laughtonelectronics.com/Arcana/ ... mmary.html
Re: Dan's 6502 build, aka, The WOPR Jr.
I see the confusion. This is not my ISR. Not is it running during my ISR. My ISR just sets a flag that tells my main loop a key has been pressed. Thus, I do indeed mean RTS, not RTI.
Re: Dan's 6502 build, aka, The WOPR Jr.
Quote:
even if I RTS to a garbage location, my ISR should still work. [...] I do indeed mean RTS, not RTI.
A JAM instruction is an undefined opcode which, on an NMOS chip, causes it to cease fetching instructions. It's considered a bug. Only a reset will get you out of the lockup. Modern WDC chips have an instruction whose effect is similar or identical, but they gave it a new opcode and an official name: STP ( SToP ). The only trigger to exit the lockup is if you do a reset (give the CPU's RESB input a low pulse). Another new opcode is WAI (WAIt), which is similar but -- more conveniently -- it accepts the exit trigger on the CPU's IRQB input instead. This works even after an SEI, so you can forgo the actual interrupt if you want to. The datasheet has the details.
OK, so: the ISR sets a flag that tells the main loop a key has been pressed. Is it also the ISR's job to read the the peripheral's status register/whatever (and thus allow the IRQ line to return high)? Y' might wanna show us the ISR too, please -- also any other code that may be pertinent.
Last edited by Dr Jefyll on Sun Feb 11, 2018 5:36 pm, edited 1 time in total.
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
https://laughtonelectronics.com/Arcana/ ... mmary.html
Re: Dan's 6502 build, aka, The WOPR Jr.
Here I post more code. I tried to fix the horrible formatting a simple cut and paste winds up with. Hopefully I didn't create typos in that process.
EDIT: my formatting turned out no better. sorry
Here is the ISR. As you can see, it does as little as possible. I don't think it is related to the problem, as it will long have finished, and multiple JSR's called by the time the problem happens.
Also, here is the snippet in my main loop that deals with the flag the ISR sets.
Finally, here is the terminal_r subroutine. This routine eventually calls process_cmdln, which is the troublesome routine. I edited my comments to reflect our conversation in a few spots, so look for that.
EDIT: my formatting turned out no better. sorry
Here is the ISR. As you can see, it does as little as possible. I don't think it is related to the problem, as it will long have finished, and multiple JSR's called by the time the problem happens.
Code: Select all
;***************************
;Interrupt service routine *
;***************************
isr: PHA
LDA COM1_STA ;get ACIA status register
BPL end_isr ;if no IRQ, return from ISR
LDA #$FF
STA READ_FLAG ;main loop pols this to see if a key has been presses
end_isr: PLA
RTICode: Select all
inf_loop: LDA READ_FLAG ;see if key was pressed. ISR sets this flag
BNE read_irq ;not 0? Flag was set
JMP inf_loop ;no flag. Loop as usual
read_irq: STZ READ_FLAG ;flag was set. Clear it
JSR terminal_r ;process the keypress
JMP inf_loop ;loop as usualCode: Select all
;**************************
;Terminal read subroutine *
;**************************
terminal_r:
PHA
PHX
PHY
LDX STRING_INDEX ;get string index. This is index is the current position in the input buffer
LDY COM1_DAT ;get data from ACIA Rx
CPY #$0D ;check if enter was pressed
BEQ process_cmd ;if enter pressed, process the input string
JSR com1_TX_chk ;wait til TX buffer clears
TYA ;I can't remember why I initially use Y, and then transfer it. Clue maybe?
STA COM1_DAT
STA COM1_RXBUF,X ;place recieved data into input buffer
INX ;increment it
STX STRING_INDEX ;put incremented version back in memory
PLY
PLX
PLA
RTS
process_cmd:
STZ COM1_RXBUF,X ;put NULL on end of string
JSR process_cmdln ;index arguments, if any. This is the subroutine that crashes
STZ STRING_INDEX ;reset index. When it crashes, this line is never reached
JSR parse_cmd ;parse the command
JMP (SELECTED_CMD) ;run routine for selected command
rtn_to_tr: LDA #<prompt ;get lower byte of prompt message
STA STRING_PTR ;store it in first byte of the string pointer
LDA #>prompt ;get upper byte of prompt message
STA STRING_PTR+1 ;store it in second byte of string pointer
JSR terminal_w ;display prompt
PLY
PLX
PLA
RTSRe: Dan's 6502 build, aka, The WOPR Jr.
I fixed another error in my post. I had incorrectly commented that the stack calls in terminal_r cause the problem. That is incorrect. Those calls work. It is the calls in process_cmdln, the routine I posted earlier. Sorry. I edited that comment out just now
- barrym95838
- Posts: 2056
- Joined: 30 Jun 2013
- Location: Sacramento, CA, USA
Re: Dan's 6502 build, aka, The WOPR Jr.
Code: Select all
...
JMP (SELECTED_CMD) ;run routine for selected command
...
Mike B.
Re: Dan's 6502 build, aka, The WOPR Jr.
They do indeed jump back. I do it this way because I don't know what routine I'm going to run until the last minute. There is a jump, not a RTS at returning end. There are no JSRs unmatched with RTSs. Each
Jumped o to routine returns to this spot via a another jump
Never the less, this all works.
Jumped o to routine returns to this spot via a another jump
Never the less, this all works.
Re: Dan's 6502 build, aka, The WOPR Jr.
Quote:
They do indeed jump back.
Quote:
I do it this way because I don't know what routine I'm going to run until the last minute.
Code: Select all
JSR process_cmdln ;index arguments, if any. This is the subroutine that crashes
STZ STRING_INDEX ;reset index. When it crashes, this line is never reachedThis is quite a head-scratcher! Just in case, can you also show us the labels that define all the pertinent memory addresses please.
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
https://laughtonelectronics.com/Arcana/ ... mmary.html
Re: Dan's 6502 build, aka, The WOPR Jr.
Yes, it is the key press immediately following the crash that sticks the IRQ line low.
Here is my complete label space.
Here is my complete label space.
Code: Select all
;*************
;UART Labels *
;*************
;COM1. Main UART
COM1_DAT = $5000
COM1_STA = COM1_DAT+1
COM1_CON = COM1_DAT+3
COM1_COM = COM1_DAT+2
;************************
;Display port VIA Labels*
;************************
VIA_1PORTB = $6000
VIA_1PORTA = VIA_1PORTB+1
VIA_1DDRB = VIA_1PORTB+2
VIA_1DDRA = VIA_1PORTB+3
;******************
;0 page variables *
;******************
STRING_PTR .DS $02 ;pointer to current output message string
STRING_INDEX .DS $01 ;index into input buffer
LINE_CNT .DS $01 ;clear screen line count
ARG_INDEX .DS $03 ;indices into command line string to arguments
ARG_CNT .DS $01 ;number of command line arguments
CMD_INDEX .DS $02 ;index into command string list
SELECTED_CMD .DS $02 ;pointer to selected command routine
CMDLN_ERROR .DS $01 ;command line error condition
ARG_TEMP .DS $04 ;holds the 4 bit decoded character values of input arguments
ARG_VALUE .DS $02 ;the final 16 bit numeric value of the arguments
ADR_START .DS $02 ;holds lower limit of commandline memory ops.
ADR_END .DS $02 ;holds upper limit of commandline memory ops.
HEX_INPUT .DS $02
HEX_HIGH .DS $01 ;holds ascii representation of high nibble of displayed hex byte
HEX_LOW .DS $01 ;holds ascii representation of low nibble of displayed hex byte
HEX_DSPLY .DS $28 ;holds strings of hex/ascii data to be displayed
SCRN_BF_TOP .DS $02 ;top of ring buffer that contains screen contents. Physical top of screen.
SCRN_BF_CUR .DS $02 ;pointer to current cursor position in display buffer
ROW .DS $01 ;current cursor row position
COLUMN .DS $01 ;current cursor column position
CHARACTER .DS $01 ;current character to be displayed
BUG_LITE .DS $01 ;debug status light on VIA_1 PA0
READ_FLAG .DS $01
;***************************
;memory starting at page 2 *
;***************************
.ORG $0200
SCRN_BUF .DS $C80 ;Screen buffer. 3,200 bytes for an 80*40 character display.
;Placed at start of page for ease of inderect indexing
SCRN_BUF_ENDL = $80 ;C80 is 3,200 for a 3,200 byte 80*40 character screen buffer
SCRN_BUF_ENDH = $0E
COM1_RXBUF .DS $100 ;UART input buffer
;**********************
;ROM data starts here *
;**********************
.ORG $8000
;*****************
;command strings *
;*****************
commands:
cmd_empty: .BYTE $00 ;empty:user pressed enter with no characters
cmd_write: .BYTE "write", $00 ;command to write to memory
cmd_read: .BYTE "read", $00 ;command to read from memory
cmd_test: .BYTE "test", $00 ;command for system self-test
cmd_clr: .BYTE "clr", $00 ;command to clear screen
cmd_list_end: .BYTE $FF ;marker for end of list
;******************************
; pointers to command strings *
;******************************
cmd_indices:
empty_index: .WORD cmd_empty
write_index: .WORD cmd_write
read_index: .WORD cmd_read
test_index: .WORD cmd_test
clr_index .WORD cmd_clr
;******************************
;pointers to command routines *
;******************************
cmd_routines:
empty_rtn_ptr: .WORD empty_rtn
write_rtn_ptr: .WORD write_rtn
read_rtn_ptr: .WORD read_rtn
test_rtn_ptr: .WORD test_rtn
clr_rtn_ptr .WORD clr_rtn
no_cmd_rtn_ptr: .WORD no_cmd_rtn
;************
;UI strings *
;************
strings:
prompt: .BYTE $0D, $0A, $0A, "WOPRjr:" ,$00 ;commandline prompt
empty_msg .BYTE $0D, $0A, $00 ;empty string
message: .BYTE $0D, $0A, "You entered: ", $00 ;input response message
write_msg: .BYTE $0D, $0A, "writing", $00 ;temp write message
read_msg: .BYTE $0D, $0A, $0A, "No arguments entered." ;line 1 of default read message
read_msg2: .BYTE $0D, $0A,"Enter a single HEX address, or 2 addresses as a range", $00 ;line 2
test_msg: .BYTE $0D, $0A, "testing", $00
clr_msg: .BYTE $0D, $0A, "clearing", $00 ;temp clear screen message
nl_cr: .BYTE $0D, $0A, $00 ;newline, carriage return
no_cmd_msg: .BYTE $0D, $0A, $0A, "Unknown command", $00 ;default message for unknown string
bad_args_msg: .BYTE $0D, $0A, $0A, "Bad, or too many arguments", $00 ;wrong or too many arguments
Re: Dan's 6502 build, aka, The WOPR Jr.
BTW. , About my indirect jumps: Is the reason to push the return address and JMP() so that I can have an RTS in the routine, making it a little more universal, rather than only being able to return to a hardcoded location? Makes sense if so, although right now I can't imagine needing that flexibility in these particular routines. Maybe a good practice for my future indirect subroutine jumps?
Re: Dan's 6502 build, aka, The WOPR Jr.
Dan Moos wrote:
BTW. , About my indirect jumps: Is the reason to push the return address and JMP() so that I can have an RTS in the routine, making it a little more universal, rather than only being able to return to a hardcoded location? Makes sense if so, although right now I can't imagine needing that flexibility in these particular routines. Maybe a good practice for my future indirect subroutine jumps?
Last edited by Dr Jefyll on Sun Feb 11, 2018 9:04 pm, edited 1 time in total.
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
https://laughtonelectronics.com/Arcana/ ... mmary.html
Re: Dan's 6502 build, aka, The WOPR Jr.
BTW. I love these kind of bugs. Forces me to gain a much deeper understanding of how the system works.
When reading my code, I offer this disclaimer: this is the first and only thing I've ever written in 6502 assembly, and its been pecked away slowly over many months. You might notice that my skills were at different places in different sections! Also, I'm sure there is old code that never gets used form earlier iterations that I haven't cleaned up yet. A thorough re-write is in the near future. Other than this issue, it all works perfectly though.
When reading my code, I offer this disclaimer: this is the first and only thing I've ever written in 6502 assembly, and its been pecked away slowly over many months. You might notice that my skills were at different places in different sections! Also, I'm sure there is old code that never gets used form earlier iterations that I haven't cleaned up yet. A thorough re-write is in the near future. Other than this issue, it all works perfectly though.
- barrym95838
- Posts: 2056
- Joined: 30 Jun 2013
- Location: Sacramento, CA, USA
Re: Dan's 6502 build, aka, The WOPR Jr.
The "springboard" method is easier than manually pushing any hard-coded addresses. All you need to do is find a little out-of-the-way spot to stick
then
and let the assembler figure the addresses and the 65c02 do the pushing for you.
Mike B.
Code: Select all
springboard:
JMP (SELECTED_CMD)Code: Select all
GET some_stuff_done
JSR springboard
GET more_stuff_doneMike B.
Re: Dan's 6502 build, aka, The WOPR Jr.
Damn, that's clever