6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Tue Jun 04, 2024 4:28 am

All times are UTC




Post new topic Reply to topic  [ 321 posts ]  Go to page Previous  1 ... 17, 18, 19, 20, 21, 22  Next
Author Message
PostPosted: Tue Jan 30, 2018 6:34 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
Dan Moos wrote:
Any thoughts? My first choice would be any method that lets me create my own font so I can give it a little flare!

Lots of bitmap fonts on line, especially since the old Mac, Windows, and X-Windows systems used bitmap fonts.

For smaller fonts, bitmaps are easier to design anyway.

They tend to be represented as "one, long bitmap" rather than a lot of little bitmaps.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 30, 2018 6:42 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10821
Location: England
Maybe DamienG's site can help:
https://damieng.com/blog/2011/02/20/typ ... stem-fonts


Top
 Profile  
Reply with quote  
PostPosted: Sat Feb 03, 2018 7:45 pm 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
I have what I believe to a simple way to expose my video memory to my system.

I just want to run it by you folks for obvious flaws.

I am already committed to using dual ported SRAM for video memory, cost be damned. Its just too obvious a solution for me to ignore. 64k cost me close to $30 if I remember, which is a lot by chip cost standards, but compared to my completely frivolous and pointless desire to buy a $1700 spectrum analyzer, its small peanuts. That was how I pitched it to my wife anyway. Long story short, RAM was purchased with little more than a halfhearted glare from said woman, so I think we're cool...

Back to the plan.

I am going to use 2 6522 VIAs as gateways to the address pins of the video RAM. If I actually wanted to, the way I see it is that could be up to a 32 bit video ram address bus if I wished. Clearly, that would be going over board, so I plan on maybe starting by using one VIA as a 16 bit address port to video RAM, and a few pins of I/O on the second VIA to operate chip enables and the like. This gives me a ton of room for expansion to a larger address space if I want. Data pins of video ram will be on normal data bus.

So what I'd do, is to first output the desired address on the VIA GPIOs, which will be directly connected to the video RAM address pins. Next, I'll put the value to be sent to video in one register, and a byte setup to operate the proper chip select and enables in another register. I'd then send the enables. Next, I'd write my data byte to some place in system RAM, except since the video RAM is write enabled, it too would clock in the value. Next I turn off the enables and we go on our merry way!

I think doing reads would be a little more complicated, but doable. Also, likely unnecessary, so I don't plan to worry about that for now.

My plan is to implement the 64k video RAM version, and expand it until performance gets hit to badly.

Any thoughts? I never see people talk about doing it this way, which makes me think I'm missing something. It's biggest pros to me are simplicity, expand ability, and can be done with parts I already possess.


Top
 Profile  
Reply with quote  
PostPosted: Sat Feb 03, 2018 9:21 pm 
Offline
User avatar

Joined: Mon May 12, 2014 6:18 pm
Posts: 365
It sounds like your writes to video memory would be slowed way down by resetting the address every time and managing the control signals yourself. Why not have one port of the video memory mapped so the 6502 can generate write signals itself? If you have room, you could map a 256 byte stretch of address space to the video ram. That way you could set the high byte with the VIA and let the processor generate the low byte. If you're copying large blocks of data, you might not have to change the high byte very often. Another idea if you're copying sequential data would be to hook 74 series 8 bit counter chips to the VIA. Before you copy a block, load the counters with the VIAs then have your glue logic generate an increment signal to the counters every time you output something to video RAM. That way you only need one byte of address space for video RAM and you gain a small increase in speed writing to a fixed address, rather than using indexing mode.


Top
 Profile  
Reply with quote  
PostPosted: Sat Feb 03, 2018 9:57 pm 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
I think I like your first idea, especially since reads and writes suddenly become identically easy.

If I understand you correctly, I manually put the high byte(s) of the address on the SRAM pins with the VIA(s). The lowest byte of video RAM would then be mapped like any other I/O device. So I just do a read or write to that, and all control lines just happen automatically.

Am I understanding that correctly?

Whats more, if I devise a screen resolution cleverly so that the screen locations where the high bytes need to be changed are right on the beginning of a horizontal line, pixel locating math could be slightly simplified.


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 04, 2018 3:35 am 
Offline

Joined: Sat Jun 04, 2016 10:22 pm
Posts: 483
Location: Australia
If it's 8 bits per pixel, you could have the horizontal resolution being 256.
Mind you, you might not have to limit yourself to 256 bytes per line if you're a bit clever with the wiring...


Top
 Profile  
Reply with quote  
PostPosted: Sat Feb 10, 2018 11:08 pm 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
Here's a strange bug that I fixed, but can't understand what is truly happening.

The following is a subroutine that takes a string entered by the user, looks for spaces, and separates the string into a command and arguments. It just scans the string (in COM1_RXBUF), and every time it sees a space, it converts it to a NULL, and creates an index to the next character in a array so that the argument can be located by the parser later. It does this until it finds a NULL, meaning the end of the string.

Long story short, it turns a long string of words into a buffer of null terminated command and arguments.

It works perfectly, except...

If I try to save any of my registers on the stack, and there are ANY arguments, the computer crashes when I RTS. If I enter a command with no arguments, it returns just fine. Using an LED as an indicator (poor man's debugger), all seems well until I RTS.

In the below code, I have the stack calls commented out. Un-commmenting any single push or pull pair (or all of them) causes the bug. The actual contents of those registers are not really needing to be saved when this sub routine is called, and I save them just out of habit and "just in case". Things work great with out saving them.

So I'm basically just trying to see what the heck is happening?

My reset routine sets the stack at $FF. I should have TONS of room still on the stack when this routine is called. I can't see that any of my memory writes go anywhere NEAR the stack. Actually, can you even do that (use $100 page like regular memory accidentally?). I can't see that I'm doing that anywhere. My first RAM allocations start at $200, and I really don't use much at all.

Here's the subtroutine:

Code:
;*****************************************************************************
;Process commandline subroutine.                                             *
;puts indices to individual arguments into memory location labled  ARG_INDEX *
;*****************************************************************************
 
process_cmdln:;   PHA
         ;   PHX
         ;   PHY
      STZ   CMDLN_ERROR   ;clear command line error byte
      STZ   ARG_CNT      ;reset argument count
      LDX   #$00      ;clear X register
      LDY   #$00      ;clear Y register
find_spaces:   LDA   COM1_RXBUF,X   ;get current character
      CMP   #$00      ;is it a NULL?
      BEQ   cmdln_exit   ;if its a NULL, we are at the end of the string. Return from subroutine
      CMP   #$20      ;is it a space?
      BEQ   add_arg      ;if its a space, branch to add argument
      INX         ;increment to next character
      JMP   find_spaces   ;keep looking
add_arg:   STZ   COM1_RXBUF,X   ;convert SPACE into NULL.
      INX         ;increment character index. Will be at first char of argument now
      STX   ARG_INDEX,Y   ;store index into string buffer to current argument
      INY         ;increment argument count index.
      CPY   #$04      ;check if we are above max number of arguments
      BCS   cmdln_err   ;if too many args, error and rts
      STY   ARG_CNT      ;store number of arguments.
      JMP   find_spaces   ;go back to searching string for aruments                                          
cmdln_err:   LDA    #$FF         
      STA   CMDLN_ERROR   ;put $FF in error flag byte
      STZ   ARG_CNT      ;reset argument count     
cmdln_exit:   
          ;PLY
          ;PHX
          ;PHA
      RTS


Top
 Profile  
Reply with quote  
PostPosted: Sat Feb 10, 2018 11:57 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3363
Location: Ontario, Canada
Code:
          ;PLY
          ;PHX
          ;PHA
      RTS
Can it be as simple as a pair of typos -- the result of a copy-paste error, perhaps? (I've done stuff like that.) Surely these should all be pulls (not a pull and two pushes). This just jumped out at me. I haven't yet begun looking at the body of the routine.

Yet you say (if I understand correctly) the routine appears to return successfully if there are no arguments. I'm thinkin that's a fluke of some kind.

ETA: The RTS would load PC with A:X which just got pushed, then increment PC as always with a 65xx family RTS. I think A and X are both zero, and if so then RTS will cause the chip to start executing whatever the heck is at $0001!

_________________
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: Sun Feb 11, 2018 1:44 am 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
hmmm...

I see the typo's. I've typed, cut and pasted, rettyped yada yada these snippits many times, and I can't believe I'd make that blunder each time, yet...

lemme get back to ya. :lol:


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 11, 2018 1:57 am 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
Nope, fixed the errant PHs. It still only works when I comment out the pushes and pulls. (I push A X and Y in that order in the beginning, and I pull them in the opposite order before RTS)

Stink'n weird I tell ya!

I re-checked all my RAM accesses. I don't get near the stack.

Here's another clue. Lets say my return address somehow got jumbled on the stack, and I RTS to something random. Wouldn't my ACIA (Rockwell 6551) still send an interrupt when It receives data? Doesn't it work independently to the processor, until they need to exchange data? Under normal operation, I have it set to send and interrupt when it receives a character from the terminal (i press a key on my laptop in this case). I probe the interrupt pin on the 6502, and when the crash happens, I no longer get interrupts. I can't see how even if the CPU was in lala land, that it would effect the ACIA in this way. Its clocked directly from the system clock, not the PH2 output on the cpu.

I'm baffled. I guess I can leave those stack calls out, but I don't like not understanding.


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 11, 2018 2:01 am 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
Ooh... another clue...

That IRQ pin is being held LOW when the crash happens. Its on a pull-up, so when I unhook the ACIA's IRQ line, it goes back HIGH, as it should be.

What the crap would a stack call be doing that would trigger the ACIA to get stuck sending an IRQ?


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 11, 2018 2:53 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3363
Location: Ontario, Canada
Dan Moos wrote:
Wouldn't my ACIA (Rockwell 6551) still send an interrupt when It receives data? Doesn't it work independently to the processor
If the ACIA has previously been configured to generate an interrupt on receive then yes it'll automatically (ie, without intervention from the CPU) pull its interrupt output low when a character arrives. But the line will remain low until the CPU reads the ACIA status register or whatever -- an action which'd be part of the interrupt service routine ISR. So if the line remains low it's possibly because the ISR didn't execute.

Are interrupts enabled while the subroutine (above) executes? I don't quite see how the interrupt context and the foreground context relate. Consequently I may not be making any sense but I'm gonna keep asking questions anyway :)

When you refer to a failure, that simply means failure to return from the subroutine, right? And, if the pushes & pulls are allowed (not commented out), what's the result if the subroutine is called ...

- before any keypresses
- after 1 keypress
- after 2 or more keypresses ?

And, correspondingly, what three results are obtained when pushes & pulls are removed (commented out)?

_________________
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: Sun Feb 11, 2018 3:25 am 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
Your take on why my IRQ line is low pretty much makes sense, so I think you are right. Its low because the ACIA gets a keypress, sends the interrupt, which is never responded to by a locked up CPU, and thus, stays low.

Not sure how to answer your specific questions, so I'll try my best.

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, this routine doesn't respond to keypresses per se. It is called after enter is pressed. So if there is no arguments, the small portion that deals with indexing and counting the arguments is never run. That is really the only difference between it getting arguments and not. Also, it is definitely running this portion when it should, because as you may see, I keep a count of the number of arguments it finds. I tried sending this count to the VIA and displayed it with LEDs. It always shows the correct count, even if it crashes.

Using the VIA and an LED, I found the last moment that the cpu is not crashed. Any time before RTS, all is well. I try lighting the LED in the calling routine directly after the JSR call, and it never lights. So it seems the return address is being lost. The fact that me making stack calls causes this, kinda lines up here. Except I can't see how it's happening. I tried simply PHY at the start, and PLY at exit to simplify matters. Still crashes. Its as if my pushes and pulls aren't pared up. Your spotting that typo in my code surely looks like the culprit, but I fixed that to no avail. I think that typo never was even run, and was an error when I was messing with the thing to post it here.


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 11, 2018 3:47 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1933
Location: Sacramento, CA, USA
Perhaps your main program is unintentionally dependent on the register side-effects of your subroutine, and the crash is happening several instructions after the RTS, back in main? I forgot to check, but are you running NMOS? If you hit one of the NMOS JAM instructions, your interrupt will not be serviced and the request will remain asserted indefinitely. If you are running CMOS, is your firmware able to properly handle a BRK instruction if you (intentionally or accidentally) execute it?

Code:
      ...
add_arg:   STZ   COM1_RXBUF,X   ;convert SPACE into NULL.
      INX         ;increment character index. Will be at first char of argument now
      STX   ARG_INDEX,Y   ;store index into string buffer to current argument
      INY         ;increment argument count index.
      CPY   #$04      ;check if we are above max number of arguments
      BCS   cmdln_err   ;if too many args, error and rts
      STY   ARG_CNT      ;store number of arguments.
      JMP   find_spaces   ;go back to searching string for aruments                                          
      ...

The first argument (if it exists) will always have an index of 0, so the 0 doesn't need to be stored, but perhaps you haven't noticed that your subroutine doesn't really distinguish between zero arguments and one argument (except as an X register side-effect), because your ARG_CNT is actually a SPACE_CNT, AFAICT.

Mike B.

[Edit: Please ignore my first question as it was answered earlier.]


Last edited by barrym95838 on Sun Feb 11, 2018 4:12 am, edited 2 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 11, 2018 4:06 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3363
Location: Ontario, Canada
Quote:
sends the interrupt, which is never responded to by a locked up CPU, and thus, stays low.
Just a point of expression to double check here. Even a CPU that's off in lala land may still respond normally to interrupts. The CPU may be executing garbage but it never "locks up" (stops executing) except an NMOS chip if it eats a certain undefined opcode. As long as the garbage doesn't include an SEI or the NMOS lockup opcode (and you're using an NMOS chip) then interrupt service will be unaffected. The ISR ends with an RTI and this'll simply return us to the garbage.

Dan Moos wrote:
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.
That sounds complete and sensible, but it says nothing about the interrupts you mentioned earlier. Can you explain, please, or else post ALL the code (if it's not too long)?

edit: a WDC CPU that executes a STP or WAI can also lock up (stop executing)
edit2: oops, didn't notice your post at first, Mike. I've needlessly echoed your point about the JAM instructions.

_________________
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  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 321 posts ]  Go to page Previous  1 ... 17, 18, 19, 20, 21, 22  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 19 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:  
cron