<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"><meta name=Generator content="Microsoft Word 15 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Consolas;
        panose-1:2 11 6 9 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
pre
        {mso-style-priority:99;
        mso-style-link:"HTML Vorformatiert Zchn";
        margin:0cm;
        margin-bottom:.0001pt;
        font-size:10.0pt;
        font-family:"Courier New";}
span.HTMLVorformatiertZchn
        {mso-style-name:"HTML Vorformatiert Zchn";
        mso-style-priority:99;
        mso-style-link:"HTML Vorformatiert";
        font-family:Consolas;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:70.85pt 70.85pt 2.0cm 70.85pt;}
div.WordSection1
        {page:WordSection1;}
--></style></head><body lang=DE-CH link="#0563C1" vlink="#954F72" style='word-wrap:break-word'><div class=WordSection1><p class=MsoNormal><span lang=EN-US>Jeff<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-US>In addition to Chris’ reply. Here a minimum implementation of Install*(handler: PROCEDURE); <o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US>      SYSTEM.LDPSR(0);                                                                   (* disable/clear interrupt *)<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US>      Kernel.Install(SYSTEM.VAL(INTEGER, handler), 4);      (* install the interrupt handler at memory address 4 *)<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US>      SYSTEM.LDPSR(1);                                                                   (* enable/set interrupt *)<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US style='mso-fareast-language:EN-US'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-US style='mso-fareast-language:EN-US'>LDPSR is the abbreviation for “load processor status register”. The last bit of this status register is “interrupt: on/off”<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US style='mso-fareast-language:EN-US'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-US style='mso-fareast-language:EN-US'>As interrupts begin and end differently than “normal” procedures, and it has bad consequences if you install a “normal” procedure as interrupt handler, I decided to check that the parameter “handler” is really an interrupt procedure. To do this I check the procedure’s prolog. Here the start of the prolog (=the code the compiler generates when it sees a BEGIN)<br>  normal proc:                  interrupt proc:<br>  SUB SP SP localsize       SUB SP SP localsize<br>  STW LNK SP 0                STW R0 SP 0<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US style='mso-fareast-language:EN-US'>  ….                                    …<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US style='mso-fareast-language:EN-US'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-US style='mso-fareast-language:EN-US'>The first instruction is the same but the second instruction differs.<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US style='mso-fareast-language:EN-US'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-US>      SYSTEM.LDPSR(0);                                                                                   (* disable/clear interrupt *)<o:p></o:p></span></p><p class=MsoNormal style='margin-left:283.2pt;text-indent:-283.2pt'><span lang=EN-US>      Kernel.Install(SYSTEM.ADR(Empty), 4);                                           (* see below *)<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US>      SYSTEM.GET(SYSTEM.VAL(INTEGER, handler)+4, instr);           (* get second instruction of the “handler” code. If “handler” is NIL the check below is never true *)<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US>      IF instr = 0A0E00000H THEN (* valid interrupt handler *)       (* check for STW R0 SP 0 *)<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US>        Kernel.Install(SYSTEM.VAL(INTEGER, handler), 4);                   (* install interrupt handler at memory address 4 *)<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US>        SYSTEM.LDPSR(1)                                                                                  (* enable/set interrupt *)<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US>      END<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US style='mso-fareast-language:EN-US'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-US>The “Empty” interrupt is a precaution in case the programmer’s interrupt handler is not valid or NIL and the programmer would code a SYSTEM.LDPSR(1) on his own after Install(). I could put this code in the ELSE.<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US style='mso-fareast-language:EN-US'><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-US style='mso-fareast-language:EN-US'>Instead of </span><span lang=EN-US>SYSTEM.GET(SYSTEM.VAL(INTEGER, handler)+4, instr);  the compiler would also accept the shorter SYSTEM.GET(ORD(handler)+4, instr);<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US>As the Oberon report does not define ORD() on procedure variables, I use the “official” way of doing it.<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p><p class=MsoNormal><span lang=EN-US>br<o:p></o:p></span></p><p class=MsoNormal><span lang=EN-US>Jörg<o:p></o:p></span></p><p class=MsoNormal><span style='mso-fareast-language:EN-US'><o:p> </o:p></span></p><div style='border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0cm 0cm 0cm'><p class=MsoNormal><b><span style='font-size:12.0pt;color:black'>Von: </span></b><span style='font-size:12.0pt;color:black'>Oberon <oberon-bounces@lists.inf.ethz.ch> im Auftrag von Jeff Maggio <jmaggio14@gmail.com><br><b>Antworten an: </b>ETH Oberon and related systems <oberon@lists.inf.ethz.ch><br><b>Datum: </b>Donnerstag, 6. Mai 2021 um 22:20<br><b>An: </b><oberon@lists.inf.ethz.ch><br><b>Betreff: </b>[Oberon] Stimulus driven interrupts?<o:p></o:p></span></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><div><pre style='white-space:pre-wrap'><span style='font-family:"Arial",sans-serif;color:black'>Gray - that would be fantastic! I'd love to look more into it</span><span style='color:black'><o:p></o:p></span></pre></div><div><pre><span style='color:black'><o:p> </o:p></span></pre></div><div><pre><span style='color:black'>Jorg - thank you, that module simplifies things a lot. Would it be possible for you to walk me through how it works in more detail? I'm not following every line - for instance what does SYSTEM.LDPSR do?<o:p></o:p></span></pre></div><div><pre><span style='color:black'><o:p> </o:p></span></pre></div><div><pre><span style='color:black'><o:p> </o:p></span></pre></div><blockquote style='border:none;border-left:solid #CCCCCC 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-right:0cm'><pre><span style='color:black'>Adding to Jörg's post, below, I have a simple eight channel interrupt controller in the FPGA hardware as "front end" to the single interrupt of the RISC5 CPU, including the corresponding Oberon driver of course. It adds one clock cycle of latency, IIRC. Let me know if you're interested. It requires some minor changes to the RISC5 CPU, though.<o:p></o:p></span></pre><pre><span style='color:black'>-- gray<o:p></o:p></span></pre></blockquote><blockquote style='border:none;border-left:solid #CCCCCC 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-right:0cm'><pre><span style='color:black'>On Thu, 6 May 2021, at 19:53, Joerg wrote:<br>><i> Hi Jeff<o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i>  <o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i> The interrupt signal is handed over by the HW to the RISC5 CPU in RISC5Top.v.<o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i> The interrupt signal in the CPU is called .irq, and the current RISC5Top.v hands over periodic interrupts with the Verilog code below<o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i> RISC5 riscx(.clk(clk), .rst(rst), *.irq(limit),*<o:p></o:p></i></span></pre><pre><span style='color:black'>><i>    .rd(rd), .wr(wr), .ben(ben), .stallX(vidreq),<o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i>    .adr(adr), .codebus(codebus), .inbus(inbus),<o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i>         .outbus(outbus));<o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i>  <o:p></o:p></i></span></pre><pre><span style='color:black'>><i> assign limit = (cnt0 == 24999);<o:p></o:p></i></span></pre><pre><span style='color:black'>><i>  <o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i> But you are totally free to set the CPU’s .irq signal on other HW conditions, e.g. a packet on the Ethernet board arrived or the temperature sensor says the meat is tender.<o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i>  <o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i> Below I attached an older mail on an “simple” API to facilitate programming with interrupts. Instead of Kernel.Install you would call Interrupt.Install to install the interrupt handler.<o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i>  <o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i> br<o:p></o:p></i></span></pre><pre><span style='color:black'><o:p> </o:p></span></pre><pre><span style='color:black'>><i> Jörg<o:p></o:p></i></span></pre></blockquote><p class=MsoNormal><o:p> </o:p></p></div><p class=MsoNormal>-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon <o:p></o:p></p></div></body></html>