fst_ptr <- 0 slot1 <- 4 header <- 8 off_oref <- -8 off_osize <- -4 off_next <- 0 off_size <- 4 // memlib - simple memory allocator for ILOC // // This library maintains a single-linked list (of monotonically increasing addresses) of free // slots in memory and a reference count for occupied slots. Each slot contains a tuple `(next // free slot address,size)` followed by `size` free bytes. The memory is initiliased with a // pointer to the first free slot at `#fst_ptr` and one free slot at `#slot1` of size // `brk-slot1-header`. When a piece of memory is requested for allocation, a tuple // `(reference count, size)` followed by `size` bytes for the object is formed. The calling // convention of the functions in this library consists of pushing the return address followed by // any arguments (in order) to the stack. Any return values will be pushed to the stack likewise. // // Requires a register `brk` for the highest address available for heap allocation. // Requires an instruction `halt` when memory runs out // // @author Frank Wibbelink // initialise memlib_: loadI 0 => m_0 loadI @slot1 => m_1 subI brk,@slot1 => m_2 subI m_2,@header => m_2 storeAI m_1 => m_0,@fst_ptr // pointer to first slot storeAI m_0 => m_1,@off_next // next slot is null storeAI m_2 => m_1,@off_size // first slot size jumpI -> ememlib_ // allocate memory // searches through the free slots for either a slot size of ~~exactly #4+8 or a size of~~ at // least #4+16 // stack: [return address, object size] -> [object address] memalloc: loadI 0 => m_0 pop => m_s // load size loadI @fst_ptr => m_p // load previous address (base pointer) loadAI m_p,@off_next => m_c // load current address (first slot) ma_loop: cmp_EQ m_0,m_c => m_1 // check if address pointer is null cbr m_1 -> ma_null,ma_cont // if null, go to end and return null pointer ma_cont: loadAI m_c,@off_size => m_1 // load slot size cmp_EQ m_1,m_s => m_2 // check if request fits exactly cbr m_2 -> ma_yxct,ma_nxct ma_nxct: subI m_1,@header => m_1 // subtract free slot size cmp_GE m_1,m_s => m_1 // check if request fits cbr m_1 -> ma_found,ma_next ma_next: i2i m_c => m_p loadAI m_p,@off_next => m_c jumpI -> ma_loop ma_yxct: loadAI m_c,@off_next => m_n // location of next free slot jumpI -> ma_final ma_found: addI m_s,@header => m_1 add m_1,m_c => m_n // location of new free slot loadAI m_c,@off_size => m_1 subI m_1,@header => m_1 sub m_1,m_s => m_1 // size of new free slot storeAI m_1 => m_n,@off_size loadAI m_c,@off_next => m_1 // location of next free slot storeAI m_1 => m_n,@off_next ma_final: storeAI m_n => m_p,@off_next // link previous free slot to new addI m_c,@header => m_c // move to object location loadI 1 => m_1 storeAI m_1 => m_c,@off_oref // set reference count to 1 storeAI m_s => m_c,@off_osize // set object size ma_zerc: cbr m_s -> ma_zerl,ma_null // zero memory ma_zerl: subI m_s,1 => m_s cstoreAO m_0 => m_c,m_s jumpI -> ma_zerc ma_null: pop => m_1 // load return address push m_c // store object address jump -> m_1 // increase reference count of object // stack: [return address, object address] -> [] memaddref: loadI 0 => m_0 pop => m_n // load object address cmp_EQ m_0,m_n => m_1 cbr m_1 -> mr_ynul,mr_nnul // check if null pointer mr_ynul: haltI 1865445997 mr_nnul: loadAI m_n,@off_oref => m_1 addI m_1,1 => m_1 storeAI m_1 => m_n,@off_oref pop => m_1 // load return address jump -> m_1 // decrease reference count of object // frees memory if count goes to zero // stack: [return address, object address] -> [] memfree: loadI 0 => m_0 pop => m_n // load object address cmp_EQ m_0,m_n => m_1 cbr m_1 -> mf_ynul,mf_nnul // check if null pointer mf_ynul: haltI 1865442925 mf_nnul: loadAI m_n,@off_oref => m_1 subI m_1,1 => m_1 cmp_GT m_1,m_0 => m_2 cbr m_2 -> mf_exit,mf_free mf_exit: storeAI m_1 => m_n,@off_oref pop => m_1 // load return address jump -> m_1 mf_free: subI m_n,@header => m_n loadI @fst_ptr => m_p loadAI m_p,@off_next => m_c mf_loop: cmp_EQ m_0,m_c => m_1 // loop until the surrounding free blocks are found cbr m_1 -> mf_halt,mf_cont // check if address pointer is null mf_halt: haltI 1882220141 // halt program; object beyond last free slot (or memory corrupted) mf_cont: cmp_EQ m_c,m_n => m_1 cbr m_1 -> mf_hal2,mf_con2 mf_hal2: haltI 1717855853 // halt program; object is free slot mf_con2: cmp_LE m_c,m_n => m_1 cbr m_1 -> mf_next,mf_done mf_next: i2i m_c => m_p loadAI m_p,@off_next => m_c jumpI -> mf_loop mf_done: loadAI m_p,@off_size => m_1 addI m_1,@header => m_1 add m_1,m_p => m_2 cmp_EQ m_2,m_n => m_2 cbr m_2 -> mf_yprv,mf_nprv mf_yprv: loadAI m_n,@off_size => m_2 // merge with previous free slot add m_1,m_2 => m_1 // new size of previous free slot storeAI m_1 => m_p,@off_size i2i m_p => m_n jumpI -> mf_dprv mf_nprv: storeAI m_n => m_p,@off_next // link previous free slot with new mf_dprv: loadAI m_n,@off_size => m_1 addI m_1,@header => m_1 add m_1,m_n => m_2 cmp_EQ m_2,m_c => m_2 cbr m_2 -> mf_ynxt,mf_nnxt mf_ynxt: loadAI m_c,@off_size => m_2 // merge with next free slot add m_1,m_2 => m_1 // new size of next free slot storeAI m_1 => m_n,@off_size loadAI m_c,@off_next => m_1 storeAI m_1 => m_n,@off_next // move link of next's next to new free slot pop => m_1 // load return address jump -> m_1 mf_nnxt: storeAI m_c => m_n,@off_next // link new free slot with next pop => m_1 // load return address jump -> m_1 // copy object to location // stack: [return address, object address, destination] -> [] memcopy: loadI 0 => m_0 haltI 1835626101 // unimplemented pop => m_1 // load return address jump -> m_1 ememlib_: nop // end of memlib // stdlib - generic subroutines for ILOC // // This library contains a few common subroutines for Boppi. // // @author Frank Wibbelink // initialise stdlib_: jumpI -> estdlib_ // write a boolean to output // stack: [return address, bool] -> [] stdbout: pop => m_1 // get boolean loadI 0 => m_2 // load zero-length string push m_2 cbr m_1 -> sbout_t,sbout_f sbout_t: cout "true" jumpI -> sbout_e sbout_f: cout "false" sbout_e: pop => m_1 // load return address jump -> m_1 // write an array of characters (a string) to output // stack: [return address, address] -> [] stdsout: pop => m_1 // get address loadAI m_1,@off_osize => m_2 // get length sout_lc: cbr m_2 -> sout_ll,sout_le // check if any character to push sout_ll: subI m_2,1 => m_2 // iterate backward cloadAO m_1,m_2 => m_c // get character cpush m_c // push character jumpI -> sout_lc // repeat sout_le: loadAI m_1,@off_osize => m_2 // get length push m_2 // push string length cout "" // print string pop => m_1 // get return address jump -> m_1 // read a character from input // stack: [return address] -> [char] stdcin: cin "" // get line pop => m_1 // get length cbr m_1 -> scin_t,stdcin // repeat until at least one character scin_t: cpop => m_2 // save character scin_lc: subI m_1,1 => m_1 // decrement char count cbr m_1 -> scin_ll,scin_le scin_ll: cpop => m_0 // discard character jumpI -> scin_lc // repeat scin_le: loadI 0 => m_0 // reset zero register pop => m_1 // get return address cpush m_2 // push result character jump -> m_1 // read an array of characters (a string) from input // the memalloc label cannot be used, so address 28 is used instead // stack: [return address] -> [address] stdsin: cin "" // get line pop => m_2 // get length push m_2 // save length loadI #ssin_a => m_1 // call malloc push m_1 // call malloc push m_2 // call malloc loadI 28 => m_c // call malloc jump -> m_c // call malloc ssin_a: pop => m_1 // get array address pop => m_2 // get length i2i m_1 => m_n // load character iterator ssin_c: cbr m_2 -> ssin_l,ssin_e // pop characters into the array ssin_l: subI m_2,1 => m_2 cpop => m_c // pop character cstore m_c => m_n // save character addI m_n,1 => m_n // increment iterator jumpI -> ssin_c ssin_e: pop => m_2 // get return address push m_1 // push array address jump -> m_2 estdlib_: nop // end of stdlib loadI 0 => r_nul // initialise zero register loadI 217 => r_arp // malloc push r_arp // malloc loadI 28 => r_arp // malloc push r_arp // malloc jumpI -> memalloc // malloc pop => r_arp // malloc addI r_arp,16 => r_arp // construct main AR jumpI -> s0 // define f1 - jump over body nop // define f1 - entry point addI r_arp,0 => r_1 // add offset load r_1 => r_1 // load address storeAI r_1 => r_arp,-12 // define f1 - move result loadAI r_arp,-8 => r_2 // load ref count loadI 1 => r_1 // one cmp_LE r_2,r_1 => r_2 // check more than one ref cbr r_2 -> ycl1,ncl2 // remove vars if last reference ycl1: nop // cleanup target ncl2: nop // no cleanup target loadAI r_arp,-8 => r_1 // define f1 - load return address jump -> r_1 // define f1 - go to return address s0: nop // define f1 - skip target loadI 238 => r_1 // malloc push r_1 // malloc loadI 12 => r_1 // malloc push r_1 // malloc jumpI -> memalloc // malloc pop => r_1 // malloc loadI 220 => r_2 // define f1 - load target address storeAI r_2 => r_1,0 // define f1 - set target address storeAI r_arp => r_1,4 // define f1 - copy ARP loadI 20 => r_2 // define f1 - load AR size storeAI r_2 => r_1,8 // define f1 - set AR size storeAI r_1 => r_arp,4 // define f1 - set function reference i2i r_arp => ART // AR incRef cmp_NE ART,r_nul => r_1 // AR incRef cbr r_1 -> aril3,arid4 // AR incRef aril3: loadI 253 => r_1 // AR incRef push r_1 // AR incRef subI ART,16 => r_1 // AR incRef push r_1 // AR incRef jumpI -> memaddref // AR incRef loadAI ART,-16 => ART // AR incRef cmp_NE ART,r_nul => r_1 // AR incRef cbr r_1 -> aril3,arid4 // AR incRef arid4: nop // AR incRef loadI 0 => r_1 // false cbr r_1 -> if_t5,if_e7 // if_t5: nop // addI r_arp,4 => r_1 // add offset load r_1 => r_1 // load address loadI 266 => r_3 // memaddref push r_3 // memaddref push r_1 // memaddref jumpI -> memaddref // memaddref loadAI r_1,4 => r_2 // add new reference i2i r_2 => ART // AR incRef cmp_NE ART,r_nul => r_3 // AR incRef cbr r_3 -> aril8,arid9 // AR incRef aril8: loadI 275 => r_3 // AR incRef push r_3 // AR incRef subI ART,16 => r_3 // AR incRef push r_3 // AR incRef jumpI -> memaddref // AR incRef loadAI ART,-16 => ART // AR incRef cmp_NE ART,r_nul => r_3 // AR incRef cbr r_3 -> aril8,arid9 // AR incRef arid9: nop // AR incRef addI r_arp,0 => r_2 // add offset load r_2 => r_3 // load reference cmp_EQ r_3,r_nul => r_4 // remove old reference cbr r_4 -> ynul10,nnul11 // remove old reference nnul11: nop // remove old reference loadI 288 => r_4 // free push r_4 // free push r_3 // free jumpI -> memfree // free loadAI r_3,4 => r_3 // remove old reference i2i r_3 => ART // AR decRef cmp_NE ART,r_nul => r_4 // AR decRef cbr r_4 -> ardl12,ardd13 // AR decRef ardl12: loadI 297 => r_4 // AR decRef push r_4 // AR decRef subI ART,16 => r_4 // AR decRef push r_4 // AR decRef jumpI -> memfree // AR decRef loadAI ART,-16 => ART // AR decRef cmp_NE ART,r_nul => r_4 // AR decRef cbr r_4 -> ardl12,ardd13 // AR decRef ardd13: nop // AR decRef ynul10: nop // remove old reference store r_1 => r_2 // to f load r_2 => r_3 // load reference loadI 308 => r_5 // memaddref push r_5 // memaddref push r_3 // memaddref jumpI -> memaddref // memaddref loadAI r_3,4 => r_4 // add new reference i2i r_4 => ART // AR incRef cmp_NE ART,r_nul => r_5 // AR incRef cbr r_5 -> aril14,arid15 // AR incRef aril14: loadI 317 => r_5 // AR incRef push r_5 // AR incRef subI ART,16 => r_5 // AR incRef push r_5 // AR incRef jumpI -> memaddref // AR incRef loadAI ART,-16 => ART // AR incRef cmp_NE ART,r_nul => r_5 // AR incRef cbr r_5 -> aril14,arid15 // AR incRef arid15: nop // AR incRef cmp_EQ r_1,r_nul => r_3 // remove old reference cbr r_3 -> ynul16,nnul17 // remove old reference nnul17: nop // remove old reference loadI 328 => r_3 // free push r_3 // free push r_1 // free jumpI -> memfree // free loadAI r_1,4 => r_1 // remove old reference i2i r_1 => ART // AR decRef cmp_NE ART,r_nul => r_3 // AR decRef cbr r_3 -> ardl18,ardd19 // AR decRef ardl18: loadI 337 => r_3 // AR decRef push r_3 // AR decRef subI ART,16 => r_3 // AR decRef push r_3 // AR decRef jumpI -> memfree // AR decRef loadAI ART,-16 => ART // AR decRef cmp_NE ART,r_nul => r_3 // AR decRef cbr r_3 -> ardl18,ardd19 // AR decRef ardd19: nop // AR decRef ynul16: nop // remove old reference addI r_arp,0 => r_4 // add offset load r_4 => r_4 // load address loadI 348 => r_2 // memaddref push r_2 // memaddref push r_4 // memaddref jumpI -> memaddref // memaddref loadAI r_4,4 => r_3 // add new reference i2i r_3 => ART // AR incRef cmp_NE ART,r_nul => r_2 // AR incRef cbr r_2 -> aril20,arid21 // AR incRef aril20: loadI 357 => r_2 // AR incRef push r_2 // AR incRef subI ART,16 => r_2 // AR incRef push r_2 // AR incRef jumpI -> memaddref // AR incRef loadAI ART,-16 => ART // AR incRef cmp_NE ART,r_nul => r_2 // AR incRef cbr r_2 -> aril20,arid21 // AR incRef arid21: nop // AR incRef addI r_arp,0 => r_2 // add offset load r_2 => r_1 // load reference cmp_EQ r_1,r_nul => r_3 // remove old reference cbr r_3 -> ynul22,nnul23 // remove old reference nnul23: nop // remove old reference loadI 370 => r_3 // free push r_3 // free push r_1 // free jumpI -> memfree // free loadAI r_1,4 => r_1 // remove old reference i2i r_1 => ART // AR decRef cmp_NE ART,r_nul => r_3 // AR decRef cbr r_3 -> ardl24,ardd25 // AR decRef ardl24: loadI 379 => r_3 // AR decRef push r_3 // AR decRef subI ART,16 => r_3 // AR decRef push r_3 // AR decRef jumpI -> memfree // AR decRef loadAI ART,-16 => ART // AR decRef cmp_NE ART,r_nul => r_3 // AR decRef cbr r_3 -> ardl24,ardd25 // AR decRef ardd25: nop // AR decRef ynul22: nop // remove old reference store r_4 => r_2 // to f load r_2 => r_3 // load reference loadI 390 => r_5 // memaddref push r_5 // memaddref push r_3 // memaddref jumpI -> memaddref // memaddref loadAI r_3,4 => r_1 // add new reference i2i r_1 => ART // AR incRef cmp_NE ART,r_nul => r_5 // AR incRef cbr r_5 -> aril26,arid27 // AR incRef aril26: loadI 399 => r_5 // AR incRef push r_5 // AR incRef subI ART,16 => r_5 // AR incRef push r_5 // AR incRef jumpI -> memaddref // AR incRef loadAI ART,-16 => ART // AR incRef cmp_NE ART,r_nul => r_5 // AR incRef cbr r_5 -> aril26,arid27 // AR incRef arid27: nop // AR incRef if_e7: nop // end target loadI 409 => r_3 // malloc push r_3 // malloc loadI 8 => r_3 // malloc push r_3 // malloc jumpI -> memalloc // malloc pop => r_3 // malloc loadI 2 => r_2 // 2 storeAI r_2 => r_3,0 // store array element loadI 2 => r_4 // 2 storeAI r_4 => r_3,4 // store array element addI r_arp,8 => r_2 // add offset load r_2 => r_1 // load reference cmp_EQ r_1,r_nul => r_4 // remove old reference cbr r_4 -> ynul28,nnul29 // remove old reference nnul29: nop // remove old reference loadI 423 => r_4 // free push r_4 // free push r_1 // free jumpI -> memfree // free ynul28: nop // remove old reference store r_3 => r_2 // to arr load r_2 => r_4 // load reference loadI 430 => r_5 // memaddref push r_5 // memaddref push r_4 // memaddref jumpI -> memaddref // memaddref cmp_EQ r_3,r_nul => r_4 // remove old reference cbr r_4 -> ynul30,nnul31 // remove old reference nnul31: nop // remove old reference loadI 437 => r_4 // free push r_4 // free push r_3 // free jumpI -> memfree // free ynul30: nop // remove old reference addI r_arp,8 => r_2 // add offset load r_2 => r_2 // get array object loadI 0 => r_4 // 0 loadAI r_2,-4 => r_3 // check array index divI r_3,4 => r_3 // check array index cmp_LT r_4,r_3 => r_3 // check array index cmp_GE r_4,r_nul => r_1 // check array index and r_3,r_1 => r_1 // check array index cbr r_1 -> nob33,oob32 // check array index oob32: haltI 1634692962 // array index out of bounds nob33: multI r_4,4 => r_4 // multiply index by size add r_2,r_4 => r_2 // get array index address load r_2 => r_2 // load address addI r_arp,8 => r_1 // add offset load r_1 => r_1 // get array object loadI 1 => r_3 // 1 loadAI r_1,-4 => r_5 // check array index divI r_5,4 => r_5 // check array index cmp_LT r_3,r_5 => r_5 // check array index cmp_GE r_3,r_nul => r_4 // check array index and r_5,r_4 => r_4 // check array index cbr r_4 -> nob35,oob34 // check array index oob34: haltI 1634692962 // array index out of bounds nob35: multI r_3,4 => r_3 // multiply index by size add r_1,r_3 => r_1 // get array index address load r_1 => r_1 // load address add r_2,r_1 => r_2 // + out "",r_2 // loadAI r_arp,0 => r_1 // remove reference get var cmp_EQ r_1,r_nul => r_3 // remove reference cbr r_3 -> ynul36,nnul37 // remove reference nnul37: nop // remove reference loadI 474 => r_3 // free push r_3 // free push r_1 // free jumpI -> memfree // free loadAI r_1,4 => r_1 // remove reference i2i r_1 => ART // AR decRef cmp_NE ART,r_nul => r_3 // AR decRef cbr r_3 -> ardl38,ardd39 // AR decRef ardl38: loadI 483 => r_3 // AR decRef push r_3 // AR decRef subI ART,16 => r_3 // AR decRef push r_3 // AR decRef jumpI -> memfree // AR decRef loadAI ART,-16 => ART // AR decRef cmp_NE ART,r_nul => r_3 // AR decRef cbr r_3 -> ardl38,ardd39 // AR decRef ardd39: nop // AR decRef ynul36: nop // remove reference loadAI r_arp,4 => r_1 // remove reference get var cmp_EQ r_1,r_nul => r_3 // remove reference cbr r_3 -> ynul40,nnul41 // remove reference nnul41: nop // remove reference loadI 496 => r_3 // free push r_3 // free push r_1 // free jumpI -> memfree // free loadAI r_1,4 => r_1 // remove reference i2i r_1 => ART // AR decRef cmp_NE ART,r_nul => r_3 // AR decRef cbr r_3 -> ardl42,ardd43 // AR decRef ardl42: loadI 505 => r_3 // AR decRef push r_3 // AR decRef subI ART,16 => r_3 // AR decRef push r_3 // AR decRef jumpI -> memfree // AR decRef loadAI ART,-16 => ART // AR decRef cmp_NE ART,r_nul => r_3 // AR decRef cbr r_3 -> ardl42,ardd43 // AR decRef ardd43: nop // AR decRef ynul40: nop // remove reference loadAI r_arp,8 => r_1 // remove reference get var cmp_EQ r_1,r_nul => r_3 // remove reference cbr r_3 -> ynul44,nnul45 // remove reference nnul45: nop // remove reference loadI 518 => r_3 // free push r_3 // free push r_1 // free jumpI -> memfree // free ynul44: nop // remove reference subI r_arp,16 => r_arp // deconstruct main AR loadI 524 => r_2 // free push r_2 // free push r_arp // free jumpI -> memfree // free