From a356ac5b551aca205122aa8d6d95a4fda9b5e1cf Mon Sep 17 00:00:00 2001 From: Wolfgang Spraul Date: Wed, 3 Oct 2012 15:19:59 +0200 Subject: [PATCH] support IO standards LVCMOS 33/25/18/15/12, LVTTL --- LINKS | 14 ++ README | 1 + autotest.c | 88 +++++++--- blinking_led.c | 6 +- hello_world.c | 6 +- libs/bit_frames.c | 406 +++++++++++++++++++++++++++++++++++----------- libs/control.c | 24 ++- libs/control.h | 6 +- libs/helper.c | 6 +- libs/model.h | 12 +- libs/parts.h | 55 ++++++- 11 files changed, 481 insertions(+), 143 deletions(-) diff --git a/LINKS b/LINKS index 625e51b..db5e8de 100644 --- a/LINKS +++ b/LINKS @@ -4,3 +4,17 @@ http://en.wikipedia.org/wiki/Wikipedia:WikiProject_Electronics/Programs http://qfsm.sourceforge.net/about.html http://www.texample.net/tikz/examples/timing-diagram/ http://smithsonianchips.si.edu/ice/s4.htm + +http://www.hottconsultants.com/techtips/pcb-stack-up-3.html + +Andrew's redtin logic analyzer + http://code.google.com/p/red-tin-logic-analyzer + +gtkwave wave viewer + http://gtkwave.sourceforge.net + +Fedora Electronic Lab tool overview + http://spins.fedoraproject.org/fel/#portfolio + http://chitlesh.fedorapeople.org/FEL/list.html + + with links to magic, toped, qucs, iverilog, alliance, etc. diff --git a/README b/README index 68cd798..d27eee8 100644 --- a/README +++ b/README @@ -61,6 +61,7 @@ TODO short-term (1 month): * add lut_encoding autotest for lut6 and lut5 in a-d position of x(m), x(l), l and m devs +* more cases in logic_cfg test * example: blinking_led * example: counter (including clock, jtag) * support reading iologic switches diff --git a/autotest.c b/autotest.c index 302ebbc..ff0e0db 100644 --- a/autotest.c +++ b/autotest.c @@ -514,7 +514,7 @@ int test_routing_sw_from_iob(struct test_state* tstate, rc = fpga_find_iob(tstate->model, "P48", &iob_y, &iob_x, &iob_type_idx); if (rc) FAIL(rc); - rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx); + rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33); if (rc) FAIL(rc); iob_dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx); if (!iob_dev) FAIL(EINVAL); @@ -851,7 +851,7 @@ static int test_iologic_switches(struct test_state* tstate) // input IOB rc = fpga_find_iob(tstate->model, iob_name, &iob_y, &iob_x, &iob_type_idx); if (rc) FAIL(rc); - rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx); + rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33); if (rc) FAIL(rc); rc = test_iologic_switches2(tstate, iob_y, iob_x, iob_type_idx); if (rc) FAIL(rc); @@ -860,7 +860,7 @@ static int test_iologic_switches(struct test_state* tstate) // output IOB rc = fpga_find_iob(tstate->model, iob_name, &iob_y, &iob_x, &iob_type_idx); if (rc) FAIL(rc); - rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx); + rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33); if (rc) FAIL(rc); rc = test_iologic_switches2(tstate, iob_y, iob_x, iob_type_idx); if (rc) FAIL(rc); @@ -873,16 +873,17 @@ fail: static int test_iob_config(struct test_state* tstate) { - int iob_y, iob_x, iob_type_idx, rc; + int iob_y, iob_x, iob_type_idx, i, j, rc; net_idx_t net_idx; struct fpga_device* dev; + int drive_strengths[] = {2, 4, 6, 8, 12, 16, 24}; tstate->diff_to_null = 1; // P45 is an IOBS rc = fpga_find_iob(tstate->model, "P45", &iob_y, &iob_x, &iob_type_idx); if (rc) FAIL(rc); - rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx); + rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33); if (rc) FAIL(rc); dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx); if (!dev) FAIL(EINVAL); @@ -896,7 +897,7 @@ static int test_iob_config(struct test_state* tstate) // P46 is an IOBM rc = fpga_find_iob(tstate->model, "P46", &iob_y, &iob_x, &iob_type_idx); if (rc) FAIL(rc); - rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx); + rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33); if (rc) FAIL(rc); if ((rc = diff_printf(tstate))) FAIL(rc); fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx); @@ -904,7 +905,7 @@ static int test_iob_config(struct test_state* tstate) // P47 is an IOBS rc = fpga_find_iob(tstate->model, "P47", &iob_y, &iob_x, &iob_type_idx); if (rc) FAIL(rc); - rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx); + rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33); if (rc) FAIL(rc); dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx); if (!dev) FAIL(EINVAL); @@ -928,20 +929,10 @@ static int test_iob_config(struct test_state* tstate) rc = diff_printf(tstate); if (rc) FAIL(rc); dev->u.iob.suspend = SUSP_3STATE; - dev->u.iob.drive_strength = 2; - rc = diff_printf(tstate); if (rc) FAIL(rc); - dev->u.iob.drive_strength = 4; - rc = diff_printf(tstate); if (rc) FAIL(rc); - dev->u.iob.drive_strength = 6; - rc = diff_printf(tstate); if (rc) FAIL(rc); - dev->u.iob.drive_strength = 8; - rc = diff_printf(tstate); if (rc) FAIL(rc); - dev->u.iob.drive_strength = 12; - rc = diff_printf(tstate); if (rc) FAIL(rc); - dev->u.iob.drive_strength = 16; - rc = diff_printf(tstate); if (rc) FAIL(rc); - dev->u.iob.drive_strength = 24; - rc = diff_printf(tstate); if (rc) FAIL(rc); + for (i = 0; i < sizeof(drive_strengths)/sizeof(*drive_strengths); i++) { + dev->u.iob.drive_strength = drive_strengths[i]; + rc = diff_printf(tstate); if (rc) FAIL(rc); + } dev->u.iob.drive_strength = 8; dev->u.iob.slew = SLEW_SLOW; @@ -957,7 +948,7 @@ static int test_iob_config(struct test_state* tstate) // P48 is an IOBM rc = fpga_find_iob(tstate->model, "P48", &iob_y, &iob_x, &iob_type_idx); if (rc) FAIL(rc); - rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx); + rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33); if (rc) FAIL(rc); dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx); if (!dev) FAIL(EINVAL); @@ -977,7 +968,59 @@ static int test_iob_config(struct test_state* tstate) if (rc) FAIL(rc); if ((rc = diff_printf(tstate))) FAIL(rc); + fnet_delete(tstate->model, net_idx); fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx); + + // different IO standards + // The left (3) and right (1) banks have higher voltage ranges + // than the top (0) and bottom (2) banks, so we test this on + // the left side (ug381 page 13). + // todo: IO_SSTL2_I is not implemented right + { const char* io_std[] = { IO_LVCMOS33, IO_LVCMOS25, IO_LVCMOS18, + IO_LVCMOS18_JEDEC, IO_LVCMOS15, IO_LVCMOS15_JEDEC, + IO_LVCMOS12, IO_LVCMOS12_JEDEC, IO_LVTTL, IO_SSTL2_I, 0 }; + i = 0; + while (io_std[i]) { + // input + rc = fpga_find_iob(tstate->model, "P22", &iob_y, &iob_x, &iob_type_idx); + if (rc) FAIL(rc); + rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx, io_std[i]); + if (rc) FAIL(rc); + if ((rc = diff_printf(tstate))) FAIL(rc); + fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx); + + i++; + } + i = 0; + while (io_std[i]) { + // output + rc = fpga_find_iob(tstate->model, "P22", &iob_y, &iob_x, &iob_type_idx); + if (rc) FAIL(rc); + rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx, io_std[i]); + if (rc) FAIL(rc); + if (!strcmp(io_std[i], IO_SSTL2_I)) { + rc = diff_printf(tstate); if (rc) FAIL(rc); + } else { + dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx); + if (!dev) FAIL(EINVAL); + + for (j = 0; j < sizeof(drive_strengths)/sizeof(*drive_strengths); j++) { + if ((!strcmp(io_std[i], IO_LVCMOS15) + || !strcmp(io_std[i], IO_LVCMOS15_JEDEC)) + && drive_strengths[j] == 24) + continue; + if ((!strcmp(io_std[i], IO_LVCMOS12) + || !strcmp(io_std[i], IO_LVCMOS12_JEDEC)) + && (drive_strengths[j] == 16 || drive_strengths[j] == 24)) + continue; + dev->u.iob.drive_strength = drive_strengths[j]; + rc = diff_printf(tstate); if (rc) FAIL(rc); + } + } + fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx); + + i++; + }} return 0; fail: return rc; @@ -1126,7 +1169,6 @@ static int test_lut_encoding(struct test_state* tstate) } } } -out: return 0; fail: return rc; diff --git a/blinking_led.c b/blinking_led.c index dc415d9..5e0da19 100644 --- a/blinking_led.c +++ b/blinking_led.c @@ -25,17 +25,17 @@ int main(int argc, char** argv) if ((rc = fpga_find_iob(&model, "P45", &iob_inA_y, &iob_inA_x, &iob_inA_type_idx))) FAIL(rc); if ((rc = fdev_iob_input(&model, iob_inA_y, iob_inA_x, - iob_inA_type_idx))) FAIL(rc); + iob_inA_type_idx, IO_LVCMOS33))) FAIL(rc); if ((rc = fpga_find_iob(&model, "P46", &iob_inB_y, &iob_inB_x, &iob_inB_type_idx))) FAIL(rc); if ((rc = fdev_iob_input(&model, iob_inB_y, iob_inB_x, - iob_inB_type_idx))) FAIL(rc); + iob_inB_type_idx, IO_LVCMOS33))) FAIL(rc); if ((rc = fpga_find_iob(&model, "P48", &iob_out_y, &iob_out_x, &iob_out_type_idx))) FAIL(rc); if ((rc = fdev_iob_output(&model, iob_out_y, iob_out_x, - iob_out_type_idx))) FAIL(rc); + iob_out_type_idx, IO_LVCMOS33))) FAIL(rc); logic_y = 68; logic_x = 13; diff --git a/hello_world.c b/hello_world.c index dc415d9..5e0da19 100644 --- a/hello_world.c +++ b/hello_world.c @@ -25,17 +25,17 @@ int main(int argc, char** argv) if ((rc = fpga_find_iob(&model, "P45", &iob_inA_y, &iob_inA_x, &iob_inA_type_idx))) FAIL(rc); if ((rc = fdev_iob_input(&model, iob_inA_y, iob_inA_x, - iob_inA_type_idx))) FAIL(rc); + iob_inA_type_idx, IO_LVCMOS33))) FAIL(rc); if ((rc = fpga_find_iob(&model, "P46", &iob_inB_y, &iob_inB_x, &iob_inB_type_idx))) FAIL(rc); if ((rc = fdev_iob_input(&model, iob_inB_y, iob_inB_x, - iob_inB_type_idx))) FAIL(rc); + iob_inB_type_idx, IO_LVCMOS33))) FAIL(rc); if ((rc = fpga_find_iob(&model, "P48", &iob_out_y, &iob_out_x, &iob_out_type_idx))) FAIL(rc); if ((rc = fdev_iob_output(&model, iob_out_y, iob_out_x, - iob_out_type_idx))) FAIL(rc); + iob_out_type_idx, IO_LVCMOS33))) FAIL(rc); logic_y = 68; logic_x = 13; diff --git a/libs/bit_frames.c b/libs/bit_frames.c index 5623ccb..3432489 100644 --- a/libs/bit_frames.c +++ b/libs/bit_frames.c @@ -123,17 +123,30 @@ static int write_iobs(struct fpga_bits* bits, struct fpga_model* model) if (dev->u.iob.istandard[0]) { if (!dev->u.iob.I_mux || !dev->u.iob.bypass_mux - || strcmp(dev->u.iob.istandard, IO_LVCMOS33) || dev->u.iob.ostandard[0]) HERE(); - u64 = XC6_IOB_INSTANTIATED; - u64 |= XC6_IOB_INPUT_LVCMOS33; - if (dev->u.iob.I_mux == IMUX_I) - u64 |= XC6_IOB_IMUX_I; - else if (dev->u.iob.I_mux == IMUX_I_B) + u64 = XC6_IOB_INPUT | XC6_IOB_INSTANTIATED; + + if (dev->u.iob.I_mux == IMUX_I_B) u64 |= XC6_IOB_IMUX_I_B; - else HERE(); + + if (!strcmp(dev->u.iob.istandard, IO_LVCMOS33) + || !strcmp(dev->u.iob.istandard, IO_LVCMOS25) + || !strcmp(dev->u.iob.istandard, IO_LVTTL)) + u64 |= XC6_IOB_INPUT_LVCMOS33_25_LVTTL; + else if (!strcmp(dev->u.iob.istandard, IO_LVCMOS18) + || !strcmp(dev->u.iob.istandard, IO_LVCMOS15) + || !strcmp(dev->u.iob.istandard, IO_LVCMOS12)) + u64 |= XC6_IOB_INPUT_LVCMOS18_15_12; + else if (!strcmp(dev->u.iob.istandard, IO_LVCMOS18_JEDEC) + || !strcmp(dev->u.iob.istandard, IO_LVCMOS15_JEDEC) + || !strcmp(dev->u.iob.istandard, IO_LVCMOS12_JEDEC)) + u64 |= XC6_IOB_INPUT_LVCMOS18_15_12_JEDEC; + else if (!strcmp(dev->u.iob.istandard, IO_SSTL2_I)) + u64 |= XC6_IOB_INPUT_SSTL2_I; + else + HERE(); frame_set_u64(&bits->d[IOB_DATA_START + part_idx*IOB_ENTRY_LEN], u64); @@ -141,29 +154,85 @@ static int write_iobs(struct fpga_bits* bits, struct fpga_model* model) if (!dev->u.iob.drive_strength || !dev->u.iob.slew || !dev->u.iob.suspend - || strcmp(dev->u.iob.ostandard, IO_LVCMOS33) || dev->u.iob.istandard[0]) HERE(); u64 = XC6_IOB_INSTANTIATED; // for now we always turn on O_PINW even if no net // is connected to the pinw - u64 |= XC6_IOB_MASK_O_PINW; - switch (dev->u.iob.drive_strength) { - case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_2; break; - case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4; break; - case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6; break; - case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8; break; - case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12; break; - case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16; break; - case 24: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24; break; - default: HERE(); - } + u64 |= XC6_IOB_O_PINW; + if (!strcmp(dev->u.iob.ostandard, IO_LVTTL)) { + switch (dev->u.iob.drive_strength) { + case 2: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_2; break; + case 4: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_4; break; + case 6: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_6; break; + case 8: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_8; break; + case 12: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_12; break; + case 16: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_16; break; + case 24: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_24; break; + default: FAIL(EINVAL); + } + } else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS33)) { + switch (dev->u.iob.drive_strength) { + case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS33_25_DRIVE_2; break; + case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4; break; + case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6; break; + case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8; break; + case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12; break; + case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16; break; + case 24: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24; break; + default: FAIL(EINVAL); + } + } else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS25)) { + switch (dev->u.iob.drive_strength) { + case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS33_25_DRIVE_2; break; + case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_4; break; + case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_6; break; + case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_8; break; + case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_12; break; + case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_16; break; + case 24: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_24; break; + default: FAIL(EINVAL); + } + } else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS18) + || !strcmp(dev->u.iob.ostandard, IO_LVCMOS18_JEDEC)) { + switch (dev->u.iob.drive_strength) { + case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_2; break; + case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_4; break; + case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_6; break; + case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_8; break; + case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_12; break; + case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_16; break; + case 24: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_24; break; + default: FAIL(EINVAL); + } + } else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS15) + || !strcmp(dev->u.iob.ostandard, IO_LVCMOS15_JEDEC)) { + switch (dev->u.iob.drive_strength) { + case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_2; break; + case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_4; break; + case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_6; break; + case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_8; break; + case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_12; break; + case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_16; break; + default: FAIL(EINVAL); + } + } else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS12) + || !strcmp(dev->u.iob.ostandard, IO_LVCMOS12_JEDEC)) { + switch (dev->u.iob.drive_strength) { + case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_2; break; + case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_4; break; + case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_6; break; + case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_8; break; + case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_12; break; + default: FAIL(EINVAL); + } + } else FAIL(EINVAL); switch (dev->u.iob.slew) { case SLEW_SLOW: u64 |= XC6_IOB_SLEW_SLOW; break; case SLEW_FAST: u64 |= XC6_IOB_SLEW_FAST; break; case SLEW_QUIETIO: u64 |= XC6_IOB_SLEW_QUIETIO; break; - default: HERE(); + default: FAIL(EINVAL); } switch (dev->u.iob.suspend) { case SUSP_LAST_VAL: u64 |= XC6_IOB_SUSP_LAST_VAL; break; @@ -172,7 +241,7 @@ static int write_iobs(struct fpga_bits* bits, struct fpga_model* model) case SUSP_3STATE_PULLDOWN: u64 |= XC6_IOB_SUSP_3STATE_PULLDOWN; break; case SUSP_3STATE_KEEPER: u64 |= XC6_IOB_SUSP_3STATE_KEEPER; break; case SUSP_3STATE_OCT_ON: u64 |= XC6_IOB_SUSP_3STATE_OCT_ON; break; - default: HERE(); + default: FAIL(EINVAL); } frame_set_u64(&bits->d[IOB_DATA_START @@ -219,58 +288,214 @@ static int extract_iobs(struct fpga_model* model, struct fpga_bits* bits) clear_bit(bits, /*row*/ 0, get_rightside_major(XC6SLX9), /*minor*/ 22, 64*15+XC6_HCLK_BITS+4); } - if ((u64 & XC6_IOB_MASK_INSTANTIATED) == XC6_IOB_INSTANTIATED) - u64 &= ~XC6_IOB_MASK_INSTANTIATED; + if (u64 & XC6_IOB_INSTANTIATED) + u64 &= ~XC6_IOB_INSTANTIATED; else HERE(); switch (u64 & XC6_IOB_MASK_IO) { - case XC6_IOB_INPUT_LVCMOS33: - u64 &= ~XC6_IOB_MASK_IO; - - strcpy(cfg.istandard, IO_LVCMOS33); + case XC6_IOB_INPUT: cfg.bypass_mux = BYPASS_MUX_I; - switch (u64 & XC6_IOB_MASK_I_MUX) { - case XC6_IOB_IMUX_I: - u64 &= ~XC6_IOB_MASK_I_MUX; - cfg.I_mux = IMUX_I; + if (u64 & XC6_IOB_IMUX_I_B) { + cfg.I_mux = IMUX_I_B; + u64 &= ~XC6_IOB_IMUX_I_B; + } else + cfg.I_mux = IMUX_I; + + switch (u64 & XC6_IOB_MASK_IN_TYPE) { + case XC6_IOB_INPUT_LVCMOS33_25_LVTTL: + u64 &= ~XC6_IOB_MASK_IN_TYPE; + strcpy(cfg.istandard, IO_LVCMOS25); break; - case XC6_IOB_IMUX_I_B: - u64 &= ~XC6_IOB_MASK_I_MUX; - cfg.I_mux = IMUX_I_B; + case XC6_IOB_INPUT_LVCMOS18_15_12: + u64 &= ~XC6_IOB_MASK_IN_TYPE; + strcpy(cfg.istandard, IO_LVCMOS12); + break; + case XC6_IOB_INPUT_LVCMOS18_15_12_JEDEC: + u64 &= ~XC6_IOB_MASK_IN_TYPE; + strcpy(cfg.istandard, IO_LVCMOS12_JEDEC); + break; + case XC6_IOB_INPUT_SSTL2_I: + u64 &= ~XC6_IOB_MASK_IN_TYPE; + strcpy(cfg.istandard, IO_SSTL2_I); break; - default: HERE(); - } - break; - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_2: - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4: - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6: - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8: - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12: - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16: - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24: - switch (u64 & XC6_IOB_MASK_IO) { - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_2: - cfg.drive_strength = 2; break; - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4: - cfg.drive_strength = 4; break; - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6: - cfg.drive_strength = 6; break; - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8: - cfg.drive_strength = 8; break; - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12: - cfg.drive_strength = 12; break; - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16: - cfg.drive_strength = 16; break; - case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24: - cfg.drive_strength = 24; break; default: HERE(); break; } - u64 &= ~XC6_IOB_MASK_IO; - u64 &= ~XC6_IOB_MASK_O_PINW; + break; + + case XC6_IOB_OUTPUT_LVCMOS33_25_DRIVE_2: + cfg.drive_strength = 2; + strcpy(cfg.ostandard, IO_LVCMOS25); + break; + case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4: + cfg.drive_strength = 4; strcpy(cfg.ostandard, IO_LVCMOS33); - cfg.O_used = 1; + break; + case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6: + cfg.drive_strength = 6; + strcpy(cfg.ostandard, IO_LVCMOS33); + break; + case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8: + cfg.drive_strength = 8; + strcpy(cfg.ostandard, IO_LVCMOS33); + break; + case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12: + cfg.drive_strength = 12; + strcpy(cfg.ostandard, IO_LVCMOS33); + break; + case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16: + cfg.drive_strength = 16; + strcpy(cfg.ostandard, IO_LVCMOS33); + break; + case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24: + cfg.drive_strength = 24; + strcpy(cfg.ostandard, IO_LVCMOS33); + break; + + case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_4: + cfg.drive_strength = 4; + strcpy(cfg.ostandard, IO_LVCMOS25); + break; + case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_6: + cfg.drive_strength = 6; + strcpy(cfg.ostandard, IO_LVCMOS25); + break; + case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_8: + cfg.drive_strength = 8; + strcpy(cfg.ostandard, IO_LVCMOS25); + break; + case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_12: + cfg.drive_strength = 12; + strcpy(cfg.ostandard, IO_LVCMOS25); + break; + case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_16: + cfg.drive_strength = 16; + strcpy(cfg.ostandard, IO_LVCMOS25); + break; + case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_24: + cfg.drive_strength = 24; + strcpy(cfg.ostandard, IO_LVCMOS25); + break; + + case XC6_IOB_OUTPUT_LVTTL_DRIVE_2: + cfg.drive_strength = 2; + strcpy(cfg.ostandard, IO_LVTTL); + break; + case XC6_IOB_OUTPUT_LVTTL_DRIVE_4: + cfg.drive_strength = 4; + strcpy(cfg.ostandard, IO_LVTTL); + break; + case XC6_IOB_OUTPUT_LVTTL_DRIVE_6: + cfg.drive_strength = 6; + strcpy(cfg.ostandard, IO_LVTTL); + break; + case XC6_IOB_OUTPUT_LVTTL_DRIVE_8: + cfg.drive_strength = 8; + strcpy(cfg.ostandard, IO_LVTTL); + break; + case XC6_IOB_OUTPUT_LVTTL_DRIVE_12: + cfg.drive_strength = 12; + strcpy(cfg.ostandard, IO_LVTTL); + break; + case XC6_IOB_OUTPUT_LVTTL_DRIVE_16: + cfg.drive_strength = 16; + strcpy(cfg.ostandard, IO_LVTTL); + break; + case XC6_IOB_OUTPUT_LVTTL_DRIVE_24: + cfg.drive_strength = 24; + strcpy(cfg.ostandard, IO_LVTTL); + break; + + case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_2: + cfg.drive_strength = 2; + strcpy(cfg.ostandard, IO_LVCMOS18); + break; + case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_4: + cfg.drive_strength = 4; + strcpy(cfg.ostandard, IO_LVCMOS18); + break; + case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_6: + cfg.drive_strength = 6; + strcpy(cfg.ostandard, IO_LVCMOS18); + break; + case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_8: + cfg.drive_strength = 8; + strcpy(cfg.ostandard, IO_LVCMOS18); + break; + case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_12: + cfg.drive_strength = 12; + strcpy(cfg.ostandard, IO_LVCMOS18); + break; + case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_16: + cfg.drive_strength = 16; + strcpy(cfg.ostandard, IO_LVCMOS18); + break; + case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_24: + cfg.drive_strength = 24; + strcpy(cfg.ostandard, IO_LVCMOS18); + break; + + case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_2: + cfg.drive_strength = 2; + strcpy(cfg.ostandard, IO_LVCMOS15); + break; + case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_4: + cfg.drive_strength = 4; + strcpy(cfg.ostandard, IO_LVCMOS15); + break; + case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_6: + cfg.drive_strength = 6; + strcpy(cfg.ostandard, IO_LVCMOS15); + break; + case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_8: + cfg.drive_strength = 8; + strcpy(cfg.ostandard, IO_LVCMOS15); + break; + case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_12: + cfg.drive_strength = 12; + strcpy(cfg.ostandard, IO_LVCMOS15); + break; + case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_16: + cfg.drive_strength = 16; + strcpy(cfg.ostandard, IO_LVCMOS15); + break; + + case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_2: + cfg.drive_strength = 2; + strcpy(cfg.ostandard, IO_LVCMOS12); + break; + case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_4: + cfg.drive_strength = 4; + strcpy(cfg.ostandard, IO_LVCMOS12); + break; + case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_6: + cfg.drive_strength = 6; + strcpy(cfg.ostandard, IO_LVCMOS12); + break; + case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_8: + cfg.drive_strength = 8; + strcpy(cfg.ostandard, IO_LVCMOS12); + break; + case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_12: + cfg.drive_strength = 12; + strcpy(cfg.ostandard, IO_LVCMOS12); + break; + + default: HERE(); break; + } + if (cfg.istandard[0] || cfg.ostandard[0]) + u64 &= ~XC6_IOB_MASK_IO; + if (cfg.ostandard[0]) { + cfg.O_used = 1; + u64 &= ~XC6_IOB_O_PINW; + + if (!strcmp(cfg.ostandard, IO_LVCMOS12) + || !strcmp(cfg.ostandard, IO_LVCMOS15) + || !strcmp(cfg.ostandard, IO_LVCMOS18) + || !strcmp(cfg.ostandard, IO_LVCMOS25) + || !strcmp(cfg.ostandard, IO_LVCMOS33) + || !strcmp(cfg.ostandard, IO_LVTTL)) { switch (u64 & XC6_IOB_MASK_SLEW) { case XC6_IOB_SLEW_SLOW: u64 &= ~XC6_IOB_MASK_SLEW; @@ -286,35 +511,34 @@ static int extract_iobs(struct fpga_model* model, struct fpga_bits* bits) break; default: HERE(); } - switch (u64 & XC6_IOB_MASK_SUSPEND) { - case XC6_IOB_SUSP_3STATE: - u64 &= ~XC6_IOB_MASK_SUSPEND; - cfg.suspend = SUSP_3STATE; - break; - case XC6_IOB_SUSP_3STATE_OCT_ON: - u64 &= ~XC6_IOB_MASK_SUSPEND; - cfg.suspend = SUSP_3STATE_OCT_ON; - break; - case XC6_IOB_SUSP_3STATE_KEEPER: - u64 &= ~XC6_IOB_MASK_SUSPEND; - cfg.suspend = SUSP_3STATE_KEEPER; - break; - case XC6_IOB_SUSP_3STATE_PULLUP: - u64 &= ~XC6_IOB_MASK_SUSPEND; - cfg.suspend = SUSP_3STATE_PULLUP; - break; - case XC6_IOB_SUSP_3STATE_PULLDOWN: - u64 &= ~XC6_IOB_MASK_SUSPEND; - cfg.suspend = SUSP_3STATE_PULLDOWN; - break; - case XC6_IOB_SUSP_LAST_VAL: - u64 &= ~XC6_IOB_MASK_SUSPEND; - cfg.suspend = SUSP_LAST_VAL; - break; - default: HERE(); - } - break; - default: HERE(); break; + } + switch (u64 & XC6_IOB_MASK_SUSPEND) { + case XC6_IOB_SUSP_3STATE: + u64 &= ~XC6_IOB_MASK_SUSPEND; + cfg.suspend = SUSP_3STATE; + break; + case XC6_IOB_SUSP_3STATE_OCT_ON: + u64 &= ~XC6_IOB_MASK_SUSPEND; + cfg.suspend = SUSP_3STATE_OCT_ON; + break; + case XC6_IOB_SUSP_3STATE_KEEPER: + u64 &= ~XC6_IOB_MASK_SUSPEND; + cfg.suspend = SUSP_3STATE_KEEPER; + break; + case XC6_IOB_SUSP_3STATE_PULLUP: + u64 &= ~XC6_IOB_MASK_SUSPEND; + cfg.suspend = SUSP_3STATE_PULLUP; + break; + case XC6_IOB_SUSP_3STATE_PULLDOWN: + u64 &= ~XC6_IOB_MASK_SUSPEND; + cfg.suspend = SUSP_3STATE_PULLDOWN; + break; + case XC6_IOB_SUSP_LAST_VAL: + u64 &= ~XC6_IOB_MASK_SUSPEND; + cfg.suspend = SUSP_LAST_VAL; + break; + default: HERE(); + } } if (!u64) { frame_set_u64(&bits->d[IOB_DATA_START diff --git a/libs/control.c b/libs/control.c index ee7182c..317f0bb 100644 --- a/libs/control.c +++ b/libs/control.c @@ -682,7 +682,8 @@ fail: // iob device // -int fdev_iob_input(struct fpga_model* model, int y, int x, int type_idx) +int fdev_iob_input(struct fpga_model* model, int y, int x, int type_idx, + const char* io_std) { struct fpga_device* dev; int rc; @@ -692,7 +693,7 @@ int fdev_iob_input(struct fpga_model* model, int y, int x, int type_idx) rc = reset_required_pins(dev); if (rc) FAIL(rc); - strcpy(dev->u.iob.istandard, IO_LVCMOS33); + strcpy(dev->u.iob.istandard, io_std); dev->u.iob.bypass_mux = BYPASS_MUX_I; dev->u.iob.I_mux = IMUX_I; dev->instantiated = 1; @@ -701,7 +702,8 @@ fail: return rc; } -int fdev_iob_output(struct fpga_model* model, int y, int x, int type_idx) +int fdev_iob_output(struct fpga_model* model, int y, int x, int type_idx, + const char* io_std) { struct fpga_device* dev; int rc; @@ -711,11 +713,21 @@ int fdev_iob_output(struct fpga_model* model, int y, int x, int type_idx) rc = reset_required_pins(dev); if (rc) FAIL(rc); - strcpy(dev->u.iob.ostandard, IO_LVCMOS33); - dev->u.iob.drive_strength = 8; + strcpy(dev->u.iob.ostandard, io_std); dev->u.iob.O_used = 1; - dev->u.iob.slew = SLEW_QUIETIO; dev->u.iob.suspend = SUSP_3STATE; + if (strcmp(io_std, IO_SSTL2_I)) { + // also see ug381 page 31 + if (!strcmp(io_std, IO_LVCMOS33) + || !strcmp(io_std, IO_LVCMOS25)) + dev->u.iob.drive_strength = 12; + else if (!strcmp(io_std, IO_LVCMOS12) + || !strcmp(io_std, IO_LVCMOS12_JEDEC)) + dev->u.iob.drive_strength = 6; + else + dev->u.iob.drive_strength = 8; + dev->u.iob.slew = SLEW_SLOW; + } dev->instantiated = 1; return 0; fail: diff --git a/libs/control.h b/libs/control.h index 220ce06..e9dd40c 100644 --- a/libs/control.h +++ b/libs/control.h @@ -78,8 +78,10 @@ int fdev_logic_cout_used(struct fpga_model* model, int y, int x, int fdev_logic_precyinit(struct fpga_model* model, int y, int x, int type_idx, int precyinit); -int fdev_iob_input(struct fpga_model* model, int y, int x, int type_idx); -int fdev_iob_output(struct fpga_model* model, int y, int x, int type_idx); +int fdev_iob_input(struct fpga_model* model, int y, int x, + int type_idx, const char* io_std); +int fdev_iob_output(struct fpga_model* model, int y, int x, + int type_idx, const char* io_std); int fdev_set_required_pins(struct fpga_model* model, int y, int x, int type, int type_idx); diff --git a/libs/helper.c b/libs/helper.c index 5cf3ca3..6bfa8b1 100644 --- a/libs/helper.c +++ b/libs/helper.c @@ -366,7 +366,7 @@ const char* lut2bool(const uint64_t lut, int bits, int printf_iob(uint8_t* d, int len, int inpos, int num_entries) { - int i, j, num_printed; + int i, num_printed; uint64_t u64; num_printed = 0; @@ -375,10 +375,6 @@ int printf_iob(uint8_t* d, int len, int inpos, int num_entries) if (u64) { printf("iob i%i 0x%016llX\n", i, (long long unsigned) u64); - for (j = 0; j < 64; j++) { - if (u64 & (1ULL << j)) - printf("iob i%i b%i\n", i, j); - } num_printed++; } } diff --git a/libs/model.h b/libs/model.h index 96747a2..e172979 100644 --- a/libs/model.h +++ b/libs/model.h @@ -445,8 +445,16 @@ struct fpgadev_logic enum { IOBM = 1, IOBS }; typedef char IOSTANDARD[32]; -#define IO_LVCMOS33 "LVCMOS33" -#define IO_SSTL2_I "SSTL2_I" // drive attr and slew not used here? +#define IO_LVTTL "LVTTL" +#define IO_LVCMOS33 "LVCMOS33" +#define IO_LVCMOS25 "LVCMOS25" +#define IO_LVCMOS18 "LVCMOS18" +#define IO_LVCMOS18_JEDEC "LVCMOS18_JEDEC" +#define IO_LVCMOS15 "LVCMOS15" +#define IO_LVCMOS15_JEDEC "LVCMOS15_JEDEC" +#define IO_LVCMOS12 "LVCMOS12" +#define IO_LVCMOS12_JEDEC "LVCMOS12_JEDEC" +#define IO_SSTL2_I "SSTL2_I" // TODO: sstl not fully supported enum { BYPASS_MUX_I = 1, BYPASS_MUX_O, BYPASS_MUX_T }; enum { IMUX_I_B = 1, IMUX_I }; enum { SLEW_SLOW = 1, SLEW_FAST, SLEW_QUIETIO }; diff --git a/libs/parts.h b/libs/parts.h index 3d6a854..b0c70ce 100644 --- a/libs/parts.h +++ b/libs/parts.h @@ -41,25 +41,64 @@ #define XC6_HCLK_BYTES 2 #define XC6_HCLK_BITS (XC6_HCLK_BYTES*8) -#define XC6_IOB_MASK_INSTANTIATED 0x0000000000000080 -#define XC6_IOB_MASK_IO 0x00FF00FF00000000 -#define XC6_IOB_MASK_O_PINW 0x0000000000000100 -#define XC6_IOB_MASK_I_MUX 0x000000000000E400 +#define XC6_IOB_MASK_IO 0x00FF00FFFF000000 +#define XC6_IOB_MASK_IN_TYPE 0x000000000000F000 #define XC6_IOB_MASK_SLEW 0x0000000000FF0000 #define XC6_IOB_MASK_SUSPEND 0x000000000000001F #define XC6_IOB_INSTANTIATED 0x0000000000000080 -#define XC6_IOB_INPUT_LVCMOS33 0x00D0002400000000 -#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_2 0x001000B400000000 +#define XC6_IOB_INPUT 0x00D0002400000000 +#define XC6_IOB_INPUT_LVCMOS33_25_LVTTL 0x000000000000E000 +#define XC6_IOB_INPUT_LVCMOS18_15_12 0x000000000000C000 +#define XC6_IOB_INPUT_LVCMOS18_15_12_JEDEC 0x0000000000002000 +#define XC6_IOB_INPUT_SSTL2_I 0x000000000000B000 + +#define XC6_IOB_OUTPUT_LVCMOS33_25_DRIVE_2 0x001000B400000000 #define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4 0x0070006C00000000 #define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6 0x003000FC00000000 #define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8 0x0040000000000000 #define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12 0x0060008800000000 #define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16 0x009800C600000000 #define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24 0x0088007200000000 + +#define XC6_IOB_OUTPUT_LVCMOS25_DRIVE_4 0x00B0006C00000000 +#define XC6_IOB_OUTPUT_LVCMOS25_DRIVE_6 0x004000FC00000000 +#define XC6_IOB_OUTPUT_LVCMOS25_DRIVE_8 0x0000000000000000 +#define XC6_IOB_OUTPUT_LVCMOS25_DRIVE_12 0x0058008800000000 +#define XC6_IOB_OUTPUT_LVCMOS25_DRIVE_16 0x00B800C600000000 +#define XC6_IOB_OUTPUT_LVCMOS25_DRIVE_24 0x0054007200000000 + +#define XC6_IOB_OUTPUT_LVTTL_DRIVE_2 0x009000B400000000 +#define XC6_IOB_OUTPUT_LVTTL_DRIVE_4 0x00F0006C00000000 +#define XC6_IOB_OUTPUT_LVTTL_DRIVE_6 0x007000FC00000000 +#define XC6_IOB_OUTPUT_LVTTL_DRIVE_8 0x0030000000000000 +#define XC6_IOB_OUTPUT_LVTTL_DRIVE_12 0x0080008800000000 +#define XC6_IOB_OUTPUT_LVTTL_DRIVE_16 0x006000C600000000 +#define XC6_IOB_OUTPUT_LVTTL_DRIVE_24 0x0018007200000000 + +#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_2 0x00F000B402000000 +#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_4 0x00C000AC02000000 +#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_6 0x00E000BC02000000 +#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_8 0x00D800A002000000 +#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_12 0x003800A802000000 +#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_16 0x002800A602000000 +#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_24 0x00A400A202000000 + +#define XC6_IOB_OUTPUT_LVCMOS15_DRIVE_2 0x00B0007402000000 +#define XC6_IOB_OUTPUT_LVCMOS15_DRIVE_4 0x00E0000C02000000 +#define XC6_IOB_OUTPUT_LVCMOS15_DRIVE_6 0x0098005C02000000 +#define XC6_IOB_OUTPUT_LVCMOS15_DRIVE_8 0x00C8003002000000 +#define XC6_IOB_OUTPUT_LVCMOS15_DRIVE_12 0x00F4001802000000 +#define XC6_IOB_OUTPUT_LVCMOS15_DRIVE_16 0x002400D602000000 + +#define XC6_IOB_OUTPUT_LVCMOS12_DRIVE_2 0x004000B402000000 +#define XC6_IOB_OUTPUT_LVCMOS12_DRIVE_4 0x0098006C02000000 +#define XC6_IOB_OUTPUT_LVCMOS12_DRIVE_6 0x008800FC02000000 +#define XC6_IOB_OUTPUT_LVCMOS12_DRIVE_8 0x0014000002000000 +#define XC6_IOB_OUTPUT_LVCMOS12_DRIVE_12 0x00FC008802000000 + +#define XC6_IOB_IMUX_I_B 0x0000000000000400 #define XC6_IOB_O_PINW 0x0000000000000100 -#define XC6_IOB_IMUX_I 0x000000000000E000 -#define XC6_IOB_IMUX_I_B 0x000000000000E400 #define XC6_IOB_SLEW_SLOW 0x0000000000000000 #define XC6_IOB_SLEW_FAST 0x0000000000330000 #define XC6_IOB_SLEW_QUIETIO 0x0000000000660000