Last visit was: Mon Dec 09, 2024 7:48 am
|
It is currently Mon Dec 09, 2024 7:48 am
|
One Page Computing - roll your own challenge
Author |
Message |
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1807
|
I'm not sure what you're seeing or why - perhaps you could show one or two worked examples? Have you tried running the python emulator, or the javascript one? I think you see enough there to see what's going on.
|
Wed Sep 26, 2018 8:00 pm |
|
|
quadrant
Joined: Sat Jun 16, 2018 2:51 am Posts: 50
|
I get this: I'm trying to figure out how the architecture works from the verilog code... In the python emulator, the line of code is still the same... Code: if (bool(pinvert) ^ bool(((pcarry or c) and (pzero or z)))):
You do not have the required permissions to view the files attached to this post.
|
Wed Sep 26, 2018 9:27 pm |
|
|
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1807
|
Hmm - have you noticed there's pcarry, which controls whether the predicate as a whole is sensitive to c, and pzero, which controls whether the predicate is sensitive to z? In the originally quoted table, "Carry pred" refers to the value of pcarry, and same for zero. That is, the columns are the value of the predicate control bit, not the cpu status bit.
As ever, there might be ways to improve the doc.
For the casual onlooker, the idea is that we can do a unconditional operation such as ld, or one only when z is set, with ld.z, or only when z is clear, with ld.nz, and so on. There's the always condition, the nop condition, and six others, which turns out to be quite powerful and flexible. More importantly for one-page computing, it's quite simple.
(We had another goal, of small implementation size, so simple in the implementation is good too.)
In later revisions of the architecture, we could take the 'nop' case and reuse it as an opcode bit, which means we get to double the operation count, with half of them predicated and half of them not.
|
Wed Sep 26, 2018 9:39 pm |
|
|
quadrant
Joined: Sat Jun 16, 2018 2:51 am Posts: 50
|
Ah I see. I was unaware of the instruction variation. So, suppose you have instruction ld.z. pred_zero would be 1, pred_invert would be 0, and pred_carry would be 0. How will the predicate signal ever be high/true for the ld.z instruction? If, Code: predicate = pred_invert xor ( (pred_carry or flag_carry) and (pred_zero or flag_zero) ) Then the only way it can evaluate to true is if flag_carry is 1 ... Thanks a lot for you time and patience!
|
Thu Sep 27, 2018 6:08 pm |
|
|
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1807
|
For whatever subtle reason, it seems the pred bits are negative logic, so for a ld.z you'd have pred_zero as 0, pred_carry as 1, and pred_invert as 0. I think that should work out. Of course, at assembly level you don't worry about this. But of course the verilog, the assembler, the emulators, the monitor do all need to do it. (For at least some of these CPUs, we wrote (hoglet wrote) a single-stepping disassembling monitor which runs on the CPU, and has to understand enough to disassemble and single step. It was all rather interesting! See here https://github.com/hoglet67/opc/blob/ma ... /monitor.sand https://github.com/hoglet67/opc/tree/master/include)
|
Thu Sep 27, 2018 9:01 pm |
|
|
quadrant
Joined: Sat Jun 16, 2018 2:51 am Posts: 50
|
Ah ok! Thanks! I'll explore the programs as well =)
|
Thu Sep 27, 2018 10:54 pm |
|
|
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1807
|
There are some arithmetic libraries too - see the 'syslib' files in https://github.com/revaldinho/opc/tree/master/bcpl
|
Fri Sep 28, 2018 7:40 am |
|
|
quadrant
Joined: Sat Jun 16, 2018 2:51 am Posts: 50
|
Hi folks!
I've created a schematic for OPC-6. A few signals have been renamed for readability. Let me know if you spot any errors or omissions and I will update accordingly.
Note: This schematic will not pass KiCad's electrical rule check. I've omitted the required bus signal labels in favor of readability.
You do not have the required permissions to view the files attached to this post.
Last edited by quadrant on Sat Oct 27, 2018 1:53 am, edited 1 time in total.
|
Sat Oct 27, 2018 1:49 am |
|
|
quadrant
Joined: Sat Jun 16, 2018 2:51 am Posts: 50
|
I have a few lingering questions about OPC-6: 1) Clarification on the concept of "one word instructions" and their relation to the FSM? From the source code: Code: wire [15:0] operand = (IR_q[IRLEN]||IR_q[IRLD]||(op==INC)||(op==DEC)||(IR_q[IRWBK]))?OR_q:RF_w_p2; // One word instructions operand usu comes from RF
2) What is the purpose of each of the predicate variations ( pred_d, pred_din, pred_q)? 3) I noticed in the emulator you only check for software interrupts. If you were to emulate hardware interrupts, what approach would you take?
|
Sat Oct 27, 2018 1:53 am |
|
|
Revaldinho
Joined: Tue Apr 25, 2017 7:33 pm Posts: 32
|
quadrant wrote: I have a few lingering questions about OPC-6: 1) Clarification on the concept of "one word instructions" and their relation to the FSM? From the source code: Code: wire [15:0] operand = (IR_q[IRLEN]||IR_q[IRLD]||(op==INC)||(op==DEC)||(IR_q[IRWBK]))?OR_q:RF_w_p2; // One word instructions operand usu comes from RF
From the OPC6 Spec: All memory accesses are 16 bits wide and instructions are encoded in either one or two words :: Code: ppp l oooo ssss dddd nnnnnnnnnnnnnnnn \ \ \ \ \ \_______ 16b optional operand word \ \ \ \___\__________________ 4b source and destination registers \ \___\__________________________ 1b instruction length + 4b opcode \________________________________ 3b predicate bits A one word instruction requires only a single FETCH cycle, and so the operand will usually be taken from the register file unless it's a very short immediate. A two word instruction requires a second FETCH to get the 16bit operand These states are labelled FET0 and FET1 in the Verilog state machine, with FET1 usually being skipped for the majority of instructions. Quote: 2) What is the purpose of each of the predicate variations (pred_d, pred_din, pred_q)?
Even though it's single page of code, OPC6 does have a short pipeline and the EXEC stage on one instruction overlaps with the FETCH of the next instruction to improve performance. Consider instructions to be executed in sequence, A:B:C 1. If C is a single word instruction that is to be executed based on the flag states produced by A, then we need to know what condition needs to be satisfied (the predicate) and what is the status of the flags. This needs to be determined at the end of the fetch (FET0) for C, because we are deciding whether or not to EXECute C or just skip straight to the next instruction fetch. However, during FET0 for C, the predicate bits have not yet been latched into the Instruction Register, so the computation uses the predicate bits as they are currently on the databus vs the stable flag bits in the status register. This is labelled pred_din. 2. If C were a two word instruction, the we must complete the second fetch (FET1) for C whether or not the instruction is to be executed. In this case we need to check predicates against flag states at the end of the FET1 cycle. The flags (from instruction A) are still stable and in the status register, but now the predicate bits are no longer on the data bus which is holding the 16b operand instead. The predicate bits however have been latched into the Instruction Register now at the end of FET0. So, we need to compare the predicate bits in the IR this time then vs the stable flag bits in the status register. This is labelled pred_q. 3. Finally if C were a single word instruction and were conditional on the status of the flags at the end of B then we have a slight problem. Execution of B overlaps with the fetch of C, so that at the end of FET0 for instruction C, the flags have not yet been written into the status register by B. So, just as in the first case the predicate bits are on the data bus for C, but now we need to compare these against the yet-to-be-written flags which have just been computed in instruction B. ie we are comparing predicates against the flag data on the 'd' side of the status register rather than the 'q' side. This is labelled pred_d. Quote: 3) I noticed in the emulator you only check for software interrupts. If you were to emulate hardware interrupts, what approach would you take? This would just need a slightly larger emulator modelling more of a system than just the CPU and memory. Probably checking for a hardware interrupt at the start of every cycle would be adequate, and pseudo-randomly firing the interrupt during specific tests to log the results. R.
Last edited by Revaldinho on Tue Nov 06, 2018 10:38 pm, edited 1 time in total.
|
Sun Oct 28, 2018 3:57 pm |
|
|
quadrant
Joined: Sat Jun 16, 2018 2:51 am Posts: 50
|
I see, thanks for the explanation!
|
Mon Oct 29, 2018 6:02 pm |
|
|
quadrant
Joined: Sat Jun 16, 2018 2:51 am Posts: 50
|
How does the assembler for OPC-6 handle padding? For example consider the following code: Code: GROUP0: BYTE 0xAA GROUP1: BYTE 0x11, 0x22 Is a byte of zero inserted after the byte 0xAA to make GROUP0 equal to a multiple of 16? Thus the programmer has to keep this in mind to avoid unexpected bytes?
|
Tue Mar 19, 2019 11:06 pm |
|
|
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1807
|
At a guess, as it's a word-oriented machine, all values in the assembly source will be interpreted as words. There are no bytes, unless you say it has 16-bit bytes - which amounts to the same thing.
|
Wed Mar 20, 2019 8:02 am |
|
|
Revaldinho
Joined: Tue Apr 25, 2017 7:33 pm Posts: 32
|
quadrant wrote: How does the assembler for OPC-6 handle padding? For example consider the following code: Code: GROUP0: BYTE 0xAA GROUP1: BYTE 0x11, 0x22 Is a byte of zero inserted after the byte 0xAA to make GROUP0 equal to a multiple of 16? Thus the programmer has to keep this in mind to avoid unexpected bytes? I think this is easily shown with an example Code: python opc6asm.py test.as test.hex 0000 0001 GLOBAL1: BYTE 0x01 0001 0201 GLOBAL2: BYTE 0x01, 0x02 0002 0201 0003 GLOBAL3: BYTE 0x01, 0x02, 0x03 0004 0201 0403 GLOBAL4: BYTE 0x01, 0x02, 0x03, 0x04
As Ed says, it's a word oriented machine but bytes can be handy use so the assembler processes BYTE statements line by line, packs two bytes to a word and pads out any odd number with a 0 byte.
|
Wed Mar 20, 2019 9:01 am |
|
|
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1807
|
Ah, thanks - a worked example is worth a thousand guesses. So, I think we can say that the OPC-6 doesn't know about bytes, but the assembler - this particular assembler - does, and is little-endian too. I think we hooked up 8-bit ports to the low end of the word. And we do read and interpret srecords, I think, and had to decide how to handle a bytestream. I expect that was a little-endian approach too.
|
Wed Mar 20, 2019 1:44 pm |
|
Who is online |
Users browsing this forum: CCBot and 0 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
|
|