6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 1:43 pm

All times are UTC




Post new topic Reply to topic  [ 127 posts ]  Go to page 1, 2, 3, 4, 5 ... 9  Next
Author Message
PostPosted: Sat May 02, 2020 11:52 pm 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 746
Location: Germany
Hi everyone.
(i'm already sorry if this post is kind of a mess, i'm not good at writing informative things)

I've been working for the past few weeks on a Project, and as the title may suggest it's an Extended 6502 build in a logic simualtor known as Logisim (Evolution HC).
GitHub link to that here: https://github.com/kevinawalsh/logisim-evolution
I currently just call the CPU "6502V" for one reason, if you read the last 3 characters backwards it says "V20", and that is the CPU i basically want to replicate in function.
(for anyone who doesn't know the V20 is an Intel 8088 compatible CPU that has more instructions and can run at greater clock speeds, but even at the same clock speed it's slightly faster than an 8088 due to fewer cycle counts on some instructions), and i want this to be the V20 of the 6502.
I have already "finished" the circuit, i just need to overlook it to see if i missed any mistakes, then i need to decide on the Instructions to program into it (besides the regular ones i mean).

Here the main goals i want to reach with this CPU:

1. it should be 6502 compatible (minus the bugs)
2. it should be as fast or faster than a 6502 running at the same clock speed (ie fewer cycles per instruction; also more consistent cylce counts, no extra cycles because of page boundaries or something)
3. it should have more instructions and useful features
?. final goal is to have this run on a cheap FPGA, but that'll take a while. first i just want this to work on a Logic Simulator.

The first one is already showing some problems. while making the CPU functionally identical (enough) to the 6502 is not that hard it's the timings of some things that are a bit harder to get right.
for example i assume RDY gets acknowledged on the rising edge of a Memory Access, that is atleast how i wired it up in my CPU...
and SYNC/VPB get pulled down for a whole clock cycle, from falling edge to falling edge.
I was not able to verfy these things, while this site was a big help with the memory accesses it doesn't cover the rest of the control signals, so i just assumed that this is how those signals are supposed to work. the original datasheet wasn't very helpful either...

The second one is pretty easy and basically just a result of the fact that i designed the CPU from scratch instead of just copying the 6502's design.
the only thing that really holds me back from reaching even lower cycles counts are memory accesses.
also having the CPU be faster than a regular 6502 at the same clock speed makes it a bit more likely people will actually this CPU for real projects (once i got Verilog code done).
which would be nice.

The third one, that is also a bit more complicated. because i don't just want to fill the Instruction set with stuff that i think is useful, but rather with stuff that people who have worked with these CPUs for decades think is useful (ie you guys, on this forum).

about the features i have added/plan to add:

Registers:

B - basically a Secondary Accumulator, used for 16 bit arithmetics and some other instructions.
DN (Direct Page) - it's used as the upper byte for any Zeropage Addressing Mode, essentially allowing you to relocate the Zeropage to anywhere in Memory.
SN (Stack Page) - same as DN but for the Stack, upon startup/hardware reset is initialized with 0x01 for backwards compatibility.
VP (Vector Pointer) - this pointer is used to specify where the Vectors for the Reset/IRQ/NMI/BRK are located in Memory, upon startup/hardware reset is initialized with 0xFFFA for backwards compatibility. (one problem is, during a hardware Reset this register is cleared, so it makes the Reset Vector kinda pointless, should it be left uncleared upon a hardware reset? or maybe just be left uncleared after a software reset?)

Now about the instructions:

I'll post them in a style similar to this site that i used as source for all the 6502 instructions.
note that i didn't program any of them so i don't have the cycle counts or opcodes for them (yet).

I took some of the 65C02's Instructions that i found useful: (though i could add more if needed/useful)
Code:
BIT #
BRA r
JMP (a,x)
PHX/PLX
PHY/PLY
INC/DEC A
All instructions that use the Indirect Zeropage addressing mode


Code:
#------------------------------------------------#
 Existing Instructions with new Addressing Modes:
#------------------------------------------------#

LDA      - Load Accumulator with Memory

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   ind zp post-inc   LDA (oper)+      -      2      -
   ind zp pre-dec   LDA -(oper)      -      2      -


STA      - Store Accumulator in Memory

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   ind zp post-inc   STA (oper)+      -      2      -
   ind zp pre-dec   STA -(oper)      -      2      -


JSR      - Jump Subroutine

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   indirect,X      JSR (oper,x)   -      3      -
   long relative   JSR oper      -      3      -


ADC      - Add Memory to Accumulator with Carry

   N Z C I E D V
   + + + - - - +

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         ADC B         -      1      -


SBC      - Subtract Memory from Accumulator with Borrow

   N Z C I E D V
   + + + - - - +

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         SBC B         -      1      -


AND      - AND Memory with Accumulator

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         AND B         -      1      -


ORA      - OR Memory with Accumulator

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         ORA B         -      1      -


XOR      - XOR Memory with Accumulator

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         XOR B         -      1      -


CMP      - Compare Memory with Accumulator

   N Z C I E D V
   + + + - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         CMP B         -      1      -


#-----------------#
 New Instructions:
#-----------------#


LDB      - Load Secondary Accumulator (B) with Memory

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   immidiate      LDB #oper      -      2      -
   zeropage      LDB oper      -      2      -
   zeropage,X      LDB oper,X      -      2      -
   absolute      LDB oper      -      3      -
   absolute,X      LDB oper,X      -      3      -


LDV      - Load Vector Pointer with Memory

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   immidiate      LDV #oper      -      3      -
   zeropage      LDV oper      -      2      -


STB      - Store Secondary Accumulator (B) in Memory

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   zeropage      STB oper      -      2      -
   zeropage,X      STB oper,X      -      2      -
   absolute      STB oper      -      3      -
   absolute,X      STB oper,X      -      3      -

STV      - Store Vector Pointer in Memory

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   zeropage      STV oper      -      2      -


TXD      - Transfer X to Direct Page

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         TXD            -      1      -


TXN      - Transfer X to Stack Page

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         TXN            -      1      -


TDX      - Transfer Direct Page to X

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         TDX            -      1      -


TNX      - Transfer Stack Page to X

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         TNX            -      1      -


SNB      - Swap Nibble (of the Accumulator)

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         SNB            -      1      -


SAB      - Swap Accumulator and Secondary Accumulator (B)

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         SAB            -      1      -


SXY      - Swap X and Y

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         SXY            -      1      -


PHB      - Push Secondary Accumulator (B) on Stack

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         PHB            -      1      -


PHM      - Push Memory on Stack

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   zeropage      PHM oper      -      2      -


PLB      - Pull Secondary Accumulator (B) from Stack

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         PHB            -      1      -


PLM      - Pull Memory from Stack

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   zeropage      PLM oper      -      2      -


BRL      - Branch Always Long

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   long relative   BRL oper      -      3      -


SEV      - Set Overflow Flag

   N Z C I E D V
   - - - - - - 1

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         SEV            -      1      -


SEE      - Set Enable Carry Flag

   N Z C I E D V
   - - - - 1 - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         SEE            -      1      -


CLE      - Clear Enable Carry Flag

   N Z C I E D V
   - - - - 0 - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         CLE            -      1      -


RES      - Software Reset

   N Z C I E D V
   - - - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         RES            -      1      -


MUL      - Multiply Accumualtor with Memory (8 bit) (Low Byte stored in A, High Byte stored in B)

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   immidiate      MUL #oper      -      2      -
   zeropage      MUL oper      -      2      -
   zeropage,X      MUL oper,X      -      2      -
   absolute      MUL oper      -      3      -
   absolute,X      MUL oper,X      -      3      -


DIV      - Divide Accumualtor by Memory (8 bit) (Result stored in A, Remainder stored in B)

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   immidiate      DIV #oper      -      2      -
   zeropage      DIV oper      -      2      -
   zeropage,X      DIV oper,X      -      2      -
   absolute      DIV oper      -      3      -
   absolute,X      DIV oper,X      -      3      -


ADX      - Add Secondary Accumulator (B) to X with Carry

   N Z C I E D V
   + + + - - - +

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         ADX B         -      1      -


SBX      - Subtract Secondary Accumulator (B) from X with Borrow

   N Z C I E D V
   + + + - - - +

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         SBX B         -      1      -


ADY      - Add Secondary Accumulator (B) to Y with Carry

   N Z C I E D V
   + + + - - - +

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         ADY B         -      1      -


SBY      - Subtract Secondary Accumulator (B) from Y with Borrow

   N Z C I E D V
   + + + - - - +

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   implied         SBY B         -      1      -


ADW      - Add Memory Word to Accumulator with Carry (16 bit) (Low Byte stored in A, High Byte stored in B)

   N Z C I E D V
   + + + - - - +

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   immidiate      ADW #oper      -      3      -
   zeropage      ADW oper      -      2      -
   zeropage,X      ADW oper,X      -      2      -
   absolute      ADW oper      -      3      -
   absolute,X      ADW oper,X      -      3      -


SBW      - Subtract Memory Word from Accumulator with Borrow (16 bit) (Low Byte stored in A, High Byte stored in B)

   N Z C I E D V
   + + + - - - +

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   immidiate      SBW #oper      -      3      -
   zeropage      SBW oper      -      2      -
   zeropage,X      SBW oper,X      -      2      -
   absolute      SBW oper      -      3      -
   absolute,X      SBW oper,X      -      3      -


INW      - Increment Memory word by One (16 bit)

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   zeropage      INW oper      -      2      -
   absolute      INW oper      -      3      -


DEW      - Decrement Memory word by One (16 bit)

   N Z C I E D V
   + + - - - - -

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   zeropage      DEW oper      -      2      -
   absolute      DEW oper      -      3      -

(no idea why the TABs are broken, it looks perfectly aligned in Notepad++ and Pastebin)

a bit more detail about some things though:

the E Flag, or "Enable Carry" Flag.
This flag is by default 1, when cleared it makes all ADC and SBC instructions (including the 16 bit variants) behave like regular ADD and SUB instructions similar to non-6502 CPUs.
that way you don't need to constantly set or clear the flag before Adding/Subtracting something.
especially useful since this CPU natively supports 16 bit Addition/Subtraction, so unless you run some regular 6502 code or need to do 32 bit math, it can simply be cleared to save yourself some SEC and CLC Instructions here and there.

next up the "ind zp post-inc" (Indirect Zeropage Post-Increment) and "ind zp pre-dec" (Indirect Zeropage Pre-Decrement) addressing modes.
the first one works like the regular "Indirect Zeropage" addressing mode, but after the read/write it Adds the contents of B to the Address and writes it back to Memory.
the second works the same but before the read/write it subtracts the contents of B from the Address, and after the read/write writes the Address back to Memory.

the idea behind using the B register instead of just Incrementing/Decrementing was to give programmers more control.
I also thought about an alternative way of doing these 2 Addressing Modes. instead of adding/subtracting B as an unsigned value, i could instead only add it but treat it like a signed value, so both the "post" and "pre" addressing modes could be used to go backwards and forwards in Memory instead of being locked to a single direction, giving the programmer even more control over them without adding more instructions. (plus ironically, it would make the circuitry a bit easier)

.

I like to hear some thoughts about this project, and Obviously i'm open for suggestions on what could get added/removed or should be changed. (to be honest i can already see the AND B, ORA B, and XOR B instructions getting removed, since i don't really know what they would be useful for, since it's slower than just using an immediate AND/OR/XOR)
and of course help is also welcome about some details on how things work... for example the timings, and i also still need to do the BCD Adder/Subtractor... but I'll pass on that one until much later.

anyways, i'm tried, and probably missed some important detail, like always.
but i'll care about that tomorrow after i got some sleep.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 03, 2020 1:57 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
You could start with the topic, "Instructions that I missed."

_________________
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  
PostPosted: Sun May 03, 2020 3:10 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
Quote:
i assume RDY gets acknowledged on the rising edge of a Memory Access, that is atleast how i wired it up in my CPU...
Toward the end of every cycle, shortly before the fall of Phi2, motherboard circuitry is responsible for putting the CPU's RDY input high or low. If low (ie; not RDY) then the following cycle will be a repeat of the present cycle. Exception: on NMOS, write cycles can't be extended; only read cycles.

Quote:
the E Flag, or "Enable Carry" Flag. [...] that way you don't need to constantly set or clear the flag before Adding/Subtracting something.
This makes me uneasy, because you're adding another Mode Bit. I'm reminded of a quotation that appears in The Soul Of A New Machine. Ed de Castro (a high-level manager/exec at Data General at the time) said something more or less as follows. "The trouble with Mode Bits is you're always getting tied up in your own underwear" (!) :lol:

I don't think I need to explain that warning. Also, let me point out that your goal of eliminating dead cycles means the penalty for including a CLC or SEC shrinks from two cycles down to one. IOW, the E Flag idea is solving a problem whose impact has already been cut in half.


Extending/improving 65xx is a topic that keeps coming up again and again. Often it's just for discussion, and that's fine, but I give extra points to anyone who manages to do an actual implementation!

Cheers,
Jeff

_________________
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 May 03, 2020 5:37 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
Thanks for the major post, as a new thread, and for sharing your thoughts, Proxy.

For your reset vector puzzle, perhaps consider a separate input for power on reset, then you can distinguish cold start from warm start.

GARTHWILSON wrote:
You could start with the topic, "Instructions that I missed."

Better yet - though I say it myself - see


Top
 Profile  
Reply with quote  
PostPosted: Sun May 03, 2020 10:57 am 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 746
Location: Germany
GARTHWILSON wrote:
You could start with the topic, "Instructions that I missed."

BigEd wrote:
Better yet - though I say it myself - see


Thanks for the thread links, though i haven't read through all of them, quite a few 6502 based CPUs just seem like higher bit extensions (mostly 32 bits it seems) of the 6502, instead of aiming to be a drop-in replacement for a regular 6502.
it still is helpful to see what people would want in a CPU, especailly on the threads around the 65Org32.
though for obvious reasons i cannot implement anything, though i got future plans for a 16 bit 6502 based CPU, but that'll take some time and i doubt it'll be binary compatible as i like things to be aligned to memory words (like the 68k, and unlike the 8086 for example)

also today i learned that the 65CE02 exists... and it's almost the same CPU i'm trying to build here (atleast in terms of cycle improvements).
but aparently the CPU was not used very often and not many chips seem to exist anymore and there doesn't appear to be a softcore version of it, so i guess my project still has some kind of relevance...? especailly if i port it to an FPGA.
plus it means i can steal some Instructions from it, like the long conditional branches.

BigEd wrote:
Thanks for the major post, as a new thread, and for sharing your thoughts, Proxy.

For your reset vector puzzle, perhaps consider a separate input for power on reset, then you can distinguish cold start from warm start.

but why have a Power-on Reset input at all when that could just be handled by the CPU internally?
hmm, but maybe a soft reset as instruction and hardware input could be good?

Dr Jefyll wrote:
Toward the end of every cycle, shortly before the fall of Phi2, motherboard circuitry is responsible for putting the CPU's RDY input high or low. If low (ie; not RDY) then the following cycle will be a repeat of the present cycle. Exception: on NMOS, write cycles can't be extended; only read cycles.

i knew the NMOS 6502 couldn't do extended write cycles with RDY, but to be honest would it break anything if i implemented it anyways?
also if i understood this correctly it just repeats the cycle instead of extending it? so for a read cycle it would basically just do 2 reads of the same address in a row?
and what about the setup time of the address bus?

Dr Jefyll wrote:
This makes me uneasy, because you're adding another Mode Bit. I'm reminded of a quotation that appears in The Soul Of A New Machine. Ed de Castro (a high-level manager/exec at Data General at the time) said something more or less as follows. "The trouble with Mode Bits is you're always getting tied up in your own underwear" (!) :lol:

I don't think I need to explain that warning. Also, let me point out that your goal of eliminating dead cycles means the penalty for including a CLC or SEC shrinks from two cycles down to one. IOW, the E Flag idea is solving a problem whose impact has already been cut in half.

to be honest i'm not entirely sure what that warning is supposed to mean...
i assume you just mean it can get hard to keep track of what mode you're in?
i guess so, especailly with larger programs and interrupts...
but what else could the bit be used for that is not a mode switch?
A half-carry? A parity flag? A dummy bit that can be set/cleared/branched with and the programmer decides what it's used for? or just nothing and it's the same as in the 6502.

Dr Jefyll wrote:
Extending/improving 65xx is a topic that keeps coming up again and again. Often it's just for discussion, and that's fine, but I give extra points to anyone who manages to do an actual implementation!

thanks, i try my best.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 03, 2020 11:48 am 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
When RDY is pulled low, the address bus remains stable for the additional cycle. On the '816, the data bus also remains in data mode and doesn't present the bank address again. It's up to the glue logic to also ensure that derived /OE and /WE signals remain stable during a wait-state. I recommend you follow the CMOS 6502 behaviour of having RDY be significant for writes as well as reads, especially if you'll be cleaning up dead cycles; the only reason to keep the NMOS behaviour is to preserve timing compatibility, as the 65802 did.

The problem with mode flags is that you have to ensure you're in the correct mode before executing any instruction that depends on them. The 6502 only has the Decimal flag, which is relatively straightforward to handle by clearing it at Reset and on interrupt entry, and only setting it briefly on the comparatively rare occasions it's needed.

The '816 has two additional mode flags (ignoring the Emulation bit, which you would deal with during Reset and ignore thereafter) which have a profound effect on the CPU's operation, as they not only affect the width of operations involving their respective registers, but also the size of Immediate-mode instructions. It is perhaps relatively easy to choose default sizes for these registers, in a similar manner to the Decimal flag, even though individual subroutines will more often want to temporarily change the accumulator size at least. I think I would default to 8-bit accumulator, 16-bit indexes.

But a mode flag which determines whether the Carry is significant for ADC and SBC would need to be altered much more frequently, with no clear state that would be used most frequently; to guard against accidentally leaving it in the wrong state, you might have to get into a habit of presetting it on entry to subroutines.

Half-carry is used on some CPUs as part of handling Decimal mode. The 6502 doesn't need it since Decimal mode is built into the ALU, and consequently the '816 is able to do Decimal operations in 16-bit mode as well, handling 4-digit BCD in one go. To do the same trick with half-carries, you'd need three half-carry flags. So the 6809 just disallows running DAA on anything other than the (8-bit) A register.

I honestly have no idea what you'd use a parity flag for. I assume it would reflect whether the result of the most recent ALU operation had an even number of set bits, or an odd number. This is not usually something you need to know.

If you want a user-definable flag, the best thing I can think of is to add an SEV instruction to complement CLV. Very few instructions alter V, and you can already branch on it. The '816 has SEP and REP instructions to set and clear arbitrary combinations of flags; these are one byte larger and one cycle slower than, say, CLC.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 03, 2020 12:43 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
(my guess on the subject of the parity flag is that it's an example of something that's cheap in hardware but expensive in software, so it can seem like good value when designing a new machine. It's needed rarely, but when it is needed, it's nice to have an efficient implementation. See also crc, find first set, bit count, bit reverse. In all cases, of course, there are clever ways to reduce the cost in software: new thread please to discuss that!)


Top
 Profile  
Reply with quote  
PostPosted: Sun May 03, 2020 1:12 pm 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 746
Location: Germany
Chromatix wrote:
When RDY is pulled low, the address bus remains stable for the additional cycle. On the '816, the data bus also remains in data mode and doesn't present the bank address again. It's up to the glue logic to also ensure that derived /OE and /WE signals remain stable during a wait-state. I recommend you follow the CMOS 6502 behaviour of having RDY be significant for writes as well as reads, especially if you'll be cleaning up dead cycles; the only reason to keep the NMOS behaviour is to preserve timing compatibility, as the 65802 did.

ok yea, doing it for both reads/writes seems like a good thing.
changing the circuitry was really easy as well, just switching at which edge the CPU checks for the RDY pin to be low.

Chromatix wrote:
The problem with mode flags is that you have to ensure you're in the correct mode before executing any instruction that depends on them. The 6502 only has the Decimal flag, which is relatively straightforward to handle by clearing it at Reset and on interrupt entry, and only setting it briefly on the comparatively rare occasions it's needed.

The '816 has two additional mode flags (ignoring the Emulation bit, which you would deal with during Reset and ignore thereafter) which have a profound effect on the CPU's operation, as they not only affect the width of operations involving their respective registers, but also the size of Immediate-mode instructions. It is perhaps relatively easy to choose default sizes for these registers, in a similar manner to the Decimal flag, even though individual subroutines will more often want to temporarily change the accumulator size at least. I think I would default to 8-bit accumulator, 16-bit indexes.

But a mode flag which determines whether the Carry is significant for ADC and SBC would need to be altered much more frequently, with no clear state that would be used most frequently; to guard against accidentally leaving it in the wrong state, you might have to get into a habit of presetting it on entry to subroutines.

not entirely sure what you mean with "no clear state that would be used most frequently", i thought having the Carry disabled would be the most common state, since the only reason the carry input even exists on the 6502 is because it makes 16 bit math easier, but since 16 bit math is natively supported on this CPU there is no aparent reason to ever enable the bit unless you run regular 6502 code or need to do >16 bit math (24 bit, 32 bit, etc).

Chromatix wrote:
Half-carry is used on some CPUs as part of handling Decimal mode. The 6502 doesn't need it since Decimal mode is built into the ALU, and consequently the '816 is able to do Decimal operations in 16-bit mode as well, handling 4-digit BCD in one go. To do the same trick with half-carries, you'd need three half-carry flags. So the 6809 just disallows running DAA on anything other than the (8-bit) A register.

I honestly have no idea what you'd use a parity flag for. I assume it would reflect whether the result of the most recent ALU operation had an even number of set bits, or an odd number. This is not usually something you need to know.

If you want a user-definable flag, the best thing I can think of is to add an SEV instruction to complement CLV. Very few instructions alter V, and you can already branch on it. The '816 has SEP and REP instructions to set and clear arbitrary combinations of flags; these are one byte larger and one cycle slower than, say, CLC.

yea i just took that half carry thing from the Z80 same with parity, but as you said the 6502 doesn't need it.
and i did add a SEV instruction, you can find it in the list of instructions i have in the main post.
guess i'll just leave that flag empty for now.

any thoughts on the alternative idea of the post-inc and pre-dec addressing modes i had at the end of the main post?
were it just adds a signed 8 bit value instead of strictly adding/sbtracting an unsigned value, so both "post" and "pre" addressing modes can go forwards and backwards in memory without extra opcodes.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 03, 2020 1:40 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
Interesting point about the 16 bit maths, but I'd say 32 bit is almost as common, so the switching of modes is still likely to happen. I'm of the opinion that modes are awkward - more burden on the programmer and a (small) source of bugs. Adding ADD (and probably SUB) would be a much better way to do it, I think.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 03, 2020 1:41 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
One thing you can do with a mode bit is use to it for a compatibility mode, which is the default mode at boot. That could smooth the way to adoption.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 03, 2020 1:58 pm 
Offline

Joined: Thu Mar 12, 2020 10:04 pm
Posts: 704
Location: North Tejas
Chromatix wrote:
The problem with mode flags is that you have to ensure you're in the correct mode before executing any instruction that depends on them. The 6502 only has the Decimal flag, which is relatively straightforward to handle by clearing it at Reset and on interrupt entry, and only setting it briefly on the comparatively rare occasions it's needed.


A notorious mode flag is the direction bit on x86 processors to determine whether the "string" instructions automagically increment or decrement the index register(s). The usual convention is to leave it clear except for setting it temporarily when decrementing is needed. Things can get weird if something left it set.


Chromatix wrote:
I honestly have no idea what you'd use a parity flag for. I assume it would reflect whether the result of the most recent ALU operation had an even number of set bits, or an odd number. This is not usually something you need to know.


Parity used to be used for error detection in serial communications. Having it calculated by the hardware was handy.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 03, 2020 2:07 pm 
Offline

Joined: Thu Mar 12, 2020 10:04 pm
Posts: 704
Location: North Tejas
Proxy wrote:
Code:
#-----------------#
 New Instructions:
#-----------------#

ADW      - Add Memory Word to Accumulator with Carry (16 bit) (Low Byte stored in A, High Byte stored in B)

   N Z C I E D V
   + + + - - - +

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   immidiate      ADW #oper      -      3      -
   zeropage      ADW oper      -      2      -
   zeropage,X      ADW oper,X      -      2      -
   absolute      ADW oper      -      3      -
   absolute,X      ADW oper,X      -      3      -


SBW      - Subtract Memory Word from Accumulator with Borrow (16 bit) (Low Byte stored in A, High Byte stored in B)

   N Z C I E D V
   + + + - - - +

   addressing      assembler      opc      bytes   cyles
   -----------------------------------------------------
   immidiate      SBW #oper      -      3      -
   zeropage      SBW oper      -      2      -
   zeropage,X      SBW oper,X      -      2      -
   absolute      SBW oper      -      3      -
   absolute,X      SBW oper,X      -      3      -




If you are going to do those, you probably also want to add a way to load and store both accumulators with a single instruction with the absolute addressing modes. Doing one and then the other separately is quite expensive.

You also left out TAB, TBA, TBX, TBY, TXB, TYB.

The designers of the 6809 threw up their hands, got rid of all of them and replaced them with a single transfer (TFR) instruction. The problem is that it takes up two bytes. While they were at it, they also added the similar exchange (EXG) instruction.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 03, 2020 3:12 pm 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 746
Location: Germany
BigEd wrote:
Interesting point about the 16 bit maths, but I'd say 32 bit is almost as common, so the switching of modes is still likely to happen. I'm of the opinion that modes are awkward - more burden on the programmer and a (small) source of bugs. Adding ADD (and probably SUB) would be a much better way to do it, I think.


the problem with that is that it's a lot of new opcodes so i would need to choose what addressing modes should be used.
for example i'd say Immediate, Absolute, Zeropage, and Zeropage X Indexed are probably the most common, so doing ADD, SUB, ADW, and SBW with those 4 modes would add a total of 16 opcodes.
but i need to choose better names, being limited to 3 letters is... well, limiting. but i don't want to break consistency.
maybe these:
Code:
ADC - Add with Carry
SBC - Subtract with Carry (Borrow)
AWC - Add Word with Carry
SWC - Subtract Word with Carry (Borrow)
ADD - Add
SUB - Subtract
ADW - Add Word
SBW- Subtract Word


BigEd wrote:
One thing you can do with a mode bit is use to it for a compatibility mode, which is the default mode at boot. That could smooth the way to adoption.

for this CPU it would be kind of a waste seeing as it's already 6502 compatible, i'll probably look into a compatibility mode if/when i get to CPUs that are not natively 6502 compatible.

BillG wrote:
Chromatix wrote:
I honestly have no idea what you'd use a parity flag for. I assume it would reflect whether the result of the most recent ALU operation had an even number of set bits, or an odd number. This is not usually something you need to know.


Parity used to be used for error detection in serial communications. Having it calculated by the hardware was handy.


yea but unless the CPU has to send/reveice data itself for some reason it's rather useless. usually you got some kind of UART or similar that handles that on a hardware level.

BillG wrote:
If you are going to do those, you probably also want to add a way to load and store both accumulators with a single instruction with the absolute addressing modes. Doing one and then the other separately is quite expensive.

You also left out TAB, TBA, TBX, TBY, TXB, TYB.

The designers of the 6809 threw up their hands, got rid of all of them and replaced them with a single transfer (TFR) instruction. The problem is that it takes up two bytes. While they were at it, they also added the similar exchange (EXG) instruction.


to be completely honest i just forgot to add 16 bit LD and ST instructions. i did now, thanks!
though naming is a bit weird, i just call them "LDW" and "STW".
as for modes, i was thinking of 3 modes for LDW (Immediate, Absolute, Zeropage) and 2 for STW (Absolute, Zeropage).

I made Swap Instructions in order to prevent having to add so many Transfer instructions.
also you forgot TXY and TYX.
that would be another 8 additional opcodes, would that really be a good thing?


Top
 Profile  
Reply with quote  
PostPosted: Sun May 03, 2020 3:45 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
oh sorry yes, ADD and SUB is a lot more than just two more opcodes!

There are so many different ways to slice this. The z80 has a couple of prefix bytes which hugely expand the number of available opcodes: if you use those for things which would otherwise have been rather cumbersome then they remain a big win.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 03, 2020 4:45 pm 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 746
Location: Germany
BigEd wrote:
oh sorry yes, ADD and SUB is a lot more than just two more opcodes!

There are so many different ways to slice this. The z80 has a couple of prefix bytes which hugely expand the number of available opcodes: if you use those for things which would otherwise have been rather cumbersome then they remain a big win.


i planned on keeping some opcodes free for exactly that reason (probably 0xFF).
i just don't want to put commonly used instructions in there or instructions that could be replaced by small snippets of code, as all instructions that use the prefix will always be 1 byte larger and take 1 cycle more to execute...

if i were to put any kind of ADD/SUB instructions in there, well what would be the point?
Code:
ADD #10

would take up the same amount of bytes and cylces as:
Code:
CLC
ADC #10


and Transfer instructions would only be a bit better...
this takes up 2 bytes and (if my theory is correct) take 2 cycles to execute:
Code:
TBX

while this takes up 3 bytes, and (again only in theory) takes 3 cycles to execute:
Code:
SAB
TAX
SAB

or you do this, which takes up 2 bytes (+1 stack byte) but (in theory) 4 cycles:
Code:
PHB
PLX


so overall i wouldn't really know what to put in the prefix-ed opcodes...
only ones that would make sense are the MUL and DIV instructions, since there are no short/fast replacement functions for them i can affort an additional byte and cycle.
plus it would free up 10 opcodes. (actually 9 if you subtract the 1 that is used as the prefix)


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

All times are UTC


Who is online

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