Improved MENSCH™ Microcomputer Software
Re: Improved MENSCH™ Microcomputer Software
@BDD, thanks for the code example, it was instructive. I remember you discussing synching the direct page pointer with the stack frame, but I didn't have enough context to understand what it achieved. I get it now; programs no longer need a shared direct page area (formerly page zero); every function has its own direct page! This eliminates the tension between dedicating blocks of the direct page versus reusing parts of it. The latter being an attractive nuisance for bugs.
To resolve this on the 6502, I used a Forth like page zero data stack using the X register. But the 65816 builds that into its much larger data and return stack. Making this convention unnecessary.
BTW I laughed at the "cld ;just in case!" line. I love programming the 6502 and I understand why it has support for packed decimal, but it's a potential for hard-to-find bugs.
To resolve this on the 6502, I used a Forth like page zero data stack using the X register. But the 65816 builds that into its much larger data and return stack. Making this convention unnecessary.
BTW I laughed at the "cld ;just in case!" line. I love programming the 6502 and I understand why it has support for packed decimal, but it's a potential for hard-to-find bugs.
- BigDumbDinosaur
- Posts: 9427
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: Improved MENSCH™ Microcomputer Software
Martin_H wrote:
@BDD, thanks for the code example, it was instructive.
A certain amount of patient experimentation went into that framework before I was satisfied with it and felt it was safe to make it public. An objective, aside from taking advantage of the 816’s movable direct page, was to automate the process as much as possible to prevent messing up the stack—debugging something like that can be challenging.
Something to note is when DP is pointed to the stack in my framework, the offset starts at $00. This is in contrast to using stack-relative addressing, in which the offset starts at $01. The $00 offset is the result of the TSC - INC - TCD sequence, which I came up with to avoid an off-by-one error when addressing the temporary direct page. I am generally not concerned with this offset business, as I give each register a symbol and only use that symbol to access the register’s stack copy.
Another thing worth noting is the order in which the registers are pushed to the stack. By pushing .Y before .X, it becomes possible to pass a 32-bit pointer in those registers, with the least-significant word (LSW) in .X, and use indirect-long addressing. Passing the LSW in .Y is possible if the registers are reversed on the stack, of course. However, as the low-high combination in .X-.Y is common in much 6502 programming, I felt it was best to stick with it.
I always push DP last, so it is at SP+1 on the stack. By doing so, I can revert to the entry direct page within the function, if necessary, with LDA $00 - TCD, without changing the register stack frame. I can go back to the local direct page by again using the TSC - INC - TCD sequence. Or, if switching between the local and entry direct pages is to happen multiple times, I push the local DP value to SP+1 (with the entry DP at SP+3) so I can easily fetch the local DP with LDA $01,S when DP is pointed elsewhere.
A caution regarding these stack and direct page shenanigans is in order. It is essential that your operating environment, especially interrupt handlers, not make any assumptions about what is in DB (data bank) and DP, or the sizes of the registers. In particular, always keep in mind that if the index registers are set to eight bits, whatever is in the MSB of both registers will vanish. This is unlike the accumulator, which will retain the MSB in .B—.B remains accessible through the XBA instruction.
The other register “gotchas” to watch out for are the TDC and TSC instructions. Those two transfer a 16-bit value into the accumulator without regard to the accumulator’s width, replacing whatever was in .B with the MSB of the source register.
Quote:
BTW I laughed at the "cld ;just in case!" line. I love programming the 6502 and I understand why it has support for packed decimal, but it's a potential for hard-to-find bugs.
Last edited by BigDumbDinosaur on Fri Feb 06, 2026 8:26 pm, edited 1 time in total.
x86? We ain't got no x86. We don't NEED no stinking x86!
Re: Improved MENSCH™ Microcomputer Software
I successfully ported a rewritten Arduino Ping))) sample and the required pbPulsin function. There was only a single bug in the pbPulsin function. Woot woot!
Challenges:
- Debugging real-time signals is difficult. For example, debug output statements can't be used.
- Most of the issues were within the sample program and div16 function; it took longer to debug the test environment than the function itself.
- The Ping))) sensor draws significant current, which caused phantom issues when running on USB power. Switching to battery power resolved this.
Next Steps:
- I am porting a line sensor demo using the pbRCTime function. The pbRCTime function is similar to pbPulsin, so it should be faster.
- The timer continues to run after the pulse trailing edge transition. This doesn't affect subsequent calls, but I would like to find a way to stop it entirely.
Challenges:
- Debugging real-time signals is difficult. For example, debug output statements can't be used.
- Most of the issues were within the sample program and div16 function; it took longer to debug the test environment than the function itself.
- The Ping))) sensor draws significant current, which caused phantom issues when running on USB power. Switching to battery power resolved this.
Next Steps:
- I am porting a line sensor demo using the pbRCTime function. The pbRCTime function is similar to pbPulsin, so it should be faster.
- The timer continues to run after the pulse trailing edge transition. This doesn't affect subsequent calls, but I would like to find a way to stop it entirely.
Re: Improved MENSCH™ Microcomputer Software
I know this is a fairly simple question. I'm outputting data as text and want the absolute value. No problem I'll just write a function.
I'm just wondering if there's a spiffier way to do this.
Code: Select all
; abs16 - takes the absolute value of the input.
; Inputs:
; C - number of take absolute value.
; Outputs
; C - result
PUBLIC abs16
and #$ffff
bpl @return
dec ; undo two's complement
eor #$ffff
@return: rts
ENDPUBLIC
Re: Improved MENSCH™ Microcomputer Software
Not really very spiffy, but here's what I notice offhand.
This 3-byte, 3-cycle instruction you used isn't the only way to test the accumulator's sign bit and update the N flag. Instead, ...
is only 1 byte and 2 cycles (but it assumes you don't mind trashing X or Y); and
is 2 bytes and 4 cycles.
-- Jeff
Code: Select all
and #$ffffCode: Select all
TAX ;(or TAY)Code: Select all
ROR
ROL-- Jeff
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
- BigDumbDinosaur
- Posts: 9427
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: Improved MENSCH™ Microcomputer Software
Dr Jefyll wrote:
Not really very spiffy, but here's what I notice offhand.
This 3-byte, 3-cycle instruction you used isn't the only way to test the accumulator's sign bit and update the N flag. Instead, ...
is only 1 byte and 2 cycles (but it assumes you don't mind trashing X or Y); and
is 2 bytes and 4 cycles.
Code: Select all
and #$ffffCode: Select all
TAX ;(or TAY)Code: Select all
ROR
ROLx86? We ain't got no x86. We don't NEED no stinking x86!
Re: Improved MENSCH™ Microcomputer Software
BigDumbDinosaur wrote:
Try ORA !#0 to flip your flags...
-- Jeff
ps- But I agree that there are usually several different ways to skin the cat. (Poor kitty!)
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: Improved MENSCH™ Microcomputer Software
I debugged the pbRCTime function and was able to read a line sensor value. Line following robots are always fun.
I'll leave the abs16 function as I don't want to trash the other registers, so 3 cycles 3 bytes is good enough.
I added umax16 and umin16 functions as I'm sure they'll come in handy for clamping servo pulse widths to max and min values. That's useful in preventing servo burnout if a bug starts sending pulse widths outside of RC specs. I'm mean hypothetically, it's not like I let the magic smoke out of a servo doing that.
I also ported and debugged my unsigned square root usqrt16. Useful when doing odometry and dead reckoning. Technically calling it usqrt16 is overkill since only positive numbers have real square roots, but I decided to follow my own naming convention.
PBasic also has an integer trigonometry, and I wrote a 6502 version of that years ago. So, I'll need to port that if I want to do dead reckoning as well.
I'll leave the abs16 function as I don't want to trash the other registers, so 3 cycles 3 bytes is good enough.
I added umax16 and umin16 functions as I'm sure they'll come in handy for clamping servo pulse widths to max and min values. That's useful in preventing servo burnout if a bug starts sending pulse widths outside of RC specs. I'm mean hypothetically, it's not like I let the magic smoke out of a servo doing that.
I also ported and debugged my unsigned square root usqrt16. Useful when doing odometry and dead reckoning. Technically calling it usqrt16 is overkill since only positive numbers have real square roots, but I decided to follow my own naming convention.
PBasic also has an integer trigonometry, and I wrote a 6502 version of that years ago. So, I'll need to port that if I want to do dead reckoning as well.
Re: Improved MENSCH™ Microcomputer Software
I have the pbPWM function and pwm_led.asm sample working. The LED grows slowly brighter, slowly dimmer, and then returns to the monitor. My planned use of this function is controlling a motor's speed through an H bridge.
I learned something important. If you change the direct page register and later call the monitor's I/O routines, it behaves unpredictably. Good to know for the future.
I learned something important. If you change the direct page register and later call the monitor's I/O routines, it behaves unpredictably. Good to know for the future.
Re: Improved MENSCH™ Microcomputer Software
Martin_H wrote:
If you change the direct page register and later call the monitor's I/O routines, it behaves unpredictably.
Right. Got it!
-- Jeff
Martin_H wrote:
[...] servo burnout if a bug starts sending pulse widths outside of RC specs. I'm mean hypothetically, it's not like I let the magic smoke out of a servo doing that.
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: Improved MENSCH™ Microcomputer Software
Martin_H wrote:
My planned use of this function is controlling a motor's speed through an H bridge.
At that price it's not worth buying and soldering transistors!
Neil
Re: Improved MENSCH™ Microcomputer Software
Dr Jefyll wrote:
I assume you mean it hypothetically could behave unpredictably if used in that way. It's not like you experienced unpredictable behavior by doing so.
Right. Got it!
-- Jeff
Right. Got it!
-- Jeff
barnacle wrote:
There are some _excellent_ tiny H-bridge motor controllers available on LCSC's parts list, available for literally pennies: e.g. https://www.lcsc.com/product-detail/C18 ... controller
At that price it's not worth buying and soldering transistors!
At that price it's not worth buying and soldering transistors!
Re: Improved MENSCH™ Microcomputer Software
Martin_H wrote:
Thanks for the link. Yes, it's better to use an IC over discrete components. In the past I've used an SN754410 because it has an enable line, but I'm always open to newer IC's. I use two pins to control motor direction and a third as a PWM channel to control velocity. With a single VIA port, you can control up to three motors with a single PWM channel for their velocity. Better programmers than me could probably squeeze two PWM channels out of a single VIA port.
A disadvantage is that you need 3 outputs per motor (or 2 plus an inverter) but it means you can use high or low 'braking' to stop a motor quickly if needed. Basically 2 pins to set direction or braked and one pin to provide on/off pulses.
-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
Re: Improved MENSCH™ Microcomputer Software
I'm reading the WDC monitor source to understand how it sets and clears the tone generators. Here's a link to the code:
https://github.com/WesternDesignCenter/ ... _TONES.ASM
Overall I understand it, but one thing confuses me. The store instructions have an '!' character before the address.
I read the WDC assembler syntax and it says that is an absolute address. All the 6502 assemblers I've used don't have a character that indicates absolute addressing, it's implied for a two-byte address, and T5CL is $DF6A.
I just want to make sure this isn't some extra fancy 65816 absolute addressing mode that I don't know about.
https://github.com/WesternDesignCenter/ ... _TONES.ASM
Overall I understand it, but one thing confuses me. The store instructions have an '!' character before the address.
Code: Select all
STX !T5CL
I just want to make sure this isn't some extra fancy 65816 absolute addressing mode that I don't know about.
- BigDumbDinosaur
- Posts: 9427
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: Improved MENSCH™ Microcomputer Software
Martin_H wrote:
The store instructions have an '!' character before the address.
x86? We ain't got no x86. We don't NEED no stinking x86!