Page 7 of 24
Posted: Thu Feb 23, 2012 10:42 am
by Arlet
Opcodes for the B Accumulator are simple, not thought through at all.
For example, an LDA #$xxxx would look like $00A9, $xxxx in Hex Editor.
With a B Accumulator, a Macro/.BYTE on As65 using an LDB #$xxxx presently looks like $A9A9, $xxxx.
How about using $00A9 for LDA and $01A9 for LDB. That way you can use bit 8 as an override bit to switch from 'A' to 'B'. It's a small change, and it works seamlessly for any instruction currently using 'A', including LDA, STA, ASL A, PHA, TXA, or TAY. It is also easily extended to 'C' and 'D' accumulators by using an additional instruction bit.
Posted: Thu Feb 23, 2012 3:06 pm
by ElEctric_EyE
I think I follow you. So it should look something like this?:
Code: Select all
always @(posedge clk)
if( state == DECODE && RDY )
casex( IR[15:0] ) // decode all 16 bits
16'b0000_0000_1110_1000, // INX
16'b0000_0000_1100_1010, // DEX
16'b0000_0000_101x_xx10, // LDX, TAX, TSX
16'b0000_0001_101x_xx10: //TBX
dst_reg <= SEL_X;
16'b0000_0000_0x00_1000, // PHP, PHA
16'b0000_0000_1001_1010, // TXS
16'b0000_0001_0x00_1000: //PHB
dst_reg <= SEL_S;
16'b0000_0000_1x00_1000, // DEY, DEX
16'b0000_0000_101x_x100, // LDY
16'b0000_0000_1010_x000, // LDY #imm, TAY
16'b0000_0001_1010_x000: //TBY
dst_reg <= SEL_Y;
16'bxxxx_xxx1_xxxx_xxxx:
dst_reg <= SEL_B;
16'bxxxx_xxx0_xxxx_xxxx:
dst_reg <= SEL_A;
endcase
Posted: Thu Feb 23, 2012 3:23 pm
by Arlet
I think I follow you. So it should look something like this?:
Code: Select all
always @(posedge clk)
if( state == DECODE && RDY )
casex( IR[15:0] ) // decode all 16 bits
16'b0000_0000_1110_1000, // INX
16'b0000_0000_1100_1010, // DEX
16'b0000_0000_101x_xx10, // LDX, TAX, TSX
16'b0000_0001_101x_xx10: //TBX
dst_reg <= SEL_X;
16'b0000_0000_0x00_1000, // PHP, PHA
16'b0000_0000_1001_1010, // TXS
16'b0000_0001_0x00_1000: //PHB
dst_reg <= SEL_S;
16'b0000_0000_1x00_1000, // DEY, DEX
16'b0000_0000_101x_x100, // LDY
16'b0000_0000_1010_x000, // LDY #imm, TAY
16'b0000_0001_1010_x000: //TBY
dst_reg <= SEL_Y;
16'bxxxx_xxx1_xxxx_xxxx:
dst_reg <= SEL_B;
16'bxxxx_xxx0_xxxx_xxxx:
dst_reg <= SEL_A;
endcase
No, because now you have overlapping cases. For instance, the INX opcode now matches both SEL_X and SEL_A.
For SEL_X, SEL_Y, and SEL_S, bit 8 can be a don't care. So you could write something like this:
Code: Select all
always @(posedge clk)
if( state == DECODE && RDY )
casex( IR[15:0] ) // decode all 16 bits
16'b0000_000x_1110_1000, // INX
16'b0000_000x_1100_1010, // DEX
16'b0000_000x_101x_xx10, // LDX, TAX, TBX, TSX
dst_reg <= SEL_X;
And similarly for SEL_Y and SEL_S. For SEL_A/SEL_B, something like this:
Code: Select all
default: dst_reg <= IR[8] ? SEL_B : SEL_A;
Basically, whenever something doesn't apply to the accumulator, just put an 'x' instead of a '0' in bit 8 position. When it does apply to the accumulator, add in an extra mux for bit 8 to choose between A and B. ETA: instead of using the "? :" operator, you can also add extra cases, but then you'd have to list all opcode patterns matching the accumulator(s), without overlapping any of the X/Y/S based patters.
Posted: Thu Feb 23, 2012 7:51 pm
by ElEctric_EyE
Excellent! I believe it's working. I was able to see the B reg change value to the $00A5 I had in LDB #$xxA5. That's it. A very small Sim.
This is exciting to think of how many more opcodes just came to life! I have to wait until I get on a real computer to do some further testing because this laptop is agonizingly slow. Hopefully I can post an ISim tonight of a simple program:
Code: Select all
.CODE
.ORG $FFFFE000
LDBi .MACRO ;LDB #$xxxx
.BYTE $01A9
.ENDM
LDBa .MACRO ;LDB $xxxxxxxx
.BYTE $01AD
.ENDM
STBa .MACRO ;STB $xxxxxxxx
.BYTE $018D
.ENDM
DECBa .MACRO ;DECB $xxxxxxxx
.BYTE $01CE
.ENDM
CMPBi .MACRO ;CMPB #$xxxx
.BYTE $01C9
.ENDM
START LDBi
.BYTE $00A5 ;load $00A5 in B Accumulator
STBa
.WORD $00000400 ;store B Accumulator @$00000400
AA DECBa
.WORD $00000400 ;***I was confused here***, no need for a DECB, still DEC $00000040
LDBa
.WORD $00000400 ;load B Accumulator with value @$00000040
CMPBi
.BYTE $00A0 ;CMPBi #$00A0
BNE AA
RTS ;leads to BRK since no JSR
Posted: Fri Feb 24, 2012 2:29 am
by ElEctric_EyE
This is awesome. It is working! I/we have a B Accumulator!
Will post a Sim soon after I get a better program than above to display proof of opcode recognition within the core. But the program above worked as expected on ISim... I would just like to include most if not all of the opcodes that use the Accumulator in a short cycle program.
Now, an observation about this line of code (which does work by the way):
Code: Select all
default: dst_reg <= IR[8] ? SEL_B : SEL_A;
After I got home from work tonight, I had to go read my 'Digital Design Using Digilent FPGA Boards (Verilog Edition)' by Haskell and Hanna and see how they implemented a 2 to 1 MUX, a very basic building block one
must know the syntax of, obviously I do not. But I want to learn...
I saw the very same syntax as above, on pg.69. In their example, the expression was:
which reads: 'if
s is true (logical 1) then y=b, else y=a.
Now I will quote them regarding this syntax: "This shortcut method of writing an
if statement was inherited from the programming language C but its use should be discouraged because it is more difficult to understand than writing out the
if statement as in Listing 5.3"
Listing 5.3 goes something like this:
Code: Select all
...
always @(*)
if (s == 0)
y = a;
else
y = b;
endmodule
But, can we put an IF statement after a Default?
__________________________________________________________________________________________________________________________
The 2:1 MUX is good for IR[8] to choose SEL_A or SEL_B.
Now, going forward to the C and D Accumulators in addition to the A and B Accumulators, we will need a 4:1 MUX to put the DCBAXYS regsel data into the src_reg or dst_reg. I might be tempted to write something like this:
Code: Select all
default: dst_reg <= IR[9:8] ? SEL_D : SEL_C : SEL_B : SEL_A;
or this:
Code: Select all
default: dst_reg <= IR[9:8] ?? SEL_D : SEL_C : SEL_B : SEL_A;
but it seems this is not the proper syntax...
Posted: Fri Feb 24, 2012 6:44 am
by teamtempest
Posted: Thu Feb 23, 2012 8:29 pm Post subject:
but it seems this is not the proper syntax...
I doubt it. IMO it's the difficulty of extending the relatively simple:
Code: Select all
(cond_expr) ? (true_expr) : (false_expr)
to more deeply nested cases that prompts so much advice to avoid it altogether. And it
is hard to push it further and still be understandable (to humans, anyway).
Anyway, what you seem to be after is a four-way branch based on two conditions. I think it parses this way:
Code: Select all
(cond_expr1) ? ((cond_expr2) ? (t1_t2) : (t1_f2)) : ((cond_expr2) ? ((f1_t2) : (f1_f2))
I don't know if that's the syntax your tool requires (or even allows), but it's pretty straightforward to decode if you look at it as simply using a nested ternary expression for both the 'true' and 'false' branch expressions of the nesting ternary expression.
You can go even further, in the sense that it won't confuse a competent parser to do this to any depth, but it's generally a lot easier for humans to write now and read later to set anything beyond the simplest case use out as multi-way IF/ELSE branches.
Posted: Fri Feb 24, 2012 8:08 am
by Arlet
Now I will quote them regarding this syntax: "This shortcut method of writing an
if statement was inherited from the programming language C but its use should be discouraged because it is more difficult to understand than writing out the
if statement as in Listing 5.3"
Listing 5.3 goes something like this:
Code: Select all
...
always @(*)
if (s == 0)
y = a;
else
y = b;
endmodule
It's a matter of taste. For short expressions, I find the ?: operator easy enough to read, but as the expression gets more complicated, I usually switch to other methods. If you prefer the if/else, you could use that instead.
Now, going forward to the C and D Accumulators in addition to the A and B Accumulators, we will need a 4:1 MUX to put the DCBAXYS regsel data into the src_reg or dst_reg. I might be tempted to write something like this:
There are several approaches. You can continue using the ?: operator in the following way, which is still fairly readable.
Code: Select all
default: dst_reg <= IR[9:8] == 2'b11 ? SEL_D :
IR[9:8] == 2'b10 ? SEL_C :
IR[9:8] == 2'b01 ? SEL_B :
SEL_A;
You could also write a 2nd case statement inside the default:
Code: Select all
default: case( IR[9:8] )
2'b00: dst_reg <= SEL_A;
2'b01: dst_reg <= SEL_B;
2'b10: dst_reg <= SEL_C;
2'b11: dst_reg <= SEL_D;
endcase
And if you like to be a bit clever, you can also pick special bit patterns for the 'SEL_*' constants. Suppose SEL_A = 4'b1000, and SEL_B = 4'b1001, etc. Then you could write:
Code: Select all
default: dst_reg <= { 2'b10, IR[9:8] };
Posted: Fri Feb 24, 2012 11:00 pm
by ElEctric_EyE
I'm learning alot, thanks for sharing that info about MUX's!
It's all about the syntax. I had tried to come up with a way to do a default: case, but my syntax was way off! I do prefer that method.
So today I finished off adding the 2 other accumulators. I did a Sim on the short listing below and it worked.
My last
immediate goal as far as adding things, is to add a Z index. Before that I think I should see if the core can still run @100MHz. I'll do that when I get home, and get off this sloth machine!
Code: Select all
START LDA #$A5
TAY
TYB
TYC
TYD
CLC
ADC #$0001 ;Add #$01 to A accumulator
ADCBi
.BYTE $0002 ;Add #$02 to B accumulator
ADCCi
.BYTE $0003 ;Add #$03 to C accumulator
ADCDi
.BYTE $0004 ;Add #$04 to D accumulator
Posted: Sat Feb 25, 2012 1:55 am
by ElEctric_EyE
The new core, with 4 Accumulators, did not pass a 10.0ns O2In constraint...
However, it did pass a 10.5ns constraint! for a max of 99.48MHz.
EDIT: 10.5ns not 9.5ns.
Posted: Sat Feb 25, 2012 7:18 am
by Arlet
Did you convert all instructions to work with any of the 4 accumulators where it previously only had A ?
I think a useful next step would be to add accumulator-accumulator transfer instructions, such as TAC, and TDB. This requires adding some opcodes too.
Posted: Sat Feb 25, 2012 2:13 pm
by ElEctric_EyE
Did you convert all instructions to work with any of the 4 accumulators where it previously only had A ?
Yes. All the states related to A were changed in the Microcode state machine. So all addressing modes, etc. should work with B, C, & D Accumulators.
...I think a useful next step would be to add accumulator-accumulator transfer instructions, such as TAC, and TDB. This requires adding some opcodes too.
I agree. I think I see how to do that.
Posted: Sat Feb 25, 2012 2:42 pm
by Arlet
An interesting option is to allocate 2 different bits in the opcode space, say, bits 11-10, for the src_reg indexing, and bits 9-8 for dst_reg.
That way, you can do all kinds of interesting stuff like ADC B, A, #10, where an ADC operation is performed on A, and the result is stored in B.
Posted: Sat Feb 25, 2012 9:53 pm
by ElEctric_EyE
That is what I would like to do with a 16x16 multiply opcode.
I recently read on Xilinx forums
someone posed a question about how to infer the DSP48A1 slices which hold these multipliers. There was a link there point to a bunch of multiplier examples. Still I need to finish the transfer opcodes and the Z register, then recheck top speed... Busy at work today, so unfortunately no progress on the core.
Posted: Sun Feb 26, 2012 3:26 pm
by BigEd
Interesting developments!
It might be worth casting an eye over John West's design of the opcode encodings for 65020 (which is purely a paper design.) The machine isn't what we have - different register sizes for a start - but the encodings are quite interesting and they fit into a 16-bit opcode space, as an extension to a 6502 base.
http://www.ucc.gu.uwa.edu.au/~john/65020.html
http://www.ucc.gu.uwa.edu.au/~john/6502 ... tions.html
By flipping a few of his definitions (make the P bit the opposite value for a start) you might get something you could implement piece by piece.
Cheers
Ed
Posted: Sun Feb 26, 2012 7:16 pm
by fachat
Do you know how old this design is? There is no date on the page
André