Saturday, 2021-09-04

Las[m]lkcl: Are the instructions for building the data used in soclayout/experiments9 documented anywhere?11:08
lkclLas[m], 1 sec11:14
lkclrun this script11:15
lkclbear in mind it takes NINETY MINUTES on high-end hardware with 32 GB of DDR4 RAM and NVMe SSDs11:16
lkclby contrast11:16
Las[m]lkcl: I meant building the *data* used11:16
Las[m]as in11:16
Las[m]producing it11:16
lkclalliance-check-toolkit takes around 20 minutes11:16
lkclwhat do you mean by "data"?11:16
Las[m]You told me that you have some data you've generated and committed to that repository11:17
lkcldo you mean "the HDL verilog"?11:17
Las[m]Likely yeah11:17
lkclyes, HDL verilog which was auto-generated by litex11:17
lkcl1 sec11:17
Las[m]How do you get that?11:17
Las[m]BTW, what hardware are you using that `` takes around 20 minutes?11:18
lkcl4.8 ghz 8-core i9, 64 GB of 2400 mhz DDR4 RAM, and a 2 TB 2500 MB/s NVMe SSD11:18
lkcla donated laptop that cost USD *FIVE THOUSAND*11:19
lkclin the libresoc-litex git repo, run "make ls1804k"11:19
lkclthat will run the peripheral generator11:20
lkclthe step before_ that_ is to run this:11:20
lkcl"make ls180_4k_verilog"11:20
Las[m]lkcl: My Ryzen 5 1600 with 16 GB of RAM and some slow NVMe SSD took the same amount of time lol11:21
Las[m]Are you sure your laptop isn't throttling?11:21
lkclthat runs the nmigen-to-verilog conversion on the SoC, generating the core11:21
Las[m]I don't think it even took 20 minutes for ``11:21
lkclLas[m], most things are only run single-core11:21
lkcland yes, it usually throttles due to temperature11:21
Las[m]Well that explains that11:22
lkclor, more to the point, i deliberately throttle it so that the laptop doesn't overheat11:22
Las[m]I think it's a nice laptop, but I honestly think laptops like that are a bad design choice11:22
Las[m]Just get a good stationary desktop which you can SSH into with your cheap laptop11:22
lkcli can't carry a desktop machine on an airplane11:22
lkcland i move locations typically once every eight months11:23
Las[m]You can ssh from airplanes nowadays11:23
lkclthat's about 80 times so far11:23
lkclso, first step:11:23
lkclbuild the verilog from nmigen11:23
lkclsecond step:11:24
lkclbuild the litex peripheral set11:24
lkclthird step:11:24
lkclcopy that into the soclayout11:24
lkclfourth step:11:24
lkclcompile it to GDS-II11:24
lkclJean-Paul Chaput advised taking a snapshot of the full auto-generated source so that it's fully reproducible11:25
lkclghostmansd, all good with fixedstore11:26
lkclwill double-check with a manual read-through, and cherry-pick them over11:26
lkclerr ah ok you've already updated the master branch.11:27
lkcli'll do a read-through then, just to make sure11:28
lkclyep, all good. very simple/straightforward11:29
ghostmansdlkcl: thank you! I hope to dedicate some time today to update comparisons.11:31
ghostmansdLikely in the evening, when all the family falls asleep :-D11:31
lkclghostmansd: star. that one's intriguing. cmpeqb is particularly odd and needs special-casing11:32
ghostmansdSometimes I feel like I'm doing something against the law, given the time and modus operandi11:32
lkclsorry, cmprb. the range-comparison one11:32
lkclit's really odd, isn't it?11:32
lkcli get that all the time11:32
ghostmansdYep. Like I'm a real gangsta, not a monkey-coder11:33
lkcllike, "are we even allowed to do something that is basically telling Intel, ARM, NVIDIA, AMD: you don't control everything any more"?11:33
lkclnobody's stopped us so far, and NLnet's even paying for it, so... pffh :)11:34
ghostmansdlol, they're kinda like Moriarty, if we continue this analogy11:39
ghostmansdBTW so far nobody reached me from NLnet11:39
ghostmansdShould I reach them on my own?11:40
lkclah, right, ok, so there's an RFP process, we have to write (and email them). they deal with 100 projects so don't exactly have the time to contact people11:44
lkclha, great.  page has this, i can jump straight to the bugreports. excellent11:45
lkclghostmansd, i've sent you the RFP template for both12:05
lkclif you can fill them in and cc maciej then that saves him some work and he'll be happy12:06
lkclbecause they're 50-50 (for this one) so he can literally send the exact same email with a different bank account and address12:06
lkclbut please send *me* the RFP for review *BEFORE* sending it to NLnet12:07
lkcljust without your home address and bank account12:07
lkcldid you get a transferwise online bank account? i can't remember12:08
lkclif you haven't, do use this link
kylelgrretings lkcl13:34
lkclkylel, hii13:48
kylelWell where to now?13:48
lkclyou've been over that "first steps" thing? made some changes to the pseudocode and then got the corresponding unit test to "pass"?13:49
lkcl(then put it back again obviously :) )13:50
kylelYeah, he did nice work on that article.13:50
lkclyeh it's really readable.13:50
* lkcl trying to think13:51
lkclwe're missing some unit tests on rotate operations, i think13:51
lkclthere's a stack of them for running the HDL13:52
lkclbut none for testing the simulator13:52
lkclwhere we check the *actual* results13:52
lkclrather than assume that either the simulator *or* the HDL is correct13:53
lkclhow do you bootstrap up from that situation?13:53
lkclhow do you verify a simulator which is going to be used to confirm functionality (by comparison)... that the simulator *itself* is correct?13:53
lkclwe have these13:54
lkclbut nothing _here_13:55
lkclwhich checks that the results of shift operations in the *simulator* are actually correct13:55
lkcl"boring" as it is, it's actually extremely important. if we can't rely on the simulator, that it gets correct results, we're pretty much royally screwed13:59
kylelAt this stage in my life, I find boring good sometimes ;-)13:59
lkclboring but strategically critically important, remember?14:00
lkclso we need a test_caller_shiftrot.py14:00
kylelIndeed.  A screwup here is quite costly.14:00
kylelAnd I was just going to ask so in short, a test caller.14:00
lkcllike... "USD 6 million on production mask" costly14:00
lkclif you wanted something a bit more "exciting" we have a long-term goal of abstracting out the entire unit test infrastructure14:01
lkclso that there's:14:01
lkcl* a set of expected results14:01
lkcl* a "way-to-call-anything-that-executes-Power-ISA"14:01
lkcl* a "runner-of-said-executer" in a step-by-step fashion (one instruction at a time)14:02
lkcl* a "comparator-of-two-or-more-such-steppers"14:02
lkcl* a "comparator-against-the-above-mentioned-expected-results"14:02
lkclthe idea here being, there's a standard API by which we can check execution against *qemu*14:03
lkclor... microwatt14:03
lkclor... power-gem514:03
lkclor... ssh-into-an-IBM-POWER9-system-and-remote-gdb-single-step14:03
lkclbut before that i'd suggest first actually getting used to the existing infrastructure14:04
lkclwhich *can* already run co-simulation single-stepping against qemu (horribly slowly, mind)14:04
lkclyou can see a very very basic function, "check_regs"14:05
lkclanother version of that same function, here, which isn't even called (sigh)14:05
lkclinstead, you can see a bunch of manual self.assertEqual() calls14:05
lkclwhich, guess what, is the brain-dead way to do it14:06
kylelso a rot caller it is14:08
kylela good exercise14:09
lkclbtw i'm just splitting out ISATestRunner into decoder/isa/test_runner.py14:09
lkclso there's no danger of accidentally copying ISATestRunner (formerly in multiple times by accidental cut/paste14:12
lkclkylel, feel free to make it *real* boring, by literally by-rote copying each case from shift_rot_cases.py14:13
lkclhowever if you make it "generic" (random input, rather than fixed values) you'll probably likely need to write a python-based version of the Power ISA shift-rot operations14:14
lkclwhich... well... if you choose to do that, i don't mind at all, but if you do, please do cross-reference them in the comments to the relevant Power ISA v3.0B specification section and page number14:14
lkcl"""rwlwinm implementation for test purposes.  implements Power ISA v3.0B Book I Section p102"""14:17
kylelGot an example for that?14:18
lkcli don't mind either way, if you do something "brain-dead" (fixed, static values) or a more generic version14:18
lkclwell, the majority of tests are brain-dead static values14:18
lkcle.g.  1 sec14:18
lkcli mean, we _know_ 0x1234 + 0x4321 = 0x5555 so, duh, it's blindingly obvious14:19
lkclbut for when i did the SVP64 Discrete Cosine Transform whoooaaaa14:20
lkclno way was i going to calculate a DCT "by hand"14:20
lkclso i wrote a python-version of DCT (actually, adapted Nayuki's simple DCT code)14:20
lkcland extracted the "expected" values after running the simulator14:21
lkclcompare expected against actual, if false assert.14:21
lkclso does that give you some increasing levels of sophistication to choose from, and work towards?14:22
kylelYes indeed, thank you.14:23
lkclok cool. need food here.14:23
kylelQuick question, why the change to xlen?14:23
lkclahh quick question, but not quick answer :)14:24
kylelahh no biggie, go eat ;-)14:24
lkclSVP64 has the ability to *override* the register width14:24
lkcl1 sec, finding link...14:24
lkclthat one's an important document for understanding the (DRAFT) Vector System we're dropping on top of Power ISA v3.0B as the scalar "base".14:25
lkcllook up the x86 "REP" instruction, for the basic concept, then "inject" that concept with a massive boost of Cray-style Vector steroids14:26
ghostmansd-pcswitched test_caller_bcd.py17:53
ghostmansd-pchm, not yet, gotta think about pdecode instance17:54
ghostmansd-pcok, test_caller_bcd tests are in progress... checking test_caller meanwhile...18:01
ghostmansd-pcboth test_caller and test_caller_bcd work; had to teach run_tst to take custom pdecode2 instance18:10
ghostmansd-pcpushed into master18:10
ghostmansd-pcA question on comparisons. Based on L field, the operation is either on 32-bit values (if L=0), or 64-bit (L=1). Should we do the following: if L=0, operate on half of XLEN, otherwise operate on full XLEN?18:21
lkclghostmansd-pc: ahh excellent. hmm we had that at one point already... ah ha! ok i see18:35
ghostmansd-pccmprb would work only on 32-bit and 64-bit based on what I see18:36
lkclpassing in a pdecode2 as an option, excellent18:36
lkclyes, totally.18:36
ghostmansd-pcand cmpeqb, as you mentioned, must be rewritten18:36
lkcllet me just check again18:36
ghostmansd-pcat the same time... specs explicitly mention the behavior is undefined in 32-bit mode18:37
lkclcmprb would work when elwidth=32/elwidth=6418:37
lkclbut be "UNDEFINED" if elwidth=16/818:37
lkclso it would still be the "XLEN-8:XLEN-1" trick18:38
ghostmansd-pc> cmprb would work when elwidth=32/elwidth=6418:38
ghostmansd-pcyep, that's what I said :-)18:38
lkclcmpeqb on the other hand could use a loop for i = 0 to (XLEN/8)-118:39
lkclreducing down to a single-byte "cmp" on elwidth=818:39
ghostmansd-pcah, I see...18:40
lkclcmpli, L=0/1, using half of XLEN? that's a really good idea18:40
ghostmansd-pcso we compare as much bytes as available in RB, but always take only one byte from RA?18:41
lkcli can see that being very useful, even for elwidth=8, where you check only 4 bits18:41
ghostmansd-pcyou might opt to take a look at xlen branch18:41
lkclyes, as many bytes... ah ok :)18:41
ghostmansd-pcI've just updated it18:41
ghostmansd-pcwill now check the test_issuer.py18:41
lkclcmpli great18:42
ghostmansd-pcFWIW... why on Earth they all are called fixed${something}, but we also have comparefixed?18:43
lkcli don't know!18:44
lkcla minor fault in reality?18:44
* lkcl running test_cr_compunit.py18:45
lkclall good18:45
lkclnow to actually check whether cmpli etc are in it :)18:45 is in progress18:45
lkcl./test/alu/    def case_cmpeqb(self):18:46
lkcl./test/alu/        lst = ["cmpeqb cr1, 1, 2"]18:46
ghostmansd-pcoops, forgot to update cmpeqb18:46
ghostmansd-pcloop needed18:46
* lkcl reading the diffs...18:46
lkclcmpli looks good18:47
lkclcmp looks good18:47
lkclcmpl sorry, right, yes, looks good18:48
lkclcmpli... complicated... ah. right.  that will break when elwidth=818:48
lkclXLEN-16 will go *negative* when XLEN=818:50
lkcldrat.  drat-drat-drat.  are there any others like that?18:50
ghostmansd-pcforce updated xlen with cmpeqb18:51
ghostmansd-pcbut actually actually only cmprb and cmpli are not "flexible"18:52
lkclfind . -name "*.mdwn" | xargs grep "XLEN-16"18:52
lkclfixedload and fixedstore, those are UNDEFINED behaviour ones18:52
lkclthere's a couple of fixedlogical ones18:53
ghostmansd-pcthat's why I bothered so much about the semantics :-)18:53
ghostmansd-pcwhether they should operate on 1/4 of register, or should deal with 16 bits18:54
lkclandi, ori, xori18:54
lkclok will raise a separate bugreport for all these18:54
ghostmansd-pcbecause, well, if we'd written the spec, I'd rather go with 1/4 of register18:54
lkclcmpl looks good18:55
ghostmansd-pc(which becomes 2 bits in 8, but hey)18:55
lkclcmprb looks good18:55
lkclwell, we have to think, "is that useful"?18:55
lkclfor a Vector Processor / 3D GPU18:56
ghostmansd-pcperhaps dealing with nibbles on 16-bit might sometimes be, but I wouldn't bet on it18:56
lkclwhich is going to be doing 3D Shader binaries (games etc.), Video Processing, etc.18:56
lkcland probably (sigh) AI18:57
ghostmansd-pcwell, those actually tend to use things like BF16 and FP1618:57
ghostmansd-pcso yep, operations on individual 16-bit values might be good18:57
ghostmansd-pcthough they generally prefer to operate on pack of those18:58
lkclfunny that, we're adding BF16/FP1618:58
ghostmansd-pce.g FMA18:58
lkclfunny that, we're allowing Vectorised FP16/BF16...18:59
ghostmansd-pctest_issuer is still running...18:59
ghostmansd-pcnever surrender18:59
lkcli'm doing and test_alu_compunit.py18:59
lkclthey run waaay quicker18:59
ghostmansd-pcthat's OK when you know what to launch :-)19:00
lkclnow you do, too19:00
ghostmansd-pcsince I lacked this information, I chose the obvious option19:00
lkclcmpeqb failed19:00
lkclwell, i actually didn't know19:00
lkcli did "find . -name "*.py" | xargs grep cmpeqb"19:00
ghostmansd-pcdid you take the recent one?19:01
lkcland test/alu/ came up19:01
lkcli believe so, yes.19:01
lkclwhoops didn't run pywriter noall fixedarith19:01
ghostmansd-pclooks like the loop is the cause19:02
ghostmansd-pcI checked on version which I forgot to update19:02
lkclurr i'm not seeing a cmpeqb here19:03
ghostmansd-pcit got merged with the last commit19:04
lkclwhoops :)19:04
lkcli'd use an if statement there19:05
lkclif src1=RB[..] match <- 119:05
lkclon one line19:05
lkclohhh i see19:05
ghostmansd-pcplease re-check19:05
lkclmatch <- 0b119:05
ghostmansd-pcmatch should be 019:06
lkclas the initial var.... yes :)19:06
ghostmansd-pcshared mind19:06
ghostmansd-pcpushed the update19:06
lkclgot it19:06
lkclran pywriter on fixedarith by mistake sigh19:06
ghostmansd-pcit's all that damned guide!19:07
lkclall good19:07
ghostmansd-pcI also hit the same issue19:07
lkclit's pressing up-arrow on a bash terminal not enough times wot dunnit19:07
ghostmansd-pcafter writing that tutorial I kept writing fixedarith for a while19:07
lkclall good19:07
ghostmansd-pc  File "/usr/lib/python3.9/unittest/", line 500, in subTest19:08
ghostmansd-pcAttributeError: 'NoneType' object has no attribute 'success19:08
ghostmansd-pcpython3 ./src/soc/fu/compunits/test/test_cr_compunit.py19:08
ghostmansd-pcah, it looks like it hit ctrl+c19:08
lkcloh well that's ok then19:08
lkclok happy with those, to push over to master branch when you're ready19:09
lkcli'll run here as well19:09
lkclbtw you're running it with the nosvp64 option right? saves a loootta time19:10
ghostmansd-pcchecked cr_compunit19:10
ghostmansd-pcchecking test_issuer19:10
ghostmansd-pcthanks for reminder on nosvp6419:10
lkcland also test_alu_compunit.py19:10
ghostmansd-pclast time ran w/o it19:10
ghostmansd-pcdoesn't test_issuer include test_alu_compunit and test_cr_compunit?19:11
* lkcl trying to remember why cmpeqb is in ALU19:11
lkclit does19:11
lkclbut it also includes.... logical ldst general branch etc. etc. etc.19:11
lkcldiv mul... it's why it takes ages19:11
ghostmansd-pcah, ok, so test_alu_compunit and test_cr_compunit are for quick checks, gotcha19:12
lkclmuch quicker because they don't even deal with regfiles.19:12
lkclthey're literally testing a raw pipeline19:12 all good19:23
ghostmansd-pctest_issuer works19:26
ghostmansd-pcok, I'm now rebasing the master19:26
ghostmansd-pcso far so good19:28
ghostmansd-pcwhat our next steps?19:28
ghostmansd-pcI've been thinking of madd tests19:28
ghostmansd-pcbut I'm open to your suggestions19:28
lkclyyeah they're not implemented in the HDL at the moment19:28
lkclso yes would need some openpower-isa unit tests before being able to proceed19:28
lkclgo for it, raise a bugreport (or see if one exists)19:29
lkclmake sure to always cross-ref to at least one other vaguely-relevant bugreport19:29
ghostmansd-pcI guess most of things we dealt with don't have tests in openpower-isa, except for fixedarith19:29
lkclah 681 already exists19:30
lkclit's a bit sporadic / piecemeal19:30
lkclone of the reasons i asked kylel if he could do some shiftrot ones19:31
ghostmansd-pcyep, got it19:31
* lkcl will check what else needs converting19:32
ghostmansd-pcI think I'll start with madd and will also re-visit those I modified for XLEN19:32
ghostmansd-pcah, yes19:32
ghostmansd-pctotally forgot about it19:32
ghostmansd-pcthese are a bit weird19:32
ghostmansd-pc(well, we knew it, but this time I'm not about semantics)19:33
ghostmansd-pcthese deal with AT LEAST 12 or 10 bits at once19:33
ghostmansd-pcgenerally speaking, as many 10/12 bits as fits in the register19:33
ghostmansd-pcso I suspect xlen=8 is already the outsider19:34
lkclthat's going to be fun19:34
ghostmansd-pcas for xlen=16, it's up to 119:34
lkclwhere the heck is isel19:34
ghostmansd-pcwhat's isel?19:34
lkclreturn a ? b : c19:35
lkcltwi and tdi need converting to XLEN/219:36
* lkcl need to get up and walk about19:38
ghostmansd-pcem, tdi doesn't have bits19:38
ghostmansd-pcother than TO[XXX], which I have no idea what means19:38
ghostmansd-pctwi has it, though19:38
ghostmansd-pcsame is tw19:39
ghostmansd-pcthis makes tw and twi19:39
lkclyes i meant tw and twi sorr20:14
ghostmansdlkcl: I already have transferwise account, but it's tied to my primary e-mail21:15
lkclyes, a transferwise *account* is not the same as a transferwise *bank* account.21:38
lkclNLnet can make wire transfers directly to a transferwise *bank* account with zero bank transfer fees incurred... *if* that transferwise *bank* account is in Europe.21:39
lkclwhich you can do - online - by applying for a transferwise *bank* account and asking for it to be in EUR21:39
lkclif you choose to do that, you get more $ (no bank transfer fees)21:40
rscWell, bank transfers must be free when sender's and recipient's banks are in SEPA region and both bank accounts are hold in EUR currency.21:42
rscAnd note, SEPA != Europe.21:43
rsc(and of course the sender has no way to figure out in which currency the recipient's account is hold)21:44
lkclwhiich is why, registering on transferwise for a *bank* account and applying for a EUR currency *bank* account results in zero transfer fees.21:48
lkclthx rsc21:48
rscYes. But usually (German) banks are charging for additional bank accounts.21:48
rsc(not to forget for devise bank accounts, e.g USD)21:48
rscAnd if you're in non-EUR, but SEPA, these banks usually charge separately for EUR bank account ;-(21:49
ghostmansdI _think_ I have some account in EUR22:44
ghostmansdI'm not sure whether it's bank or not, but I have some fields like IBAN and BIC, along with my name22:45
ghostmansdThere are even options for those, including SEPA22:46
ghostmansdActually I will have to pay some fees anyway, since ultimately one day I'll have to convert it to national currency :-)22:46
ghostmansdI think what I have is called "Euro account"22:48
lkclok that sounds perfect22:52
lkclyes, but at least with transferwise they charge the middle rate22:52
ghostmansdWhen I check the requisites, they tell there are two options, one for European Union/ SEPA zone, and one for outside22:52
ghostmansdOr should I say "for outsiders", lol22:52
ghostmansdI guess fees-wise, that'd be the latter22:53
ghostmansdSo, if I understood correctly, I must supply the EU/SEPA details to NLNet?22:54
lkclthat would be better, yes.22:54
ghostmansdoff-topic: Luke, what do you think of XLEN-based logicals? I really would like to avoid a custom case for XLEN=8.22:55
lkclyehhh i know22:55
ghostmansdThat said, 2 bits for XLEN=8 is strange as well...22:55
lkclit's likely unavoidable, because xori for XLEN=8 is actually useful22:55
ghostmansdBut at least fits the overall idea22:55
ghostmansdBut they ultimately concatenate bits22:55
ghostmansdEven if we use 8 bits of UI, that, along with other concatenated, makes more than 8 bits22:56
ghostmansdOr do you suggest to take 8 bits of result?22:56
lkclexactly, which means the concatenation has to go...22:56
lkcl... yes22:56
ghostmansdIt'd be great if you wrote an example22:57
lkcleffectively it's reg[0..7] XOR UI[0..7]22:57
ghostmansdAnd, especially, the intended use case22:57
lkclor (sigh) reg[0..7] XOR UI[8:15] because UI will still be 16-bit and in MSB0 numbering you grab the lower byte with 8..1522:58
ghostmansdWhenever possible, it'd be great to have a unified semantics.22:58
ghostmansdThat's why I thought of crap like "take 1/4 of width"22:58
lkclif XLEN=8 then22:59
lkcl    RA <- (RS) ^ UI[8:15]22:59
ghostmansd"then take owl eyes, bat wings, throw in a bowl,  and wait for a full moon"22:59
lkclexcept that's meaningless / not useful unfortunately.23:00
* lkcl cackles23:00
ghostmansdYep, usability is really limited :-D23:00
ghostmansd2 bits per poor man23:01
ghostmansd"I took 2 bits of those 16 you used to encode the instruction"23:01
ghostmansdI guess they'd say the ISA is implemented by total assholes23:01
lkclor we took acid23:02
ghostmansdIndeed, that'd explain such ISA23:02
ghostmansdI liked the MP23:02
ghostmansdQuite well explanatory23:02
ghostmansdI meant the reference you posted23:03
* lkcl was wondering what MP was...23:03
ghostmansdPerhaps should be present in Appendix C23:03
lkcloh you mean the monty python youtube video?23:03
lkclha i must find something...23:03
ghostmansdMonty Python23:03
ghostmansdmscdfr - Means Something Completely Different For r023:04
ghostmansdI wish something like this is done for x8623:05
lkclthere really is an instruction "eieio" in ppc6423:05
ghostmansdcast programmerjake!23:05
ghostmansdvcfucc is instruction of our choice23:06
lkcltrap word extended and rotate keyboard23:06
ghostmansdThat's actually brilliant23:06
lkclthere's also a ppc64 instruction called "dozi"23:06
ghostmansdI guess we have a reference guide, lol23:06
lkclfor real23:07
lkcldifference or zero immediate23:07
lkclsadly it's been retired around Power ISA v2.0723:07
ghostmansdSuch an opportunity lost...23:08
ghostmansdDidn't quite get, is it some kind of barrier?23:09
jnghostmansd: exists, but it contains other chatter besides funny instruction names23:10
ghostmansdWith a moo-moo here and a moo-moo there23:10
ghostmansdLol, that's probably the best23:13
ghostmansdOk it's 1 AM here23:14
ghostmansdShould have some rest23:14
ghostmansdThanks for moments of good and healthy laugh (probably not, since, sigh, only real psychopaths like programmers can laught at this, most people would really struggle at this)23:17
jneh, don't worry, programmer culture is culture too :)23:19

Generated by 2.17.1 by Marius Gedminas - find it at!