Any brainiacs willing to better comment P1V code for us mere mortals?
So I tried prepping myself a bit before checking out the P1V code by reading some verilog tutorials. I'd be lying if I said I understood it all and was ready to go, but I figured I could at least start peeking at the code and do a bit of research when something wasn't clear. It didn't take more than a couple of lines into cog.v to be completely lost by nothing more than many of the names used for "constants" (inputs/outputs/parameters). Of course, I also don't know what things like 'ena' (enable?) and 'ena_bus', etc. etc. are supposed to be for. Maybe it's just my noobishness, but to me it doesn't appear to be for the faint of heart. If this code makes sense to anyone, I sincerely hope they would be willing to comment the code better (no rush! Just would appreciate if someone would undertake it!). Any takers?
-Mark

Comments
Great! I hope you'll share your progress every now and then
P8X32A_Emulation top.??? │ ┌───────────┴─────────────────────┐ │ │ dig.v ??? │ ┌───────────┴─────────────────────┐ │ │ cog.v hub.v │ │ ┌──────────┬─────┴────┬──────────┐ │ │ │ │ │ │ cog_alu.v cog_ctr.v cog_vid.v cog_ram.v hub_mem.vPerhaps someone with an understanding of Quartus/FPGA can update the drawing?This is what I gathered as well. I'm guessing any top file would be FPGA specific. I don't currently have one, I was just browsing the code with Scriptum.
Re: Hub "API"
Here are the ones that needed some more explanation.
ena_bus -- high on every other clock, makes the hub run half the speed of the cogs
r -- high when cog is loading program, turns on ROM descrambling
s -- selects byte/word/long
c -- carry
bus_ack -- acknowledge back to cog that hub request completed
cog_ena -- 8 lines, each cog gets one, enables the cog if high
ptr_w -- write PAR during COGINIT
ptr_d -- data for writing PAR during COGINIT
cfg -- control bits set by CLKSET
http://forums.parallax.com/showthread.php/157051-Hub-quot-API-quot
Note: The forum has not expanded tab stops correctly. I view the source file with Notepad++.
// cog /* ------------------------------------------------------------------------------- Copyright 2014 Parallax Inc. This file is part of the hardware description for the Propeller 1 Design. The Propeller 1 Design is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The Propeller 1 Design is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the Propeller 1 Design. If not, see <[URL]http://www.gnu.org/licenses/[/URL]>. ------------------------------------------------------------------------------- */ // RR20140823 Comments by Cluso99 /* ADD instruction mnem oper R C Z +- C D S ---------------------------------------------------------------------------- 000000 ZC0ICCCC DDDDDDDDD SSSSSSSSS WRBYTE D,S _______ __________ 000000 ZC1ICCCC DDDDDDDDD SSSSSSSSS RDBYTE D,S B______ __________ 000001 ZC0ICCCC DDDDDDDDD SSSSSSSSS WRWORD D,S _______ __________ 000001 ZC1ICCCC DDDDDDDDD SSSSSSSSS RDWORD D,S B______ __________ 000010 ZC0ICCCC DDDDDDDDD SSSSSSSSS WRLONG D,S _______ __________ 000010 ZC1ICCCC DDDDDDDDD SSSSSSSSS RDLONG D,S B______ __________ 000011 ZCRICCCC DDDDDDDDD SSSSSSSSS SYSOP D,S B__B___ __________ 000100 ZCRICCCC DDDDDDDDD SSSSSSSSS * <MUL> D,S M__M__Z __________ 000101 ZCRICCCC DDDDDDDDD SSSSSSSSS * <MULS> D,S M__M__Z __________ 000110 ZCRICCCC DDDDDDDDD SSSSSSSSS * <ENC> D,S E_____Z __________ 000111 ZCRICCCC DDDDDDDDD SSSSSSSSS * <ONES> D,S E_____Z __________ 001000 ZCRICCCC DDDDDDDDD SSSSSSSSS ROR D,S R__R__Z __________ 001001 ZCRICCCC DDDDDDDDD SSSSSSSSS ROL D,S R__R__Z __________ 001010 ZCRICCCC DDDDDDDDD SSSSSSSSS SHR D,S R__R__Z __________ 001011 ZCRICCCC DDDDDDDDD SSSSSSSSS SHL D,S R__R__Z __________ 001100 ZCRICCCC DDDDDDDDD SSSSSSSSS RCR D,S R__R__Z __________ 001101 ZCRICCCC DDDDDDDDD SSSSSSSSS RCL D,S R__R__Z __________ 001110 ZCRICCCC DDDDDDDDD SSSSSSSSS SAR D,S R__R__Z __________ 001111 ZCRICCCC DDDDDDDDD SSSSSSSSS REV D,S R__R__Z __________ 010000 ZCRICCCC DDDDDDDDD SSSSSSSSS MINS D,S L__As_Z 1__0__1__1 010001 ZCRICCCC DDDDDDDDD SSSSSSSSS MAXS D,S L__As_Z 1__0__1__1 010010 ZCRICCCC DDDDDDDDD SSSSSSSSS MIN D,S L__Au_Z 1__0__1__1 010011 ZCRICCCC DDDDDDDDD SSSSSSSSS MAX D,S L__Au_Z 1__0__1__1 010100 ZCRICCCC DDDDDDDDD SSSSSSSSS MOVS D,S L______ __________ 010101 ZCRICCCC DDDDDDDDD SSSSSSSSS MOVD D,S L______ __________ 010110 ZCRICCCC DDDDDDDDD SSSSSSSSS MOVI D,S L______ __________ 010111 ZCRICCCC DDDDDDDDD SSSSSSSSS JMPRET D,S L______ __________ 011000 ZCRICCCC DDDDDDDDD SSSSSSSSS AND D,S L__L__Z __________ 011001 ZCRICCCC DDDDDDDDD SSSSSSSSS ANDN D,S L__L__Z __________ 011010 ZCRICCCC DDDDDDDDD SSSSSSSSS OR D,S L__L__Z __________ 011011 ZCRICCCC DDDDDDDDD SSSSSSSSS XOR D,S L__L__Z __________ 011100 ZCRICCCC DDDDDDDDD SSSSSSSSS MUXC D,S L__L__Z __________ 011101 ZCRICCCC DDDDDDDDD SSSSSSSSS MUXNC D,S L__L__Z __________ 011110 ZCRICCCC DDDDDDDDD SSSSSSSSS MUXZ D,S L__L__Z __________ 011111 ZCRICCCC DDDDDDDDD SSSSSSSSS MUXNZ D,S L__L__Z __________ 100000 ZCRICCCC DDDDDDDDD SSSSSSSSS ADD D,S A__Au_Z 0__0__1__1 100001 ZCRICCCC DDDDDDDDD SSSSSSSSS SUB D,S A__Au_Z 1__0__1__1 100010 ZCRICCCC DDDDDDDDD SSSSSSSSS ADDABS D,S A__Au_Z M__0__1__1 100011 ZCRICCCC DDDDDDDDD SSSSSSSSS SUBABS D,S A__Au_Z Mn_0__1__1 100100 ZCRICCCC DDDDDDDDD SSSSSSSSS SUMC D,S A__Ao_Z C__0__1__1 100101 ZCRICCCC DDDDDDDDD SSSSSSSSS SUMNC D,S A__Ao_Z Cn_0__1__1 100110 ZCRICCCC DDDDDDDDD SSSSSSSSS SUMZ D,S A__Ao_Z Z__0__1__1 100111 ZCRICCCC DDDDDDDDD SSSSSSSSS SUMNZ D,S A__Ao_Z Zn_0__1__1 101000 ZCRICCCC DDDDDDDDD SSSSSSSSS MOV D,S A__Am_Z 0__0__0__1 101001 ZCRICCCC DDDDDDDDD SSSSSSSSS NEG D,S A__Am_Z 1__0__0__1 101010 ZCRICCCC DDDDDDDDD SSSSSSSSS ABS D,S A__Am_Z M__0__0__1 101011 ZCRICCCC DDDDDDDDD SSSSSSSSS ABSNEG D,S A__Am_Z Mn_0__0__1 101100 ZCRICCCC DDDDDDDDD SSSSSSSSS NEGC D,S A__Am_Z C__0__0__1 101101 ZCRICCCC DDDDDDDDD SSSSSSSSS NEGNC D,S A__Am_Z Cn_0__0__1 101110 ZCRICCCC DDDDDDDDD SSSSSSSSS NEGZ D,S A__Am_Z Z__0__0__1 101111 ZCRICCCC DDDDDDDDD SSSSSSSSS NEGNZ D,S A__Am_Z Zn_0__0__1 110000 ZCRICCCC DDDDDDDDD SSSSSSSSS CMPS D,S A__As_Z 1__0__1__1 110001 ZCRICCCC DDDDDDDDD SSSSSSSSS CMPSX D,S A__As_Z& 1__C__1__1 110010 ZCRICCCC DDDDDDDDD SSSSSSSSS ADDX D,S A__Au_Z& 0__C__1__1 110011 ZCRICCCC DDDDDDDDD SSSSSSSSS SUBX D,S A__Au_Z& 1__C__1__1 110100 ZCRICCCC DDDDDDDDD SSSSSSSSS ADDS D,S A__Ao_Z 0__0__1__1 110101 ZCRICCCC DDDDDDDDD SSSSSSSSS SUBS D,S A__Ao_Z 1__0__1__1 110110 ZCRICCCC DDDDDDDDD SSSSSSSSS ADDSX D,S A__Ao_Z& 0__C__1__1 110111 ZCRICCCC DDDDDDDDD SSSSSSSSS SUBSX D,S A__Ao_Z& 1__C__1__1 111000 ZCRICCCC DDDDDDDDD SSSSSSSSS CMPSUB D,S A__Ac_Z 1__0__1__1 111001 ZCRICCCC DDDDDDDDD SSSSSSSSS DJNZ D,S A__Au_Z 1__1__1__0 111010 ZCRICCCC DDDDDDDDD SSSSSSSSS TJNZ D,S A__Au_Z 1__0__1__0 111011 ZCRICCCC DDDDDDDDD SSSSSSSSS TJZ D,S A__Au_Z 1__0__1__0 111100 ZCRICCCC DDDDDDDDD SSSSSSSSS WAITPEQ D,S _______ __________ 111101 ZCRICCCC DDDDDDDDD SSSSSSSSS WAITPNE D,S _______ __________ 111110 ZCRICCCC DDDDDDDDD SSSSSSSSS WAITCNT D,S A__Au_Z 0__0__1__1 111111 ZCRICCCC DDDDDDDDD SSSSSSSSS WAITVID D,S _______ __________ ---------------------------------------------------------------------------- * future instructions ZCR effects ---------------------------------------------------------------------------- 000 nz, nc, nr 001 nz, nc, r 010 nz, c, nr 011 nz, c, r 100 z, nc, nr 101 z, nc, r 110 z, c, nr 111 z, c, r CCCC condition (easier-to-read list) ---------------------------------------------------------------------------- 0000 never 1111 always (default) 0001 nc & nz 1100 if_c if_b 0010 nc & z 0011 if_nc if_ae 0011 nc 1010 if_z if_e 0100 c & nz 0101 if_nz if_ne 0101 nz 1000 if_c_and_z if_z_and_c 0110 c <> z 0100 if_c_and_nz if_nz_and_c 0111 nc | nz 0010 if_nc_and_z if_z_and_nc 1000 c & z 0001 if_nc_and_nz if_nz_and_nc if_a 1001 c = z 1110 if_c_or_z if_z_or_c if_be 1010 z 1101 if_c_or_nz if_nz_or_c 1011 nc | z 1011 if_nc_or_z if_z_or_nc 1100 c 0111 if_nc_or_nz if_nz_or_nc 1101 c | nz 1001 if_c_eq_z if_z_eq_c 1110 c | z 0110 if_c_ne_z if_z_ne_c 1111 always 0000 never I SSSSSSSSS source operand ---------------------------------------------------------------------------- 0 SSSSSSSSS register 1 #SSSSSSSSS immediate, zero-extended DDDDDDDDD destination operand ---------------------------------------------------------------------------- DDDDDDDDD register */ `include "cog_ram.v" `include "cog_alu.v" `include "cog_ctr.v" `include "cog_vid.v" module cog ( input nres, // reset input clk_pll, // clocks input clk_cog, input ena_bus, input ptr_w, // pointers input [27:0] ptr_d, input ena, // control input bus_sel, // bus output bus_r, output bus_e, output bus_w, output [1:0] bus_s, output [15:0] bus_a, output [31:0] bus_d, input [31:0] bus_q, input bus_c, input bus_ack, input [31:0] cnt, // counter input [7:0] pll_in, // pll's output pll_out, input [31:0] pin_in, // pins output [31:0] pin_out, output [31:0] pin_dir ); // The following are used for location of the bits in an instruction... parameter oh = 31; // \ iiiiii (instruction bits) location - bits[31:26] parameter ol = 26; // / parameter wz = 25; // WZ bit location parameter wc = 24; // WC bit location parameter wr = 23; // NR bit location parameter im = 22; // I bit location parameter ch = 21; // \ cccc (conditional execution bits) location [21:18] parameter cl = 18; // / parameter dh = 17; // \ ddddddddd (destination bits) location [17:9] parameter dl = 9; // / parameter sh = 8; // \ sssssssss (source bits) location [8:0] parameter sl = 0; // / // pointers reg [27:0] ptr; always @(posedge clk_cog or negedge nres) if (!nres) ptr <= 28'b00000000000000_11111000000000; // used to force a cog start/boot else if (ena_bus && ptr_w) ptr <= ptr_d; // when running // load/run reg run; always @(posedge clk_cog or negedge ena) if (!ena) run <= 1'b0; // when cog is idle, run=0 else if (m[3] && (&px)) run <= 1'b1; // when cog is running, run=1 // state // When running, the cog can be in 5 states, represented by m[4:0] // These relate to the 6 clocks of an instruction. Due to overlapping instructions, the instructions effectively use 4 clocks. // I d S D e R <---- first instruction // I d S D e R <---- next instruction // I d S D e R <---- next instruction // where I = instruction fetch (executes previous instruction) // d = decode instruction (write previous instructions Result) // S = fetch source (unless immediate) // D = fetch destination // e = execute instruction (fetch next instruction) // R = write result (decode next instruction) // // below m[0] = S // m[1] = D // m[2] = I // m[3] = R // m[4] = wait (if a wait state needs to be inserted due to a WAITxxx instruction (or wait for hub slot???) reg [4:0] m; always @(posedge clk_cog or negedge ena) if (!ena) m <= 5'b0; else m <= { (m[2] || m[4]) && waiti, // m[4] = wait (m[2] || m[4]) && !waiti, // m[3] = write d m[1], // m[2] = read next instruction m[0], // m[1] = read d !m[4] && !m[2] && !m[1] && !m[0] }; // m[0] = read s // process reg [8:0] p; // PC program counter reg c; // C (carry) flag reg z; // Z (zero) flag always @(posedge clk_cog or negedge ena) if (!ena) p <= 1'b0; // cog not running, so PC=0 else if (m[3] && !(cond && jump_cancel)) p <= px + 1'b1; // PC = px + 1 (increment PC) always @(posedge clk_cog or negedge ena) if (!ena) c <= 1'b0; // cog not running, so C=0 else if (m[3] && cond && i[wc]) c <= alu_co; // update C flag always @(posedge clk_cog or negedge ena) if (!ena) z <= 1'b0; // cog not running, so Z=0 else if (m[3] && cond && i[wz]) z <= alu_zo; // update Z flag // addressable registers // // addr read write // ------------------------ // // 000-1EF RAM RAM // // 1F0 PAR RAM // 1F1 CNT RAM // 1F2 INA RAM // 1F3 INB * RAM // 1F4 RAM RAM+OUTA // 1F5 RAM RAM+OUTB * // 1F6 RAM RAM+DIRA // 1F7 RAM RAM+DIRB * // 1F8 RAM RAM+CTRA // 1F9 RAM RAM+CTRB // 1FA RAM RAM+FRQA // 1FB RAM RAM+FRQB // 1FC PHSA RAM+PHSA // 1FD PHSB RAM+PHSB // 1FE RAM RAM+VCFG // 1FF RAM RAM+VSCL // // * future 64-pin version // Set wio if: state m[3] & conditions met & WR(write result) & D = $1Fx (destination is special register) wire wio = m[3] && cond && i[wr] && (&i[dh:dl+4]); // Set one of the following if wio, according to D[3:0] (D is $1Fx, so set according to x) wire setouta = wio && i[dl+3:dl] == 4'h4; wire setdira = wio && i[dl+3:dl] == 4'h6; wire setctra = wio && i[dl+3:dl] == 4'h8; wire setctrb = wio && i[dl+3:dl] == 4'h9; wire setfrqa = wio && i[dl+3:dl] == 4'hA; wire setfrqb = wio && i[dl+3:dl] == 4'hB; wire setphsa = wio && i[dl+3:dl] == 4'hC; wire setphsb = wio && i[dl+3:dl] == 4'hD; wire setvid = wio && i[dl+3:dl] == 4'hE; wire setscl = wio && i[dl+3:dl] == 4'hF; // register ram // ram will be enabled for: m[0], m[1], m[2] , m[3] if condition met and write result wire ram_ena = m[0] || m[1] || m[2] || m[3] && cond && i[wr]; wire ram_w = m[3] && alu_wr; // ram write if: m[3] and ALU write result wire [8:0] ram_a = m[2] ? px // set the ram address to: PC if state m[2] (instruction fetch) : m[0] ? i[sh:sl] // Source address if state m[0] : i[dh:dl]; // otherwise destination address wire [31:0] ram_q; // set the result of a ram read // instantiate the cog ram by calling the module cog_ram in cog_ram.v // sets the parameters in cog_ram cog_ram cog_ram_ ( .clk (clk_cog), // clock .ena (ram_ena), // ram enable .w (ram_w), // ram write .a (ram_a), // ram address .d (alu_r), // ram value to be written (32 bits) ie ALU Result .q (ram_q) ); // ram value read // outa/dira The OUTA and DIRA registers are AND'ed together and then OR'ed with all other Cogs' values and then to the physical OUTA pins. reg [31:0] outa; // OUTA register reg [31:0] dira; // DIRA register always @(posedge clk_cog) if (setouta) outa <= alu_r; // if "setouta" was set above, copy the contents of the ALU Result to OUTA register always @(posedge clk_cog) if (setdira) dira <= alu_r; // if "setdira" was set above, copy the contents of the ALU Result to DIRA register // ctra/ctrb // The following are for the counters A and B. wire [32:0] phsa; // current PHSA value wire [31:0] ctra_pin_out; // CTRA output wire plla; cog_ctr cog_ctra ( .clk_cog (clk_cog), // system clock .clk_pll (clk_pll), // PLL clock .ena (ena), // counter enabled .setctr (setctra), // setctra signal (ie write to CTRA) .setfrq (setfrqa), // setfrqa signal (ie write to FRQA) .setphs (setphsa), // setphsa signal (ie write to PHSA) .data (alu_r), // data (32 bits) input .pin_in (pin_in), // .phs (phsa), // PHSA output value .pin_out (ctra_pin_out), // .pll (plla) ); // PLLA output register/value wire [32:0] phsb; wire [31:0] ctrb_pin_out; wire pllb; cog_ctr cog_ctrb ( .clk_cog (clk_cog), .clk_pll (clk_pll), .ena (ena), .setctr (setctrb), .setfrq (setfrqb), .setphs (setphsb), .data (alu_r), .pin_in (pin_in), .phs (phsb), .pin_out (ctrb_pin_out), .pll (pllb) ); assign pll_out = plla; // vid // The following are for the Video: wire vidack; // video ack (signals end of WAITVID ???) wire [31:0] vid_pin_out; // video output signals on appropriate pins // Instantiate the video from cog_vid.v cog_vid cog_vid_ ( .clk_cog (clk_cog), // system clock .clk_vid (plla), // PLLA clock input .ena (ena), // video enable .setvid (setvid), // setvid signal (ie write to VCFG) .setscl (setscl), // setscl signal (ie write to VSCL) .data (alu_r), // data (32 bits) input .pixel (s), // Source (32 bits) value .color (d), // Destination (32 bits) value .aural (pll_in), // ??? .carrier (pllb), // ??? .ack (vidack), // WAITVID complete???? .pin_out (vid_pin_out) ); // video output on pins // instruction // decode the instruction value... reg [31:0] ix; // stores next instruction fetched always @(posedge clk_cog) if (m[3]) ix <= ram_q; // if m[3] then store the ram read results for the next instruction fetched wire [31:0] i = run ? ix : // if cog running, save next instruction fetched {14'b000010_001_0_0001, p, 9'b000000000}; // else set "boot" instruction to "IF_A RDLONG PC,0" // source // decode the source value... reg [31:0] sy; // temp holding register for ram read of source address reg [31:0] s; // final source value always @(posedge clk_cog) if (m[1]) sy <= ram_q; // state m[1]: save the source value read from ram in m[0] wire [31:0] sx = i[im] ? {23'b0, i[sh:sl]} // if I then sx= immediate source value of instruction : i[sh:sl] == 9'h1F0 ? {16'b0, ptr[27:14], 2'b0} // elseif PAR then sx= PAR value : i[sh:sl] == 9'h1F1 ? cnt // elseif CNT then sx= CNT value : i[sh:sl] == 9'h1F2 ? pin_in // elseif INA then sx= pin_in : i[sh:sl] == 9'h1FC ? phsa[31:0] // elseif PHSA then sx= PHSA value : i[sh:sl] == 9'h1FD ? phsb[31:0] // elseif PHSB then sx= PHSB value : sy; // else sx= sy (ram source value read) always @(posedge clk_cog) if (m[2]) s <= sx; // state m[2] copy sx value to s // destination // decode the destination (input) value... reg [31:0] d; // final destination (input) value always @(posedge clk_cog) if (m[2]) d <= ram_q; // state m[2]: save the destination (input) value read from ram in m[1] // condition // decode the condition code... wire [3:0] condx = i[ch:cl]; // extract the cccc bits [21:18] from the instruction wire cond = condx[{c, z}] && !cancel; // ??? and not cancel (ie need to set the condition flags???) // jump/next // decode the next PC (program counter) value... reg cancel; // set if jump is cancelled wire dz = ~|d[31:1]; // calculate the Z flag setting wire [1:0] jumpx = i[oh:ol] == 6'b010111 ? {1'b1, 1'b0} // if retjmp jumpx= 10 : i[oh:ol] == 6'b111001 ? {1'b1, dz && d[0]} // elseif djnz jumpx= 1x (x= zero and result=0) : i[oh:ol] == 6'b111010 ? {1'b1, dz && !d[0]} // elseif tjnz jumpx= 1x (x= zero and result!=0) : i[oh:ol] == 6'b111011 ? {1'b1, !(dz && !d[0])} // elseif tjz jumpx= 1x (x=!(zero and result=0)) : {1'b0, 1'b0}; // else no jump jumpx= 00 wire jump = jumpx[1]; // 1= jump instruction wire jump_cancel = jumpx[0]; // 1= cancel the jump wire [8:0] px = cond && jump ? sx[8:0] : p; // if condition met and not cancelled, PC=sx[8:0] (ie jump) else PC=p (ie PC+1) always @(posedge clk_cog or negedge ena) if (!ena) cancel <= 1'b0; // if cog not enabled then cancel=0 else if (m[3]) cancel <= cond && jump_cancel || &px; // else if m[3] cancel = (condition met and not cancelled) OR &px (&px does what???) // bus interface // decode bus... // if not bus_sel set zero(s), else... assign bus_r = !bus_sel ? 1'b0 : run; // ... = run flag assign bus_e = !bus_sel ? 1'b0 : i[oh:ol+2] == 4'b0000__ && m[4]; // ... = hubop AND m[4] (hubop= RD/WR or SYSOP) assign bus_w = !bus_sel ? 1'b0 : !i[wr]; // ... = write (ie not NR) assign bus_s = !bus_sel ? 2'b0 : i[ol+1:ol]; // ... = i[1:0] bits assign bus_a = !bus_sel ? 16'b0 : run ? s[15:0] : {ptr[13:0] + {5'b0, p}, s[1:0]}; // ... if run = hub addr s[15:0] else "boot???" assign bus_d = !bus_sel ? 32'b0 : d; // ... =d[31:0] // alu interface // decode in cog_alu.v ... wire alu_wr; // alu write wire [31:0] alu_r; // alu result wire alu_co; // alu carry flag wire alu_zo; // alu zero flag // instantiate cog_alu using cog_alu.v cog_alu cog_alu_ ( .i (i[oh:ol]), // instruction op code i[31:26] .s (s), // source value .d (d), // destination value .p (p), // PC (program counter) .run (run), // run flag .ci (c), // input C flag .zi (z), // input Z flag .bus_q (bus_q), // input ??? .bus_c (bus_c), // input ??? .wr (alu_wr), // output write result .r (alu_r), // output result value .co (alu_co), // output C flag .zo (alu_zo) ); // output Z flag // pin/count match // WAITPEQ/WAITPNE/WAITCNT... reg match; // set if WAITPEQ/WAITPNE/WAITCNT condition met // decoding instructions WAITPEQ 111100 / WAITPNE 111101 / WAITCNT 111110 ... always @(posedge clk_cog) match <= m[4] && (i[ol+1:ol] == 2'b01 ^ (i[ol+1] ? cnt : pin_in & s) == d); // match <= m[4] && // state m[4] AND ... // ( i[ol+1:ol] == 2'b01 // if (instr[1:0]==01) then 1 else 0 (ie if instr=xxxx01= WAITPNE then 1 else 0) // ^ // XOR // (i[ol+1] ? cnt : pin_in & s) // if instr[1]=1 then CNT else (pin_in AND source mask) // == d); // == destination value (ie is CNT met or PINS same) // // ie if m[4] AND... // if WAITCNT then if CNT == destination value (ie count matched) // else if WAITPEQ then if (pin_in & source mask) == destination value (ie pins & mask matched) // else if WAITPNE then if !(pin_in & source mask) == destination value (ie pins & mask not matched) // wait wire waitx = i[oh:ol+2] == 4'b0000__ ? !bus_ack // if instr=0000xx then waitx= !bus_ack : i[oh:ol+1] == 5'b11110_ ? !match // elseif instr=11110x then waitx= !match : i[oh:ol+0] == 6'b111110 ? !match // elseif instr=11111x then waitx= !match : i[oh:ol+0] == 6'b111111 ? !vidack // elseif instr=111111 then waitx= !vidack : 1'b0; // else waitx= 0 wire waiti = cond && waitx; // set if condition met AND waitx // pins // set output pins... // (OUTA | CTRA | CTRB | VIDEO ) & DIRA assign pin_out = (outa | ctra_pin_out | ctrb_pin_out | vid_pin_out) & dira; assign pin_dir = dira; // DIRA endmoduleNote: The forum has not expanded tab stops correctly. I view the source file with Notepad++.
// cog_alu /* ------------------------------------------------------------------------------- Copyright 2014 Parallax Inc. This file is part of the hardware description for the Propeller 1 Design. The Propeller 1 Design is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The Propeller 1 Design is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the Propeller 1 Design. If not, see <[URL]http://www.gnu.org/licenses/[/URL]>. ------------------------------------------------------------------------------- */ // RR20140823 Comments by Cluso99 module cog_alu ( input [5:0] i, // instruction opcode iiiiii input [31:0] s, // source value input [31:0] d, // destination value input [8:0] p, // PC (program counter) input run, // run flag input ci, // C flag input input zi, // Z flag input input [31:0] bus_q, // input bus_c, // output wr, // write result flag output [31:0] r, // result output co, // C flag output zo // Z flag ); // rotation instructions 001nnn - rev/sar/rc/rcr/shl/shr/rol/ror wire [31:0] dr = { d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15], d[16], d[17], d[18], d[19], d[20], d[21], d[22], d[23], d[24], d[25], d[26], d[27], d[28], d[29], d[30], d[31] }; // REV // precalculate interim rev/sar/rc/rcr/shl/shr/rol/ror results wire [7:0][30:0] ri = { 31'b0, // rev {31{d[31]}}, // sar {31{ci}}, // rcl {31{ci}}, // rcr 31'b0, // shl 31'b0, // shr dr[30:0], // rol d[30:0] }; // ror wire [62:0] rot = {ri[i[2:0]], i[0] ? dr : d} >> s[4:0]; wire [31:0] rotr = { rot[0], rot[1], rot[2], rot[3], rot[4], rot[5], rot[6], rot[7], rot[8], rot[9], rot[10], rot[11], rot[12], rot[13], rot[14], rot[15], rot[16], rot[17], rot[18], rot[19], rot[20], rot[21], rot[22], rot[23], rot[24], rot[25], rot[26], rot[27], rot[28], rot[29], rot[30], rot[31] }; wire [31:0] rot_r = ~&i[2:1] && i[0] ? rotr : rot[31:0]; // result if rotate type instruction wire rot_c = ~&i[2:1] && i[0] ? dr[0] : d[0]; // C result if rotate type instruction // logic instructions 01nnnn - mins/maxs/min/max/movs/movd/movi/jmpret/and/andn/or/xor/muxc/muxnc/muxz/muxnz wire [1:0] log_s = i[2] ? {(i[1] ? zi : ci) ^ i[0], 1'b0} // muxc/muxnc/muxz/muxnz : {i[1], ~^i[1:0]}; // and/andn/or/xor wire [3:0][31:0] log_x = { d ^ s, // 11 = xor d | s, // 10 = or mux 1 d & s, // 01 = and d & ~s }; // 00 = andn mux 0 wire [3:0][31:0] mov_x = { d[31:9], p, // jmpret s[8:0], d[22:0], // movi d[31:18], s[8:0], d[8:0], // movd d[31:9], s[8:0] }; // movs wire [31:0] log_r = i[3] ? log_x[log_s] // and/andn/or/xor/muxc/muxnc/muxz/muxnz : i[2] ? mov_x[i[1:0]] // movs/movd/movi/jmpret : s; // mins/maxs/min/max wire log_c = ^log_r; // c is parity of result // add/sub instructions 1nnnnn wire [3:0] ads = {zi, ci, s[31], 1'b0}; wire add_sub = i[5:4] == 2'b10 ? ads[i[2:1]] ^ i[0] // 10nnnn add/sub/addabs/subabs/sumc/sumnc/sumz/sumnz/mov/neg/abs/absneg/negc/negnc/negz/negnz : i[5:0] == 6'b110010 || // 110010 addx i[5:0] == 6'b110100 || // 110100 adds i[5:0] == 6'b110110 || // 110110 addsx i[5:2] == 4'b1111 // 1111nn waitcnt ? 1'b0 // 0 if above instructions : 1'b1; // 1 if other subs wire add_ci = i[5:3] == 3'b110 && (i[2:0] == 3'b001 || i[1]) && ci || // cmpsx/addx/subx/addsx/subsx i[4:3] == 2'b11 && i[1:0] == 2'b01; // djnz wire [31:0] add_d = i[4:3] == 2'b01 ? 32'b0 : d; // x01xxx mov/neg/abs/absneg/negc/negnc/negz/negnz wire [31:0] add_s = i[4:0] == 5'b11001 || i[4:1] == 4'b1101 ? 32'hFFFFFFFF // djnz/tjnz/tjz (x11001 or x1101n) : add_sub ? ~s // subs : s; // adds wire [34:0] add_x = {1'b0, add_d[31], 1'b1, add_d[30:0], 1'b1} + {1'b0, add_s[31], 1'b0, add_s[30:0], add_ci ^ add_sub}; // interim result wire [31:0] add_r = {add_x[33], add_x[31:1]}; // final result wire add_co = add_x[34]; // interim C results wire add_cm = !add_x[32]; // interim C results wire add_cs = add_co ^ add_d[31] ^ add_s[31]; // interim C results // calculate final C out wire add_c = i[5:0] == 6'b111000 ? add_co // cmpsub : i[5:3] == 3'b101 ? s[31] // source msb : i[5] && i[3:2] == 2'b01 ? add_co ^ add_cm // overflow : i[4:1] == 4'b1000 ? add_cs // signed : add_co ^ add_sub; // unsigned // write-cancel instructions // Calculate if Write Result will occur assign wr = i[5:2] == 4'b0100 ? i[0] ^ (i[1] ? !add_co : add_cs) // mins/maxs/min/max : i[5:0] == 6'b111000 ? add_co // cmpsub : 1'b1; // others // r, c, z results // Calculate Final Result assign r = i[5] ? add_r : i[4] ? log_r : i[3] ? rot_r : run || ~&p[8:4] ? bus_q : 32'b0; // write 0's to last 16 registers during load; // Calculate Final C flag output assign co = i[5:3] == 3'b000 ? bus_c : i[5:3] == 3'b001 ? rot_c : i[5:3] == 3'b011 ? log_c : add_c; // Calculate Final Z flag output assign zo = ~|r && (zi || !(i[5:3] == 3'b110 && (i[2:0] == 3'b001 || i[1]))); // addx/subx/cmpx/addsx/subsx/cmpsx logically AND the old z endmodule@Cluso
This is great stuff! Very helpful. Thanks for sharing!
I think it would be fabulous if Chip would take half an hour and create a glossary for those two letter identifiers he loves so much - shades of Basic! I like the terseness from a visual POV but it's an effort to figure out his naming conventions.
Warning: There is an error in the states for the timing diagram. Please see the next post.
P8X32A FPGA - How it works This is my current understanding. No responsibility taken for errors, omissions, or misunderstanding. RR20140903 by Cluso99 (Ray) STATES: When running, the cog can be in 5 states, represented by m[4:0] states: m[0] = S m[1] = D m[2] = I m[4] = *wait (if wait state needs to be inserted due to a WAITxxx instruction (or wait for hub slot???) m[3] = R These states relate to the 6 clocks of an instruction. Due to overlapping instructions, each instruction effectively uses 4 clocks. I d S D e R <---- previous instruction I d S D e R <---- current instruction I d S D e R <---- next instruction where I = fetch Instruction and executes previous instruction d = decode instruction and write Result of previous instruction S = fetch Source (unless immediate) D = fetch Destination e = execute instruction and fetch next instruction R = write Result and decode next instruction Timing Diagram: │ ┬ └┐ m[1]: Latch D │ │ │ Executing instruction e I ┌─┘ ... │ │ │ Reading I (next instruction) │ │ └┐ m[2]: Latch I │ │ │ Writing R (result) R d ┌─┘ ... │ │ │ Decoding (next instruction) ---------------------------------------------------------------- │ │ └┐ m[4]: WAIT (optional wait states inserted here) │ │ │ Wait for condition │ w ┌─┘ ... │ │ │ ... ---------------------------------------------------------------- ┴ │ └┐ m[3]: Latch R (write result to Cog RAM) │ │ Reading S S ┌─┘ ... │ │ ... │ └┐ m[0]: Latch S │ │ Reading D D ┌─┘ ... │ │ ... │ ┬ └┐ m[1]: Latch D │ │ │ Executing instruction e I ┌─┘ ... │ │ │ Reading I (next instruction) │ │ └┐ m[2]: Latch I │ │ │ Writing R (result) R d ┌─┘ ... │ │ │ Decoding (next instruction) ┴ │ └┐ m[3]: Latch R (write result to Cog RAM)Just realised that my timing diagram above was incorrect.
I am hoping that I have the m[4] state correct..... where the cog waits for an access slot to the hub.
Postedit: I suspect that the wait state(s), if present, come between m[2] and m[3]. Still checking.
Timing Diagram: ┼ ┬ └┐---------------------------------------------------- │ │ │ m[2]: Reading I (next instruction) e I ┌─┘ Executing instruction │ │ │ Latch I ┼ ┼ └┐---------------------------------------------------- │ │ │ m[3]: Writing R (result) R d ┌─┘ Decoding (next instruction) │ │ │ Latch R (write result to Cog RAM) ┴ ┼ └┐==================================================== │ │ m[4]: Reading/Writing if Hub Access ??? (w) ┌─┘(option) WAIT for Condition (optional wait states) │ │ Latch Hub/Cog (read/write if hub access)??? ┼ └┐==================================================== │ │ m[0]: Reading S S ┌─┘ │ │ Latch S ┼ └┐---------------------------------------------------- │ │ m[1]: Reading D D ┌─┘ │ │ Latch D ┼ ┬ └┐---------------------------------------------------- │ │ │ m[2]: Reading I (next instruction) e I ┌─┘ Executing instruction │ │ │ Latch I ┼ ┼ └┐---------------------------------------------------- │ │ │ m[3]: Writing R (result) R d ┌─┘ Decoding (next instruction) │ │ │ Latch R (write result to Cog RAM) ┴ ┼ └┐==================================================== │ │ m[4]: Reading/Writing if Hub Access ??? (w) ┌─┘(option) WAIT for Condition (optional wait states) │ │ Latch Hub/Cog (read/write if hub access)??? ┼ └┐====================================================P8X32A FPGA - How it works This is my current understanding. No responsibility taken for errors, omissions, or misunderstanding. RR20140903 by Cluso99 (Ray) RR20140907 fixup by Cluso99 STATES: When running, the cog can be in 5 states, represented by m[4:0] states: m[0] = S m[1] = D m[2] = I m[3] = R m[4] = *wait / hub slot (if wait state needs to be inserted due to a WAITxxx instruction or wait for hub slot) These states relate to the 6 clocks of an instruction. Due to overlapping instructions, each instruction effectively uses 4 clocks. I d S D e R <---- previous instruction I d S D e R <---- current instruction I d S D e R <---- next instruction where I = fetch Instruction and executes previous instruction d = decode instruction and write Result of previous instruction S = fetch Source (unless immediate) D = fetch Destination e = execute instruction and fetch next instruction R = write Result and decode next instruction Timing Diagram: ┼ ┬ └┐-------┻-------------------------------------------- │ │ │ m[2]: Reading I (next instruction) e I ┌─┘ Executing instruction │ │ │ ┌─Latch I ┼ ┼ └┐=======┻============================================ │ │ │ m[4]: Reading/Writing if Hub Access ??? (w)(w) ┌─┘(option) WAIT for Condition (optional wait states) │ │ │ ┌─Latch Hub/Cog (read/write if hub access)??? ┼ ┼ └┐=======┻============================================ │ │ │ m[3]: Writing R (result) R d ┌─┘ Decoding (next instruction) │ │ │ ┌─Latch R (write result to Cog RAM) ┴ ┼ └┐-------┻-------------------------------------------- │ │ m[0]: Reading S S ┌─┘ │ │ ┌─Latch S ┼ └┐-------┻-------------------------------------------- │ │ m[1]: Reading D D ┌─┘ │ │ ┌─Latch D ┼ ┬ └┐-------┻-------------------------------------------- │ │ │ m[2]: Reading I (next instruction) e I ┌─┘ Executing instruction │ │ │ ┌─Latch I ┼ ┼ └┐=======┻============================================ │ │ │ m[4]: Reading/Writing if Hub Access ??? (w)(w) ┌─┘(option) WAIT for Condition (optional wait states) │ │ │ ┌─Latch Hub/Cog (read/write if hub access)??? ┼ ┼ └┐=======┻============================================ │ │ │ m[3]: Writing R (result) R d ┌─┘ Decoding (next instruction) │ │ │ ┌─Latch R (write result to Cog RAM) ┴ ┼ └┐-------┻-------------------------------------------- .